Jaké novinky přinese PHP 7.3

Vydání PHP 7.3 je plánováno na 6. prosince 2018. Přináší několik nových funkcí, vylepšení a různá pročištění jazyka. Oproti jiným vydáním mu sice chybí nějaký trhák, ale na druhou stranu nepřibyly ani žádné zásadní nekompatibilní změny, takže upgrade bude snadný.

PHP 7.3 vyjde 6. prosince 2018 (viz plán). Přináší několik nových funkcí, vylepšení a různá pročištění jazyka. Oproti jiným vydáním tu chybí nějaký trhák, kvůli kterému by všichni byli nedočkaví na upgrade. Na druhou stranu ale nepřibyly ani žádné zásadní nekompatibilní změny, takže upgrade bude snadný.

Testovací verzi si můžete stáhnout již dnes pomocí odkazů v oznámení o vydání 7.3.0RC6 (jde o poslední testovací verzi před vydáním finální). A nezapomeňte aktualizovat PhpStorm – v JetBrains se vytáhli a aktuální verze 2018.3 už podporuje novinky z PHP 7.3.

Konec podpory starých verzí

Pokud se podíváte na stránku Supported Versions na webu PHP, uvidíte následující zajímavé věci:

  • Podpora PHP 5.6 končí k 31. 12. 2018, pak již nebudou opravovány ani bezpečnostní chyby
  • Podpora PHP 7.0 končí k 3. 12. 2018, pak již nebudou opravovány ani bezpečnostní chyby
  • Podpora PHP 7.1 končí k 1. 12. 2018, pak budou ještě do 1. 12. 2019 opravovány bezpečnostní chyby

Znamená to, že by do konce roku 2018 měly veškeré vaše aplikace běžet minimálně na PHP 7.1 a že příští rok musíte naplánovat přechod nejméně na PHP 7.2.

Při jakémkoliv upgrade PHP doporučuji nejdříve aktualizovat knihovny, na kterých vaše aplikací závisí. Třeba v případě PHP 7.3 byla kompatibilní verze Doctrine ORM vydána teprve před několika dny.

RFC: Flexible Heredoc and Nowdoc Syntaxes

Pokud používáte pro dlouhé stringy přímo v kódu pomocí syntaxe Heredoc nebo Nowdoc, tak vás určitě potěší, že nově můžete odsadit uzavírací tag. Dříve bylo nutné mít celý string zarovnaný vlevo, nově může být libovolně odsazený a zleva se ořízne tolik mezer/tabů, o kolik je odsazený uzavírací tag.

<?php
$data = <<<EOT
foo
    bar
baz
EOT;

Nově:

<?php
$data = <<<EOT
    foo
        bar
    baz
    EOT;

Kromě toho už uzavírací tag nemusí být sám na řádku, takže v kombinaci se změnou výše, lze použít tento zápis:

<?php
$data = [
    <<<EOT
    a
    b
    c
    EOT,
    'd e f',
];

Je to drobnost, ale pro spoustu lidí mohlo být důvodem nepoužít heredoc/nowdoc právě to, že vypadal ošklivě. Já osobně heredoc/nowdoc moc nepoužívám, spíš ho beru jako signál, že tomu řetězci by bylo lépe v externím souboru, šabloně atd. Máte někdo nějaký hezký use-case, kde je zápis pomocí heredoc/nowdoc elegantnější než standardní string nebo šablona?

RFC: Allow a trailing comma in function calls

Už před vydáním PHP 7.2 se objevila myšlenka povolit koncovou čárku v různých výčtech (nejen) parametrů, ale nakonec z toho prošly hlasováním jen zrůdné grouped namespaces. Pro připomenutí vypadají takhle (ne, nepoužívejte je prosím):

<?php
use Foo\Bar\{
    Foo,
    Bar,
    Baz,
};

V PHP 7.3 je v rámci mírného pokroku nově možné psát čárku i za posledním parametrem při volání funkce nebo metody (ale pozor, opravdu jen při volání, ne při deklaraci).

<?php
class Foo {
    function bar(...$args) {
        var_dump($args);
    }
}

$foo = new Foo();
$foo->bar(
    1,
    2,
    3,
    4, // <- čárka na konci
);
<?php
sprintf(
    '%s text with %d parameters',
    'Some',
    2, // <- čárka na konci
);

Jak je vidět na příkladech, tak se to může hodit na různých místech, kde se často přidávají nové prvky na konec výčtu (podobně jako u polí).

RFC: JSON_THROW_ON_ERROR

Pravděpodobně už jste při použití json_decode() nebo json_encode() narazili na problém s ošetřím chyb. Správné použití těchto funkcí není triviální, protože nevyhazují výjimky ani errory, ale místo toho je nutné zkontrolovat, co po jejich zavolání vrací json_last_error(). Pokud jste na to nenarazili, tak to za vás možná řeší framework.

Od PHP 7.3 je možné použít konstantu JSON_THROW_ON_ERROR, která pro nevalidní JSON zajistí vyhození JsonException s chybovou zprávou.

<?php
// vyhodí JsonException: Syntax error 
json_decode('{', true, 512, JSON_THROW_ON_ERROR);

// vyhodí JsonException: Type is not supported
$data = fopen('foo.txt', 'w+');
json_encode($data, JSON_THROW_ON_ERROR);

Samozřejmě by bylo mnohem lepší, kdyby se tak obě funkce chovaly bez speciálního parametru, ale to není možné kvůli zachování zpětné kompatibility.

A když tu mluvíme o kontrole návratových hodnot… kontrolujete všude, že vám file_get_contents() nevrátil false? Pokud ne, tak by se vám mohla hodit knihovna thecodingmachine/safe, která přidává wrappery vyhazující výjimky pro různé PHP funkce. (článek od autora knihovny, v angličtině).

RFC: PCRE2 migration

V PHP 7.3 vyměnili knihovnu PCRE používanou pro regulární výrazy za PCRE2. Není to jen nějaký drobný update, ta PCRE knihovna, kterou PHP interně používá, je úplně přepsaná. Ale zásadní je, že z pohledu PHP aplikací je ta změna zpětně kompatibilní – tzn. není potřeba nic upravovat.

RFC: list() Reference Assignment

Nově je možné pomocí list() udělat přiřazení reference:

<?php
$array = [1, 2];
list($a, &$b) = $array; // <-- $b je reference

Odpovídá to kódu:

<?php
$array = [1, 2];
$a = $array[0];
$b =& $array[1];

Já osobně list() vůbec nepoužívám, protože vždycky je lepší vrátit nějaký result-object, díky kterému neztratíte informaci o typech. Zkusím vás přesvědčit následujícím příkladem:

<?php
function getInfo(): array
{
    return ['Jméno', 22];
}

list($jmeno, $vek) = getInfo();

var_dump($vek); // <- tady PhpStorm netuší, co tam je za typ

Ale pokud si vytvoříme třídu PersonInfo (stačí ručně napsat ty property, zbytek je pár klávesových zkratek v PhpStormu), tak získáme typovou kontrolu už v konstruktoru a zároveň nám bude fungovat napovídání i v kódu, který výsledek používá:

<?php
class PersonInfo
{
    /** @var string */
    private $jmeno;

    /** @var int */
    private $vek;
    
    public function __construct(string $jmeno, int $vek) // <-- typy už se kontrolují tady
    {
        $this->jmeno = $jmeno;
        $this->vek = $vek;
    }
    
    public function getJmeno(): string
    {
        return $this->jmeno;
    }
    
    public function getVek(): int
    {
        return $this->vek;
    }
}

function getInfo(): PersonInfo
{
    return new PersonInfo('Jméno', 22);
}

$info = getInfo();

var_dump($info->getJmeno()); // <- tady PhpStorm a PHPStan s jistotou vědí, že tam je string

RFC: is_countable

Pokud od PHP 7.2 zavoláte count() na něčem, na čem to nedává smysl, tak PHP vyhodí warning. Pokud v proměnné $foo mohly být různé typy, bylo nutné to kontrolovat pomocí následujícího:

<?php
if (is_array($foo) || $foo instanceof Countable) {
    // $foo is countable
}

Nově je možné použít funkci is_countable():

<?php
if (is_countable($foo)) {
    // $foo is countable
}

RFC: array_key_first(), array_key_last()

Pro snadné získání prvního nebo posledního klíče v poli přibyly funkce array_key_first() a array_key_last():

<?php
// asociativní pole
$array = ['a' => 1, 'b' => 2, 'c' => 3];
array_key_first($array); // 'a' 
array_key_last($array); // 'c 

// pole s číselnými indexy 
$array2 = [1 => 'a', 2 => 'b', 3 => 'c']; 
array_key_first($array2); // 1 
array_key_last($array2); // 3

RFC: Make compact function reports undefined passed variables

Jedno z míst, kde se můžete setkat se zpětnou nekompatibilitou, je funkce compact(). Ta doteď ignorovala neexistující proměnné, nově pro ně bude hlásit notice.

RFC: Argon2 Password Hash Enhancements

V PHP 7.2 přibyl pro password_hash algoritmus Argon2i (PASSWORD_ARGON2I). V 7.3 ho doplní Argon2id (PASSWORD_ARGON2ID).

Připomínám, že použití PASSWORD_BCRYPT je pořád bezpečné, jen ty nové algoritmy jsou ještě o kousek bezpečnější.

RFC: Deprecate and Remove Case-Insensitive Constants

Pokud pro definici konstant používáte funkci define(), tak od PHP 7.3 je deprecated její třetí parametr $case_insensitive, pomocí kterého bylo možné konstantu používat bez ohledu na velikost písmen.

Důležité: Toto se netýká konstant definovaných ve třídě, ty jsou a byly vždy case-sensitive.

RFC: Same Site Cookie

V PHP 7.3 přibyla nativní podpora pro nastavení parametru SameSite u cookies, který slouží jako obrana proti CSRF. Pro použití není potřeba čekat na aktualizaci PHP, protože to pro vás už možná řeší framework – Symfony od verze 3.2, Nette od 2.4 (2018–09–18).

RFC: Deprecations for PHP 7.3

Nikita Popov v 7.3 pročistil (resp. označil jako deprecated, odebrány budou v 8.0) několik věcí v PHP,  konkrétně:

  • nedokumentované aliasy k mbstring funkcím – například různé varianty mbereg_ (používejte ty s podtržítkem mb_ereg_)
  • možnost poslat int do různých funkcí pro vyhledávání v řetězcích – třeba strpos: strpos($str, 65) se totiž chová tak, že číslo bere jako ASCII kód znaku a ten pak vyhledá v předaném řetězci
  • funkce fgetss() a filtr string.strip_tags – sloužily k provedení strip_tags() při práci se streamy
  • definice vlastní assert() funkce – nově není možné definovat vlastní funkci assert(), protože se k ní kompiler od 7.0 chová odlišně (její provádění lze vypnout v php.ini, což by mohlo být matoucí)

Co nás čeká v budoucnu

Po 7.3 bude následovat verze 7.4, která přinese zajímavější věci. Například Preload (možnost přednačíst některé třídy do sdílené paměti serveru) nebo Typed Properties (striktní typy pro properties). Vzhledem k tomu, že to pravděpodobně bude poslední verze před 8.0, tak můžeme také očekávat různé deprecations, které pak budou v 8.0 odebrány. Ale na 7.4 si počkáme nejméně do konce příštího roku.

Závěr

PHP 7.3 přináší spíše drobnosti a kosmetická vylepšení, takže upgrade by neměl být složitý.

Budu rád, pokud se v komentářích podělíte o to, na jaké verzi PHP běží vaše aplikace v produkci. Pokud ne na aktuální, tak by mě zajímalo, co vám v brání v upgrade.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 6

Přehled komentářů

Jáchym Toušek
TomasVotruba Re: Použití
Lukáš Brzák Škoda, že ..
TomasVotruba PCRE není úplně zpětně kompabitilní
Jakub Vrána Re: PCRE není úplně zpětně kompatibilní
TomasVotruba Pro snažší migraci kódu na PHP 7.3
Zdroj: https://www.zdrojak.cz/?p=22139