Přejít k navigační liště

Zdroják » PHP » Jaké novinky přinese PHP 7

Jaké novinky přinese PHP 7

Články PHP

Za pár dnů (11. 6.) vyjde první alfa verze PHP 7 (a finální verze v půlce listopadu). Je tedy již je nejvyšší čas podívat se na vylepšení a novinky, které nás čekají.

Už PHP 7? Kam zmizelo PHP 6?

Jako PHP 6 byla označována nakonec nikdy nevydaná verze PHP, která měla přinést podporu Unicode. Aby se předešlo zmatkům s již vydanými články a knihami o PHP 6 (schválně si ve svém oblíbeném online knihkupectví zkuste vyhledat PHP 6), bylo rozhodnuto novou verzi označit jako PHP 7.

Jak si vyzkoušet novou funkcionalitu?

Nejjednodušším způsobem je použít online nástroj 3v4l.org, který spustí zadaný PHP kód na všech možných verzích (takže je možné rovnou porovnat, jak by se daný kód choval ve starší verzi PHP). Druhou variantou je rozjet si ho u sebe. Je možné využít připravený Vagrant image, Docker containerzkompilovat si ho ze zdrojáků nebo si stáhnout hotový nightly build, což je podle mě je nejlepší varianta. Detailněji tu rozeberu postup pro Windows.

  1. Otevřete si stránku s buildy.
  2. Postupně odspodu (od nejnovějších) otevírejte jednotlivé složky.
  3. Hledejte soubor php-master-ts-windows-vc11-x86-XXXXXXX.zip, který se velikostí bude blížit 20MB. Pokud má 10MB, tak je to asi nějaký rozbitý build (případně si rovnou stáhněte php-master-ts-windows-vc11-x86-r869f662.zip, který mi fungoval OK).
  4. Stáhněte ho a rozbalte.
  5. Zkopírujte php.ini-development do php.ini a případně v něm povolte potřebná rozšíření.

Pokud si v adresáři spustíte php -v, tak by se vám měl ukázat následující výstup (datum může být jiné – podle toho, jaký si vyberete build):

PHP 7.0.0-dev (cli) (built: Jun  5 2015 04:05:24)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v3.0.0-dev, Copyright (c) 1998-2015 Zend Technologies

Tím pádem máte PHP 7 nainstalované, wohoo! Ještě si ho případně můžete přidat do systémové cesty, ať jde spouštět odkudkoliv (jen ho pak nezapomeňte zas odebrat). Když už ho máte rozjeté lokálně, tak na něm můžete spustit lint (kontrolu syntaxe), který mimo jiné ověří, že nikde nepoužíváte nová rezervovaná slova. Případně jde využít pro spuštění PHPUnit testů vašeho projektu.

Třešničkou na dortu může být rozjetí přímo v Apache – v xamppu kupodivu stačilo jen prohodit 5 za 7 v C:\xampp\apache\conf\extra\httpd-xampp.conf. Docela fajn také je, že můj oblíbený PHPStorm 9 EAP už některé věci podporuje (a správně pro ně zvýrazňuje syntaxi).

A co je nového? PHP 7 je mnohem rychlejší!

Díky velkému refaktoringu a přepracování datových struktur označovaného jako phpng bude PHP 7 výrazně rychlejší a méně paměťově náročné (detailnější povídání o změnách v implementaci doporučuji fajnšmekrům – přiznám se, že na mě to je moc low-level).

Raději přidám nějaká čísla – Magento by mělo zvládat 3× tolik požadavků/s než na PHP 5.6 (2× rychlejší requesty, o 30 % menší spotřeba paměti). A úvodní stránka WordPressu potřebuje 4× méně CPU instrukcí.

V následujících kapitolách projdeme z mého pohledu nejdůležitější změny. Kompletní přehled implementovaných RFC si můžete pročíst na wiki.

Typová kontrola pro skalární datové typy

Kromě vyššího výkonu je typová kontrola asi nejvíce medializovanou novinkou PHP 7. Dlouhou dobu se řešilo, jak skalární typy do PHP přidat a přijato bylo až několikáté RFC, které je navrhovalo. Konečně tedy můžeme napsat:

<?php
function add(int $a, int $b) {
    return $a + $b;
}
add(1, 3);

A v případě předání neplatných datových typů PHP vypíše chybu Argument 2 passed to add() must be of the type integer, string given, called in ….

Kontrola datových typů není aktivní automaticky, ale je nutné na začátku souboru uvést:

<?php
declare(strict_types = 1);

Po zapnutí jsou datové typy kontrolovány i při volání standardních funkcí z PHP:

<?php
declare(strict_types = 1);

substr(123, 2); //substr() expects parameter 1 to be string, integer given

V případě rozšiřování z int na float probíhá automatická konverze (nevyhodí chybu, opačný směr z float na int ano).

<?php
declare(strict_types = 1);
 
function add(float $a, float $b): float {
    return $a + $b;
}
 
add(1, 2); // float(3)

Typy návratových hodnot

V PHP 7 bude možné zapsat návratovou hodnotu funkce/metody přímo do její definice (takže nebude nutné to psát do dokumentačních komentářů).

<?php
function foo(): array {
    return [];
}

Zajímavostí je, že RFC přidávající podporu návratových typů řešilo jen ty typy, které bylo možné již dříve použít v definici metody a int/string/float/boolean nepovolovalo. Jejich podpora byla v přidána až v RFC zmíněném dříve (které bylo ve skutečnosti řešeno později než návratové typy).

Pokud funkce vrátí jiný typ, než by měla, tak PHP vyhodí chybu (opět je to závislé na declare(strict_types = 1);):

<?php
declare(strict_types = 1);

function add(int $a, int $b): int
{
    return $a + $b * 0.2;
}

add(1, 2); // Return value of add() must be of the type integer, float returned

Výjimky místo fatal errorů

Spoustu věcí z jádra PHP bylo upraveno, aby místo Fatal Erroru vyhodilo výjimku. Jak jsem výše psal, že PHP v případě nekompatibilních typů vypíše chybu, tak ono ve skutečnosti nevypíše chybu, ale dokonce vyhodí výjimku: Uncaught TypeException: Return value of add() must be of the type integer, float returned.

Pokud by TypeException dědila od Exception, tak by to mohlo vést k těžko odhalitelným chybám (byly by odchyceny pomocí catch (Exception $e)). Proto byl vytvořen nový typ výjimek – EngineException a nový společný předek pro všechny výjimky, jak je naznačeno níže:

BaseException (abstract)
 +- EngineException
 +- ParseException
 +- Exception
     +- ErrorException
     +- RuntimeException
         +- ...
     +- ...

Přehodnocení E_STRICT errorů

Když jsme u těch chyb, tak jste si určitě všimli, že v PHP existoval takový divný typ chyby – E_STRICT. V PHP 7 byly jeho jednotlivé výskyty přehodnoceny a nahrazeny buď E_DEPRECATED, E_NOTICE nebo E_WARNING. Případně byl vypisování některých chyb zrušeno.

Null Coalesce Operator ??

Předpokládám, že všichni znáte krátký ternární operátor zavedený v 5.3, takže jen příklad pro připomenutí:

<?php
$a = 'value';
var_dump($a ?: 'no'); // string(5) "value"

Nicméně, problém nastane, pokud jako operand vlevo budeme mít neexistující klíč v poli – takové situace je nutné ošetřit pomocí isset():

<?php
var_dump($_GET['user'] ?: 'nobody'); // string(6) "nobody"
// Notice: Undefined index: user

var_dump(isset($_GET['user']) ? $_GET['user'] : 'nobody'); // string(6) "nobody"

Takový zápis je zbytečně upovídaný, a vývojář s vypnutými notices si chyby ani nevšimne. Právě to řeší Null Coalesce Operator, který otestuje první operand a pokud existuje a není null, tak ho vrátí, jinak vrátí druhý. Takže i v případě přístupu k neexistujícímu prvku pole nebude vyhozena notice.

<?php
var_dump($_GET['user'] ?? 'nobody'); // string(6) "nobody"

Nový porovnávací operátor – Spaceship

Nově byl přidaný „trojcestný“ porovnávací operátor (tzv. spaceship operator), který pro shodné hodnoty vrátí 0, pro první menší -1 a pro první větší 1.

<?php // http://3v4l.org/VDBof
var_dump(1 <=> 1); // 0
var_dump(1 <=> 2); // -1
var_dump(2 <=> 1); // 1

var_dump(('a' <=> 'a')); // 0
var_dump(('a' <=> 'b')); // -1
var_dump(('b' <=> 'a')); // 1

Když jsme dříve chtěli něco seřadit vlastní funkcí, tak to mohlo vypadat takhle:

<?php // http://3v4l.org/hNavV
$data = array(
    array('id' => 1, 'price' => 50),
    array('id' => 7, 'price' => 40),
    array('id' => 5, 'price' => 130),
);
uasort($data, function ($a, $b) {
    return ($a['price'] < $b['price']) ? -1 : (($a['price'] > $b['price']) ? 1 : 0);
});

A pokud použijeme raketu, tak se porovnávací funkce zjednoduší na:

<?php // http://3v4l.org/ing7c
uasort($data, function ($a, $b) {
    return $a['price'] <=> $b['price'];
});

Generátor kryptograficky bezpečných náhodných čísel (CSPRNG)

Vygenerovat dostatečně náhodné (=nepredikovatelné) číslo není jednoduché. V PHP to bylo možné řešit pomocí openssl_random_pseudo_bytes() nebo mcrypt_create_iv(), nicméně oboje je závislé na aktivovaném rozšíření. Proto v PHP 7 přibyly dvě funkce pro generování náhodných bajtů a náhodných čísel:

random_bytes(int length);
random_int(int min, int max);

Anonymní třídy

PHP 7 bude podporovat anonymní třídy, takže bude fungovat následující kód:

<?php // http://3v4l.org/I7Kbo
$instance = new class('foo') {
    public $i;
    public function __construct($i) {
        $this->i = $i;
    }
};
var_dump($instance); // object(class@anonymous)#1 (1) {   ["i"]=>   string(3) "foo" }

Nejsem si jistý, jestli tohle bylo nezbytné přidávat. Na jednu stranu si to své usecase najde – třeba pro mockování v testech nebo na nějaké drobnosti, ale na druhou stranu to umožní vznik neznovupoužitelných kusů kódu, které se budou špatně testovat. Příkladem, kdy to (trochu) dává smysl, může být jednoduchý observer:

<?php
$subject->attach(new class implements SplObserver {
    function update(SplSubject $s) {
        printf("Got update from: %s\n" $subject);
    }
);

Drobnosti

Odebrané věci

Z PHP 7 byly odebrány některé věci, který byly již dříve označené jako deprecated – nejzajímavější:

  • Extension ext/ereg – nahrazena ext/pcre
  • Extension ext/mysql – nahrazena ext/mysqli a ext/pdo_mysql
  • Přiřazení new referencí: $a = & new Foo()
  • set_magic_quotes_runtime, magic_quotes_runtime
  • Možnost použití eval v preg_replace – nahrazeno preg_replace_callback
  • Komentáře začínající # v php.ini (správně je ;)
  • Warning při nenastavené časové zóně – důležitější volby mají „sane defaults“, tak proč ne tohle
  • PHP 4 konstruktory (metoda stejného jména jako je název třídy) – zatím jen deprecated warning, odebrány budou v PHP 8
  • Alternativní otevírací tagy <% a <script language=php> (krátké otevírací <? zůstávají)

Závěrem

PHP 7 přinese výrazné zrychlení a spoustu nových věcí. I když je vydání finální verze ještě daleko, a nasazování do produkce ještě dál, tak určitě dává smysl si PHP 7 vyzkoušet už dnes a ověřit, že jsou na něj vaše aplikace připravené.

Komentáře

Subscribe
Upozornit na
guest
23 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Martin

Tesim sa na ?? a samozrejme vykon. Tiez uvazujem o typovej kontrole… Je to v podstate ciastocny unit test. :)

Asi je najvyssi cas nastudovat Exceptions… Furt neviem naco je to dobre, ale asi sa tomu zachvilu nevyhnem.

Martin

Ked tak uvazujem o typovej kontrole, vacsina funkcii tak ci tak vracia pole… Takze nebude velmi co typovat.

Oldřich Vetešník

Těžko říct, co děláte, ale výjimky se hodí když píšete třeba vlastní mini-wrapper na nějakou HTTP API. :-)

Martin

Tak trebars mam svoj mini framework… Stara sa o MySQL spojenie, error handling a par podobnych figlov. Stale mi vsak nezaplo, co ziskam s Exceptions oproti tomuto. Nemam dovod Exceptions nepouzivat, len nevidim ziadnu vyhodu.

set_error_handler('dev::errorHandler', -1);
Oldřich Vetešník

Tak třeba když mám background worker, který zpracovává nějaký joby, tak výjimky využiju proto, abych v hlavní perform metodě odchytnul jeden typ chyb, pro které má smysl job opakovat (třeba network timeout error) a zbytek zalogoval s tím, že opakovat to nemá smysl (not found, SQL error, …).

Je to jen jedna z několika možností, jak něco zastavit, když nemá smysl v tom pokračovat a zároveň dát možnost někomu s tím nějak naložit. Když bych místo toho vyhodit fatal error, můj worker by to asi nerozdejchal. :-)

podhy

Typová kontrola a návratové typy jsou opravdu užitečné. Jediné co my ještě chybí je něco na způsob šablon aby když mi funkce bude vracet pole objektů abych hned věděl o jaké typy se jedná. Prostě něco co má Hack :-)

podhy

PS: docela mi zde chybí zmínka o AST, protože to umožní konečně PHP vcelku normálně rozšiřovat

JanTvrdik

AST je implementační detail. Na koncové uživatele to nemá zatím vůbec žádný vliv. Teprve až bude API pro práci s AST dostupné v userlandu, tak to začne být zajímavé.

bartama

Tak na ten výkon se těším asi nejvíc. Vypadá to, že by to mohlo serveru celkem ušetřit.

Tomáš Kapler

Takže chápu to dobře, že by v zásadě každý dobře psaný kód měl od počátku fungovat a neměli bychom se dočkat nějakých problémů? Tj. mohu vzít třeba nějaký svůj WP web resp. jeho hosting a upgradovat na PHP7 (tedy až bude ostrá verze)?

Cechjos

Nespoléhal bych na to. Z PHP 7 budou smazány věci, které se staly deprecated klidně až ve verzi 5.5 (např. starý způsob uploadování přes curl).
https://wiki.php.net/rfc/remove_deprecated_functionality_in_php7

Oldřich Vetešník

Změny zní super, klobouk dolů. Docela by mě zajímalo, jak rychle se firmy aklimatizují, přece jen není švanda upgradnout všechna jejich řešení. :-)

Oldis

Tak to sem posledně vyřešil tak že sem napsal hostingu at mi vrati starsi verzi php, protoze za to, ze oni se rozmislely a po peti letech updatly verzi php, mi ten, komu ten web patri, za upravu nic nezaplati. proslo :)

JanTvrdik

Ten uvedený příklad je takový nešikovný, protože už v PHP 5 bylo možné to zapsat jako

uasort($data, function ($a, $b) {
    return $a['price'] - $b['price'];
});

což je ještě kratší než zápis s <=> operátorem. Rozdíl je v tom, že operátor <=> je jednak čitelnější a především funguje nejen pro čísla, ale i pro řetězce (dříve bylo potřeba použít strcmp) a pro pole (které dříve nebylo možné jednoduše porovnat vůbec). Ty pole jsou obzvlášť důležité, protože umožní porovnat podle více parametrů zároveň, např:

// porovnání primárně podle města a sekundárně podle jména
return [$a->city, $a->name] <=> [$b->city, $b->name];
Martin Všetička

Kontrola datových typů není aktivní automaticky, ale je nutné na
začátku souboru uvést: declare(strict_types = 1);

To neni pravda. Timto se jen vynuti striktni kontrola datovych typu. Pokud se tato direktiva neuvede nebo hodnota bude nula, tak se pouzije weak type-checking mode.

Lukáš Brzák

Po dlouhé době krok správným směrem. Líbí se mi výkon, přepracování Exceptions, nové operátory ?? <=> i kontrola datových typů, kterou jsem povětšinou stejně musel řešit vyhozením vyjímky třeba \InvalidArgumentException … hned se pustím do študýrování a testování :-) Fajn článek, díky!

Instalator

pridame repozitar
sudo add-apt-repository ppa:ondrej/php-7.0
aktualizujeme repozitare
sudo apt-get update
a nainstalujeme balicek php7
sudo apt-get install php7

vice zde https://launchpad.net/~ondrej/+archive/ubuntu/php-7.0
plati poucka nikdy takove veci neinstalovat na produkcnim serveru, to je myslim jasne .-)

Instalator

oprava:
a nainstalujeme balicek php7.0
sudo apt-get install php7.0

podolinek

V RFC bylo nakonec BaseException nahrazeno za Throwable, takže pokud chcete odchytit úplně všechno včetně fatalů, tak catch(Throwable $e).

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.