Jaké novinky přinese PHP 7.1

PHP 7.0.0 vyšlo teprve před necelým rokem a už se pomalu můžeme těšit na PHP 7.1. Před pár dny byla vydána verze RC3, takže už je čas začít testovat kompatibilitu aplikací.

Finální verzi můžeme očekávat v listopadu nebo začátkem prosince. Stejně jako u PHP 7.0 není stanovené přesné datum vydání, ale finální verze vyjde, až bude dostatečně stabilní.

S testováním můžete začít snadno – už jsou k dispozici i buildy pro Windows a podpora ve stabilní verzi PHPStormu (stačí přepnout verzi v Settings – Languages & Frameworks – PHP). Pokud chcete porovnat chování se staršími verzemi PHP, tak doporučuji 3v4l.org (neboli php.wtf).

Prošel jsem pro vás novinky implementované v 7.1, prostudoval jsem RFC, vybral ty nejzajímavější a shrnul je i s příklady. Spoustu změn se nese v duchu zvyšování konzistence jazyka a omezování možností střelit se do nohy, u některých zrušených věcí jsem naštěstí ani nevěděl, že to je možné. Z provedených změn je vidět snahu o silnou zpětnou kompatibilitu a případná nekompatibilita je opodstatněná. Upgrade z 7.0 by tedy měl být relativně snadný.

V manuálu už přibyla sekce o upgrade na 7.1, takže si o potřebných změnách můžete přečíst i tam.

Nullable types

V PHP 7.0 přibyla možnost definovat typy parametrů funkcí a jejich návratových hodnot. Nicméně nebylo možné místo parametru s určeným typem předat null. Obdobně nešlo vrátit null z funkce s definovaným návratovým typem:

<?php
function foo(string $foo): string
{
    return $foo;
}

foo('a'); // OK
foo(null); // TypeError: Argument 1 passed to foo() must be of the type string, null given

Obejít to šlo odebráním definice typů, případně u parametrů pomocí definice: string $foo = null – nicméně v tu chvíli nejde jen o nullable parametr, ale zároveň je $foo také nepovinný.

V PHP 7.1 přibyla možnost pomocí ? označit nullable parametry a návratové hodnoty, takže můžeme bezpečně odlišit nepovinný a nullable parametr:

<?php // https://3v4l.org/mO6vd
function bar(?string $bar): ?string
{
    return $bar;
}

var_dump(bar("a")); // string(1) "a"
var_dump(bar(null)); // NULL
var_dump(bar()); // Uncaught ArgumentCountError: Too few arguments to function bar()

Void return type

Od PHP 7.0 bylo možné definovat návratový typ funkce, ale nebylo možné vyžadovat nevrácení žádné hodnoty (což může být užitečné pro prevenci chyb). Teď je to možné pomocí void:

<?php
function shouldReturnNothing(): void
{
    return 1; // Fatal error: A void function must not return a value
}

V takové funkci musíme return vynechat úplně nebo ho zavolat bez hodnoty: return;. Vrácení null pomocí return null; také není platné.

Chybějící parametr uživatelsky definované funkce vyhodí Error

Pokud jste dříve zavolali funkci s chybějícími parametry, tak se provedla bez nich a zahlásila warning. Nově chybějící parametr funkce vyhodí ArgumentCountError a funkce se vůbec neprovede.
Zdůrazňují, že se to netýká přímo funkcí v PHP, ale jen těch uživatelsky definovaných – substr(); způsobí stále jen warning.

<?php // https://3v4l.org/F9thD
function test($param)
{
    var_dump($param);
}

test(); // Uncaught ArgumentCountError: Too few arguments to function test(), 0 passed and exactly 1 expected

Aritmetické operace s neplatnými stringy vrací warning či notice

V PHP <7.1 bylo možné sčítat jablka s hruškami bez warningů nebo notice:

<?php
var_dump('1' + '1'); // int(2)
var_dump('10 apples' + '5 pears'); // int(15)
var_dump('two apples' + '5 pears'); // int(5)

Pokud v PHP 7.1 použijeme aritmetickou operaci na string, který nelze převést na číslo (např. 'two apples') dostaneme Warning: A non-numeric value encountered in %s on line %d. Pro stringy, ze kterých jde získat číslo ('10 apples') je připravena Notice: A non well formed numeric value encountered in %s on line %d. Řetězec obsahující číslo ('10') se bere jako platný a notice nezpůsobí.

Definice viditelnosti konstant

Nově je možné konstanty označit jako private nebo protected. To přijde vhod, pokud chcete konstantu použít jen uvnitř třídy a nechcete, aby na ní někdo závisel v kódu mimo třídu.

<?php
class Token
{
    const PUBLIC_CONST = 0; // = public const
 
    public const PUBLIC_CONST_TWO = 0; // = const
    protected const PROTECTED_CONST = 0;
    private const PRIVATE_CONST = 0;
}

Chytání více typů výjimek v jednom catch

Pokud jsme v PHP <7.1 chtěli dva typy výjimek ošetřit stejným způsobem, bylo potřeba kód zkopírovat nebo vytvořit společnou metodu:

<?php
try {
   // Some code...
} catch (ExceptionType1 $e) {
   // Code to handle the exception
} catch (ExceptionType2 $e) {
   // Same code to handle the exception
} catch (Exception $e) {
   // ...
}

Nově je možné chytit více typů najednou:

<?php
try {
   // Some code...
} catch (ExceptionType1 | ExceptionType2 $e) {
   // Code to handle the exception
} catch (\Exception $e) {
   // ...
}

Nový typ iterable

Při definici typehintu pro kolekci jste se museli rozhodnout, jestli použijete array a nebude možné tam předat Traversable nebo naopak. Obejít to šlo vynecháním typehintu a kontrolou až v kódu.

Teď už to není potřeba a můžete použít typ iterable:

<?php
function foo(iterable $iterable)
{
    foreach ($iterable as $value) {
        // ...
    }
}

Zároveň přibyla funkce (bool) is_iterable().

Negativní offsety pro stringové funkce

Některé funkce pro práci se stringy (například substr()) umožňovaly používat negativní offsety:

<?php

substr("abcdef", -1); // "f"

Od 7.1 je možné negativní offsety používat také u funkcí: strpos(), stripos(), substr_count(), iconv_strpos(), mb_strpos() (a několik dalších, viz RFC)

$this se vždy bude chovat očekávaným způsobem

Tipuji, že jste nevěděli, a snad díky tomu ani nepoužívali možnost přiřadit do $this jinou hodnotu (netuším, proč by to někdo dělal). V rámci zvyšování konzistence a odebírání historických haluzí už to naštěstí v 7.1 nepůjde.

<?php // https://3v4l.org/ZcMVY

$a = 'this';
$$a = 42;

var_dump($this); // na < 7.1 vypíše 42, na 7.1+ Fatal Error
<?php // https://3v4l.org/cAJGi

class C
{
    function foo()
    {
        $a =& $this;
        $a = 42;
        var_dump($this); // na < 7.1 vypíše 42, na 7.1+ očekávaný dump $this
    }
}

$x = new C();
$x->foo();

Session ID už není hashované

Bezpečně vygenerované ID (pomocí random_bytes() přidaného v 7.0) už není potřeba hashovat, takže byly odebrány související volby v php.ini. Naopak přibyla možnost nastavení délky session id pomocí session.sid_length. V php.ini distribuovaném s PHP je nastaveno na 26 kvůli zpětné kompatibilitě, ale výchozí hodnota přímo v PHP je 32.

Doporučuji tedy ověřit, že sloupec (resp. místo, kam ukládáte session ID) zvládne 32 znaků, případně do php.ini přidat session.sid_length = 26

Zkrácená syntaxe pro array destructuring

Je možné použít kratší zápis pro přiřazení pole do jednotlivých proměnných:

<?php

list($a, $b, $c) = array(1, 2, 3); // původně

[$a, $b, $c] = [1, 2, 3]; // nově také takto

Trošku odbočím, troufám si tvrdit, že použití list() signalizuje code-smell a ve většině případů by mělo jít nahradit pomocí result objectu (tzn. metoda nebude vracet asociativní pole, ale immutable objekt). Pokud list() používáte, zkuste se zamyslet, jestli místo přechodu na novou syntaxi nebude vhodnější upravit kód a rovnou vracet objekt. Pokud máte příklad, kde použití list() dává smysl a neznepřehledňuje kód, tak budu rád, pokud se o něj podělíte v komentářích.

Drobnosti, které nepotřebují vlastní kapitolu

Závěr

Jak je vidět, tak oproti 7.0 jsou změny drobnější a zaměřené na vyladění stávající funkcionality. Upgrade by tedy neměl být složitý, ale stejně doporučuji počkat s produkčním nasazením alespoň na 7.1.1 ;-)

Pokud se vám ještě nepodařil upgrade na PHP 7.0, tak budu rád, pokud se v komentářích rozepíšete o tom, na čem jste se zasekli a co vás drží zpět.

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

Komentáře: 15

Přehled komentářů

v6ak Příklad na array destructuring
Martin Hujer Re: Příklad na array destructuring
dimov-cz list()
tomasfejfar Re: list()
Martin Hujer Re: list()
Jakub Vrána list()
Jakub Vrána Hashování session proměnných
tacoberu array destructuring
tomasfejfar Re: array destructuring
tacoberu Re: array destructuring
Martin Hujer Re: array destructuring
tacoberu Re: array destructuring
tacoberu array destructuring jinde
Plysak Hruza
Martin Hujer Re: Hruza
Zdroj: https://www.zdrojak.cz/?p=18941