13 grudnia zostanie udostępniona wersja produkcyjna PHP v7.3. Zmian jest naprawdę dużo, choć nie są rewolucyjne. Większość z nich to drobnostki, ale na pewno każdy znajdzie coś dla siebie. Wszystkie 34 aktualizacje postanowiłem opisać poniżej.
Damian Dziaduch. Absolwent Uniwersytetu Gdańskiego. Zawodowy programista z 7 letnim stażem. Aktualnie lider zespołu oraz specjalista od wydajności w GForces Polska. Po godzinach bloger (damian.dziaduch.pl) i freelancer. Lubi czysty kod, testowanie, wydajność, a także produktywność.
Spis treści
1. Elastyczna składnia HEREDOC / NOWDOC
Znacznik zamykający – nowa linia
Do tej pory, po znaku zamykającym wyrażenie, wymagana była nowa linia:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
sql_quote(<<<STR select * from table where 1=1; STR ); $data = [<<<DATA a b c DATA , 'd e f']; |
W nowej wersji nie ma już tego wymogu:
1 2 3 4 5 6 7 8 9 10 11 |
sql_quote(<<<STR select * from table where 1=1; STR); $data = [<<<DATA a b c DATA, 'd e f']; |
Wcięcie znacznika zamykającego
W aktualnej wersji PHP znacznik zamykający musi być na początku linii:
1 2 3 4 5 6 7 |
class Foo { private const SQL = <<<SQL select * from table where 1=1; SQL; } |
W nowej wersji całe wyrażenie HEREDOC / NOWDOC może być wcięte:
1 2 3 4 5 6 7 |
class Foo { private const SQL = <<<SQL select * from table where 1=1; SQL; } |
Co ważne, wcięcie znacznika zamykającego decyduje o ilości usuniętych białych znaków z łańcucha znaków:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// bez wcięcia znacznika zamykającego echo <<<END a b c END; /* a b c */ // wcięcie na 4 spacje echo <<<END a b c END; /* a b c */ |
Ja jestem bardzo zadowolony z tych zmian, często używam HEREDOC / NOWDOC np. do budowania zapytań SQL.
Uwaga na składnie nie kompatybilne z nową wersją
Jeśli w starym kodzie masz znacznik zamykający wewnątrz łańcucha znaków, może to spowodować błąd lub łańcuch zostanie źle zinterpretowany. W poniższym kodzie zostanie wyrzucony ParseError
:
1 2 3 4 5 6 |
$str = <<<FOO abcdefg FOO FOO; var_dump($str); // Parse error: Invalid body indentation level (expecting an indentation level of at least 4) in test.php on l |
Przy tej zmianie radzę zweryfikować czy stary kod działa poprawnie. Polecam do tego Unit Testy.
Więcej w RFC: https://wiki.php.net/rfc/flexible_heredoc_nowdoc_syntaxes.
2. Przecinek po ostatnim argumencie w wywołaniach funkcji / metod
Aktualnie możemy zostawić przecinek po ostatnim elemencie w tablicy oraz w grupowanych namespace. W nowej wersji możemy przecinek zostawić po ostatnim argumencie w wywołaniach:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
unset( $foo, $bar, $baz, ); echo $this->render( 'index.html', compact( 'title', 'body', 'comments', ) ); $newArray = array_merge( $arrayOne, $arrayTwo, [ 'foo', 'bar' ], ); $closure = function () {}; $closure( 1, false, ); |
Co ważne, dotyczy to tylko wywołań a nie deklaracji!
Jeśli dbasz o ładną historię w systemie kontroli wersji, to na pewno będziesz zadowolony.
Więcej informacji:
- https://wiki.php.net/rfc/trailing-comma-function-calls
- https://github.com/php/php-src/commit/b591c329ee3129adbdc35141bb1542d119f7a2a1
3. Wsparcie referencji w list()
Używając operatora list() nie mogłeś użyć referencji. Teraz jest to możliwe:
1 2 3 |
$array = [1, 2]; list($c, &$d) = $array; [$a, &$b] = $array;<br> |
Kod jest poprawny i działa jak należy w v7.3.
Więcej informacji:
- https://wiki.php.net/rfc/list_reference_assignment
- https://github.com/php/php-src/commit/6d4de4cf0582cf33848826ab78aae58077dc2dea
4. json_encode()
i json_decode()
– rzucanie wyjątków
Gdy wywołasz json_decode()
z niepoprawnym JSON funkcja zwróci null. Co ciekawe, gdy wywołasz ją z poprawnym JSON, który zawiera tylko null, funkcja również zwróci null. Jedyną metodą, by sprawdzić czy wystąpił błąd podczas dekodowania jest odwołanie się do funkcji json_last_error()
lub json_last_error_msg()
.
W v7.3 to się zmieni. Ekipa PHP wprowadziła flagę JSON_THROW_ON_ERROR
, dzięki której funkcja json_encode()
oraz json_decode()
będą rzucać wyjątek JsonException, gdy coś pójdzie nie tak. Co ważne, kod wyjątku będzie zgodny z kodem zwracanym przez funkcję json_last_error()
, a wiadomość zgodna z wiadomością zwracaną przez json_last_error_msg()
.
1 2 3 4 5 6 |
try { $decoded = json_decode("{ 'invalid' : 'json' }", false, 512, JSON_THROW_ON_ERROR); } catch (\JsonException $e) { echo $e->getCode(); // 4 echo $e->getMessage(); // Syntax error } |
Więcej informacji:
- https://wiki.php.net/rfc/json_throw_on_error
- https://github.com/php/php-src/commit/e823770515bd0530bd3c09ea273c720b4df33734
5. Nowa funkcja is_countable()
W wersji v7.2 dodano Warning które jest wyrzucany podczas próby wywołania count()
na czymś co nie jest policzalne, np. na instancji stdClass. By temu zapobiec należy zweryfikować czy rzecz jest policzalna, jednak nie było do tego odpowiedniej funkcji, więc warunek jest złożony:
1 2 3 |
if (is_array($foo) || $foo instanceof Countable) { echo count($foo); } |
W v7.3 wystarczy użyć is_countable()
:
1 2 3 |
if (is_countable($foo)) { echo count($foo); } |
Więcej informacji:
6. Nowe funkcje array_key/value_first/last()
Funkcje te zostały dodane by ułatwić uzyskiwanie kluczy i wartości ostatniego i pierwszego elementu z tablicy. W v7.2 trzeba modyfikować wewnętrzny wskaźnik tablicy używając np. end()
/ current()
:
1 2 3 4 5 6 7 8 9 10 11 12 |
$array = [ 1 => 'a', 5 => 'm', 10 => 'z' ]; reset($array); echo key($array); // 1; echo current($array); // a end($array); echo key($array); // 10 echo current($array); // z |
W v7.3 możesz użyć dedykowanych funkcji do tego, co ważne, nie zmieniają wskaźnika wewnątrz tablicy:
1 2 3 4 5 6 7 8 9 10 |
$array = [ 1 => 'a', 5 => 'm', 10 => 'z' ]; echo array_key_first($array); // 1 echo array_value_first($array); // a echo array_key_last($array); // 10 echo array_value_last($array); // z |
Więcej informacji:
7. Nowa funkcja do haszowania haseł – Argon2id
Algorytm Argon2 ma trzy odmiany:
- Argon2i,
- Argon2d,
- Argon2id.
Ta ostatnia jest teraz zalecaną odmianą w wersji roboczej specyfikacji IEFT. W nowej wersji zostaje wsparcie poprzez funkcje password_* oraz stałą PASSWORD_ARGON2ID
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
password_hash('password', PASSWORD_ARGON2ID, ['memory_cost' => 1<<17, 'time_cost' => 4, 'threads' => 2]); var_dump(password_get_info('$argon2id$v=19$m=1024,t=2,p=2$ZUhOUVczSHpZRDBDU2ZBRA$k/vI1wKP4s0ecJIpUybRfgBeo3as1PhIV1Od6PvOEFA')); /* array(3) { ["algo"]=> int(3) ["algoName"]=> string(8) "argon2id" ["options"]=> array(3) { ["memory_cost"]=> int(1024) ["time_cost"]=> int(2) ["threads"]=> int(2) } } */ |
Więcej informacji:
- https://wiki.php.net/rfc/argon2_password_hash_enhancements
- https://github.com/php/php-src/commit/55277a668409b9d62ac42695934aca64e354869f
- https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03