News

Co nowego w PHP v7.3? Opisaliśmy wszystkie 34 zmiany

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:

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:

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:

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:

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:

// 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:

$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:

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:

3. Wsparcie referencji w list()

Używając operatora list() nie mogłeś użyć referencji. Teraz jest to możliwe:

$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:

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().

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:

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:

if (is_array($foo) || $foo instanceof Countable) {
    echo count($foo);
}

W v7.3 wystarczy użyć is_countable():

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():

$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:

$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:

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:

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.

8. Same site cookie

Jest to póki co proponowany standard sieci web, ale widać chęć jego adopcji w przeglądarkach, językach programowania czy frameworkach. Zapobiega atakom CSRF. Metoda polega na ustawieniu odpowiedniej flagi w ciastku HTTP. Ciastka są ustawiane przez serwer za pomocą nagłówka Set-Cookie, nagłówek ten może mieć kilka flag:

Set-Cookie: foo=bar; path=/; domain=example.com; HttpOnly

Nowa flaga to SameSite która może przyjąć dwie wartości, Strict oraz Lax:

Set-Cookie: foo=bar; path=/; domain=example.com; HttpOnly; SameSite=Lax

Zarówno Lax jak i Strict kompletnie blokują ataki CSRF. Prosto i skuteczne. Czym się różnią oba parametry? Strict jak sama nazwa mówi jest bardziej restrykcyjny. Załóżmy, że jesteś zalogowany do serwisu https://www.allegro.pl. Gdyby ten serwis miał ustawioną flagę na Strict, to po kliknięciu w link, który umieściłem w tym zdaniu zostałbyś przekierowany do strony, lecz byłbyś wylogowany! W trybie Lax jest mniej restrykcyjny. Pozwala on na wczytanie zawartości pliku cookie pod warunkiem, że żądanie jest wykonane przy użyciu bezpiecznej metody, tzn. GET, HEAD, OPTIONS, TRACE. Ataki CSRF są wykonywane zazwyczaj przy użyciu metod POST, PUT, DELETE. Gdyby jednak twoja strona akceptowała żądania niebezpieczne metodą GET, np:

GET http://www.example.com/api/deleteUser?id=1

to zdecydowanie zalecam użycia trybu Strict.

Ekipa PHP zmodyfikowała cztery funkcje:

  • setcookie,
  • setrawcookie,
  • session_set_cookie_params,
  • session_get_cookie_params

Pierwsze trzy funkcje mają bardzo zbliżoną sygnaturę. Sygnatura funkcji setcookie w wersji v7.2 wygląda tak:

bool setcookie(string $name [, string $value = "" [, int $expire = 0 [, string $path = "" [, string $domain = "" [ , bool $secure = FALSE [ , bool $httponly = FALSE ]]]]]] )

Straszny bajzel z tym parametrami! Więc ludzie odpowiedzialni za PHP postanowili, że nie będą wprowadzać kolejnego argumentu. Zaimplementowali alternatywną wersją funkcji:

bool setcookie ( array $options )

Opcje jakie możesz teraz przekazać są następujące:

  • name,
  • value,
  • expire,
  • path,
  • domain,
  • secure,
  • httponly,
  • samesite.

Pozostałe sygnatury po zmianach:

bool setrawcookie ( array $options )
void session_set_cookie_params ( array $options )

Sygnatura funkcji session_get_cookie_params się nie zmieniła. Dodany został nowy klucz w tablicy zwracanej:

array(
  "lifetime" => 0,
  "path" => "/",
  "domain" => "example.org",
  "secure" => true,
  "httponly" => true,
  "samesite" => "Strict" // nowy klucz
)

Więcej informacji:

9. hrtime() – monotoniczny timer

Czy wiesz, że funkcja microtime() ma pewne ograniczenia? Dość często wylicza się czas wykonania kodu właśnie przy pomocy microtime(). Na początku kodu deklarujesz zmienną, która zawiera czas uruchomienia skryptu, a na końcu deklarujesz kolejną zmienną, tym razem czas zakończenia. Wystarczy, że obliczysz różnicę i otrzymasz czas wykonania. Kod:

$startTime = microtime();
/**
 * wykonaj jakiś skomplikowany kod
 */
$endTime = microtime();
$elapsed = $endTime - $startTime;
var_dump($elapsed);

Problem polega na tym, że jeśli czas systemowy zmieni się podczas wykonywania skryptu to czas wykonywania skryptu będzie niepoprawny. Dlatego zaimplementowano funkcję hrtime(). Dzięki niej czas wykonywania skryptu będzie super dokładny. Użycie:

$startTime = hrtime();
/**
 * wykonaj jakiś skomplikowany kod
 */
$endTime = hrtime();
$elapsed = $endTime - $startTime;
var_dump($elapsed);

Więcej informacji:

10. Nowa metoda – DateTime::createFromImmutable()

Metoda ta jest lustrzana do metody DateTimeImmutable::createFromMutable(). Więcej informacji:

11. Nowa funkcja – fpm_get_status()

Zwraca ona aktualny status menadżera procesów fastcgi. Więcej informacji: https://github.com/php/php-src/commit/140def4ac712acac6e2561f65e1b72f8efad8717

12. Nowe funkcje w GMP

gmp_binomial()

Wylicza Symbol Newtona. Więcej informacji: https://pl.wikipedia.org/wiki/Symbol_Newtona. Commit: https://github.com/php/php-src/commit/7fea79675cfb064726f3fc7845e2c2bb1f247ea5.

gmp_lcm()

Wylicza najmniejsza wspólną wielokrotność. Więcej informacji: https://pl.wikipedia.org/wiki/Najmniejsza_wspólna_wielokrotność. Commit: https://github.com/php/php-src/commit/a1d36a1157bd88afd64119be059812dd46c4fb2d.

gpm_perfect_power()

Sprawdza czy dana liczba jest perfect power. Więcej info: https://en.wikipedia.org/wiki/Perfect_power. Commit: https://github.com/php/php-src/commit/10a336d3d062fdfa0133b22fb4f79852ec939ea5.

gmp_kronecker()

Wylicza Symbol Kroneckera. Więcej informacji: https://pl.wikipedia.org/wiki/Symbol_Kroneckera. Commit: https://github.com/php/php-src/commit/fc80114a481e1e7fc8c7be775a2cce683db9c107.

13. CompileError – nowy typ błędu

Ekipa PHP dodała nowy błąd do aktualnie dostępnych. Dziedziczy po nim ParseError. Póki co bardzo niewielka ilość błędów kompilacji rzuci CompileError zamiast generować błąd fatal. Dotyczy to tylko funkcji token_get_all() w trybie TOKEN_PARSE oraz eval(). W przyszłości więcej błędów będzie rzucać CompileError.

try {
    token_get_all('<?php declare(encoding=[]); ?>', TOKEN_PARSE);
} catch (CompileError $error) {
    echo $error->getMessage(); // Encoding must be a literal
}

Więcej informacji https://github.com/php/php-src/commit/d04917c7b361fd07e098fe29ae931fb6fac1d9e0.

14. Aktualizacja PCRE do PCRE2

PHP aktualnie bazuje na PCRE w wersji pierwszej, które jest dość stare. Dlatego postanowiono o aktualizacji do najnowszej wersji PCRE2, która została wydana w 2015. Całość zmian jest „pod maską”, ale kilka rzeczy się zmieni:

  • modyfikator S nie ma wpływu na zachowanie, wszystkie wyrażenia regularne są teraz dokładniej analizowane, więc ta flaga jest zawsze włączona,
  • modyfikator X również nie ma wpływu na zachowanie, PCRE2 domyślnie korzysta z tej flagi więc zespół PHP ustawił ją zawsze włączoną,
  • PCRE2 korzysta z nowszego Unicode (v10 w PCRE2 vs v7 w PCRE) więc niektóre wyrażenia mogą się inaczej zachowywać,
  • PCRE2 jest bardziej dokładne, więc niektóra wyrażenie które były zgodne z poprzednią implementacją, teraz mogą nie działać jak należy.

Więcej informacji:

https://wiki.php.net/rfc/pcre2-migration
https://github.com/php/php-src/pull/2857

15. MBString – wsparcie pełnego case-mapping i case-folding

W stosunku do do prostego case-mapping, jego pełna odmiana może zmienić długość łańcucha znaków. Przykład:

mb_strtoupper("Straße")
// "STRAßE" - PHP v7.2
// "STRASSE" - PHP v7.3

Różne typy case-mapping oraz case-folding są dostępne przez mb_convert_case():

  • MB_CASE_LOWER (używane domyślnie przez mb_strtolower),
  • MB_CASE_UPPER (używane domyślnie przez mb_strtoupper),
  • MB_CASE_TITLE,
  • MB_CASE_FOLD,
  • MB_CASE_LOWER_SIMPLE,
  • MB_CASE_UPPER_SIMPLE,
  • MB_CASE_TITLE_SIMPLE,
  • MB_CASE_FOLD_SIMPLE (używane domyślnie przez operacje case-insensitive).
function toCases($str) {
    echo "String: $strn";
    echo "Lower: ", mb_convert_case($str, MB_CASE_LOWER), "n";
    echo "Lower Simple: ", mb_convert_case($str, MB_CASE_LOWER_SIMPLE), "n";
    echo "Upper: ", mb_convert_case($str, MB_CASE_UPPER), "n";
    echo "Upper Simple: ", mb_convert_case($str, MB_CASE_UPPER_SIMPLE), "n";
    echo "Title: ", mb_convert_case($str, MB_CASE_TITLE), "n";
    echo "Title Simple: ", mb_convert_case($str, MB_CASE_TITLE_SIMPLE), "n";
    echo "Fold: ", mb_convert_case($str, MB_CASE_FOLD), "n";
    echo "Fold Simple: ", mb_convert_case($str, MB_CASE_FOLD_SIMPLE), "n";
    echo "n";
}
 
toCases("ß");
toCases("ff");
toCases("İ");
 
/*
String: ß
Lower: ß
Lower Simple: ß
Upper: SS
Upper Simple: ß
Title: Ss
Title Simple: ß
Fold: ss
Fold Simple: ß
 
String: ff
Lower: ff
Lower Simple: ff
Upper: FF
Upper Simple: ff
Title: Ff
Title Simple: ff
Fold: ff
Fold Simple: ff
 
String: İ
Lower: i̇
Lower Simple: i
Upper: İ
Upper Simple: İ
Title: İ
Title Simple: İ
Fold: i̇
Fold Simple: İ
*/

Przy tej zmianie radzę zweryfikować czy stary kod działa poprawnie. Polecam Unit Testy do tego.

Więcej informacji:

16. compact() rzuci Notice gdy napotka niezdefiniowaną zmienną

Przed v7.3 funkcja compact() w żaden sposób nie informowała o fakcie przekazania nazwy niezadeklarowanej zmiennej. W przypadku literówki jest to bardzo przydatna rzecz. Spójrz na ten przykład, który wyrzuci Notice w v7.3:

$foo = 'bar';
 
$baz = compact('foz'); // Notice: compact(): Undefined variable: foz

Przy tej zmianie radzę zweryfikować czy stary kod działa poprawnie. Polecam Unit Testy do tego.

Więcej informacji:

17. instanceof – brak Fatal error w przypadku literału

Załóżmy, że masz tablicę z nieznaną Ci zawartością i chcesz z wyciągnąć tylko obiekty danej instancji. Teoretycznie wystarczy przefiltrować tablicę za pomocą instanceof:

$dateTimeObjects = array_filter($data, function ($data) {
    return $data instanceof DateTime;
});

Jedna w v7.2 spowoduje tp Fatal error:

// Fatal error: instanceof expects an object instance, constant given in php shell code on line 1

Do wersji v7.2 operator instanceof działał tylko z obiektami, w v7.3 naprawili to i teraz możesz wykonać instanceof na dowolnym typie zmiennej, w przypadku gdy nie będzie ona obiektem, zwróci false:

php > var_dump(false instanceof stdClass);
bool(false)
php > var_dump([] instanceof stdClass);
bool(false)
php > var_dump('test' instanceof stdClass);
bool(false)
php > var_dump(1 instanceof stdClass);
bool(false)

Więcej informacji:

https://github.com/php/php-src/commit/b6131364f95af68159b1c17ab48f9523e439cb65
https://github.com/php/php-src/blob/PHP-7.3/UPGRADING#L173

18. Przeprojektowane narzędzie ext_skel

Narzędzie to z pewnością przyda Ci się, jeśli planujesz stworzyć własne rozszerzenie do PHP. Każde rozszerzenie składa się z mnóstwa plików, wiele z nich wygląda bardzo podobnie i mają zbliżoną treść, wręcz duplikacje w niektórych miejscach. By ułatwić pracę przy tych plikach powstało narzędzie ext_skel. We wcześniejszych wersjach PHP narzędzie to było napisane w bash z kilkoma zależnościami. W v7.3 całość została przepisane w PHP + zero zależności. By tworzyło się rozszerzenia łatwiej. Więcej info:

19. Wyjątki nie wypełnią stanu error_get_last()

Wyjątki wyrzucane przez automatyczną konwersję Warning w trybie EH_THROW już nie wypełniają stanu error_get_last(). Teraz działają w ten sam sposób co wyjątki rzucane manualnie.

try {
    new DateTime('lalala');
} catch (Throwable $exception) {
    var_dump(error_get_last());
    /*
    array(4) {
      ["type"]=>
      int(2)
      ["message"]=>
      string(128) "DateTime::__construct(): Failed to parse time string (lalala) at position 0 (l): The timezone could not be found in the database"
      ["file"]=>
      string(53) "/Users/damiandziaduch/Downloads/php-7.3.0RC4/test.php"
      ["line"]=>
      int(3)
    }
*/
}
try {
	new DateTime('lalala');
} catch (Throwable $exception) {
	var_dump(error_get_last()); // NULL
}

Więcej:

20. `TypeError` zgłosi błędne typy jako int oraz bool

Gdy w pliku PHP masz zadeklarowane strict_types to musisz sam zadbać o typy zmiennych. Załóżmy że masz metodę która przyjmuję argument typu int. Gdy przekażesz argument type string, język wyrzuci TypeError. W v7.2 w przypadku gdy twój kod oczekuje int albo bool, wyjątek zgłosi że oczekuje integer lub boolean:

// TypeError: Argument 1 passed to Foo::__construct() must be of the type integer, string given

W v7.3 poprawiono to i teraz zgłasza int lub bool:

// TypeError: Argument 1 passed to Foo::__construct() must be of the type int, string given

Więcej:

21. Instrukcja continue rzuci Warning wewnątrz switch

Jeśli w kodzie masz pętlę np. while, w której jest struktura switch, a do tego wewnątrz switch użyjesz continue, by przejść do kolejnej iteracji w pętli, to twój kod był poprawny w v7.2, ale działał nie prawidłowo. continue wewnątrz switch działa tak samo break, przerywa dalsze przetwarzanie switch i nie przechodzi do kolejnej iteracji w pętli zawierającej switch. Wynika to z faktu iż switch jest uważany przez język za pętlę. Więc by przejść do kolejnej iteracji należy użyć continue 2. Zespół PHP wyszedł temu na przeciw i wyrzuci Warning w tym przypadku:

while ($foo) {
    switch ($bar) {
        case "baz":
            continue;
            // Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"?
    }
}

Przy tej zmianie radzę zweryfikować czy stary kod działa poprawnie. Polecam Unit Testy do tego.

Więcej:

https://github.com/php/php-src/commit/04e3523b7d095341f65ed5e71a3cac82fca690e4
http://php.net/manual/en/control-structures.continue.php13 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.

22. `ArrayAccess` nie zrzutuje $offset typu string na int

Gdy obiekt implementuje interfejs ArrayAccess i odwołujesz się do niego poprzez $foo['123'] to zostanie na nim wywołana metoda ->offsetGet(123) w przypadku v7.2. Zwróć uwagę, że string 123 został rzucony na int. W v7.3 zostało to poprawione więc kod prawidłowo wywoła ->offsetGet('123'); Przykład kodu:

class Foo implements ArrayAccess
{
    public function offsetGet($offset) {
        var_dump($offset); // '123' w v7.2, 123 w v7.3
    }
 
    public function offsetExists($offset) {
    }
 
    public function offsetSet($offset, $value) {
    }
 
    public function offsetUnset($offset) {
    }
}
 
$foo = new Foo();
$foo['123'];
$foo[123];

Przy tej zmianie radzę zweryfikować czy stary kod działa poprawnie. Polecam Unit Testy do tego.

Więcej informacji:

https://github.com/php/php-src/commit/30156d588c07e26d4e752ddb62344e96854d4773#diff-ff4e2dc4962dc25a1512353299992c8dL19

23. Naprawiono referencje w statycznych własnościach klas

Statyczne własności są współdzielone między instancjami klasy oraz między instancjami klasami potomnymi. Wyjątkiem jest klasa potomna, która bezpośrednio nadpisze własność. Co ciekawe, w v7.2 jest dość ciekawy błąd, który pozwala zepsuć współdzielenie dzięki użyciu referencji:

class Foo
{
    public static $x = 0;
}
 
class Bar extends Foo
{
}
 
$y = 1;
Bar::$x = &$y;
 
var_dump(Foo::$x); // int(0)
var_dump(Bar::$x); // int(1)

W v7.3 zostało to naprawione, obie klasy będę miały wartość int(1).

Przy tej zmianie radzę zweryfikować czy stary kod działa poprawnie. Polecam Unit Testy do tego.

Więcej informacji:

24. Naprawiono odpakowywanie argumentów z kluczami nie int

Okazuje się, że w PHP v7 – v7.2 był błąd, dzięki któremu ten kod:

function foo(...$args)
{
    var_dump($args);
}
 
function gen()
{
    yield 1.23 => 123;
}
 
foo(...gen()); // array(1) { [0] => int(123) }

w pełni działał. Zostało to naprawione i rzucany jest teraz wyjątek:

Przy tej zmianie radzę zweryfikować czy stary kod działa poprawnie. Polecam Unit Testy do tego.

Więcej informacji:

https://github.com/php/php-src/commit/3a8f26060c44b86145f332e87c53668cac58a6d0

25. BCMath użyje obsługi błędów PHP

Wcześniej niektóre ostrzeżenia rzucane przez funkcje BCMath były wypisane bezpośrednio do stderr. Przykład:

var_dump(bcpowmod(1, 1.2, 1, 1));
/*
v7.2:
bc math warning: non-zero scale in exponent
 
v7.3:
PHP Warning:  bcpowmod(): non-zero scale in exponent
*/

Więcej informacji:

26. Wsparcie dla BeOS porzucono

System ten został wykupiony przez Palm w 2001. Od tego czasu nie było nowej wersji systemu. Więcej:

27. Deprecated – image2wbmp()

W rozszerzeniu gd do PHP są dwie bardzo zbliżone do siebie funkcje, image2wbmp() (http://php.net/manual/en/function.image2wbmp.php) oraz imagewbmp() (http://php.net/manual/en/function.imagewbmp.php). Robią one praktycznie to samo, więc ekipa PHP postanowiła zostawić tylko jedną. W 7.3 image2wmbp zostaje oznaczona jako deprecated, w kolejnych wersjach zostanie usunięta.

Więcej informacji:

28. Deprecated – Stałe case-insensitive

PHP aktualnie wspiera zmienne case-sensitive oraz case-insensitive. Te drugie można zadeklarować używając funkcji define() z trzecim parametrem true (http://php.net/manual/en/function.define.php). By ujednolicić oraz pozbyć się dziwnych problemów typu:

define('foo', 42, true);
var_dump(FOO); // int(42);
define('FOO', 24);
var_dump(FOO); // int(24)

więc zespół PHP oznaczył stałe case-insensitive jako deprecated. Więc teraz język będzie wyrzucał takie oto wiadomości:

define('FOO', 42, true); // Deprecated: define(): Declaration of case-insensitive constants is deprecated
var_dump(FOO); // Ok!
var_dump(foo); // Deprecated: Case-insensitive constants are deprecated. The corre

W kolejnych wersjach stałe te zostaną usunięte.

Więcej informacji:

29. Deprecated – funkcje mb* bez dokumentacji

Lista funkcji:

  • mbregex_encoding,
  • mbereg,
  • mberegi,
  • mbereg_replace,
  • mberegi_replace,
  • mbsplit,
  • mbereg_match,
  • mbereg_search,
  • mbereg_search_pos,
  • mbereg_search_regs,
  • mbereg_search_init,
  • mbereg_search_getregs,
  • mbereg_search_getpos,
  • mbereg_search_setpos.

Wszystkie te funkcje to aliasy do funkcji z prefiksem mb_, np. mberegi to alias do mb_eregi.

Więcej informacji:

30. Deprecated – funkcje szukania w string z argumentem nie string int

Dotyczy to funkcji:

  • strpos,
  • strrpos,
  • stripos,
  • strripos,
  • strstr,
  • strchr,
  • strrchr,
  • stristr.

Załóżmy, że w string Ala ma 10 kotów chcesz znaleźć 10, ale przekazujesz 10 jako int. Niestety to nie zadziała, ponieważ powyższe funkcje rzutują na `int` każdy argument, który nie jest typu `string`. Następnie dla wynikowej wartości pobierają znak z tablicy ASCII.10 w ASCII to znak nowej linii. Sam tego nie wiedziałem, dopóki nie zacząłem pisać tego wpis. Kod w 7.2:

$str = "Ala ma 10 kotów";
var_dump(strpos($str, "10")); // int(7)
var_dump(strpos($str, 10));   // bool(false)

Kod w 7.3:

$str = "Ala ma 10 kotów";
var_dump(strpos($str, "10"));
// int(7)
var_dump(strpos($str, 10));
// Deprecated: strpos(): Non-string needles will be interpreted as strings in the future. Use an explicit chr() call to preserve the current behavior in php shell code on line 1
// bool(false)

Więcej informacji:

31. Deprecated – fgetss() oraz filter string.strip_tags

Obie konstrukcje umożliwiają użycie funkcjonalności z strip_tags() podczas streamingu. Jak wiadomo strip_tags() działa niezbyt dokładnie, dlatego zespół PHP postanowił oznaczyć następujące twory jako deprecated:

  • funkcja fgetss()
  • funkcja gzgetss()
  • metoda SplFileObject::fgetss()
  • filter streamu string.strip_tags()

Więcej informacji:

W PHP jest wbudowana funkcja assert(). Jest ona specjalnie traktowana przez kompilator, tzn gdy ustawisz w zend.assertions=-1 to kompilator tą funkcję po prostu pominie. Przydatne gdy korzystasz z tej funkcji, a kod wrzucasz na produkcję. Co ciekawe, możesz sobie zdefiniować własną funkcję `assert()` w nieglobalnym namespace np. fooassert(). A w samym PHP jest błąd, po wyłączeniu wbudowanej funkcji assert(), wszystkie zdefiniowane przez użytkownika również zostaną wyłączone. Dlatego w 7.3 podczas definiowania własnej funkcji assert() zostaniemy poinformowani, że jest to Deprecated:

namespace Foo {
    function assert() {
        echo 'foobar';
    }
}
// Deprecated: Defining a custom assert() function is deprecated, as the function has special semantics in php shell code on line

Więcej informacji:

32. Deprecated – FILTER_FLAG_SCHEME_REQUIRED oraz FILTER_FLAG_HOST_REQUIRED

Od wersji 5.2.1 FILTER_VALIDATE_URL implikuje oba filtry, więc są one zbędne. Dodatkowo tworzą wrażenie, że walidacja schematu / host może zostać pominięta, co jest nieprawdą. Od 7.3 podczas próby ich użycia otrzymasz ostrzeżenie Deprecated:

var_dump(filter_var('//example.com/', FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED));
// Deprecated: filter_var(): explicit use of FILTER_FLAG_SCHEME_REQUIRED and FILTER_FLAG_HOST_REQUIRED is deprecated in php shell code on line 1
bool(false)
var_dump(filter_var('http://', FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED));
// Deprecated: filter_var(): explicit use of FILTER_FLAG_SCHEME_REQUIRED and FILTER_FLAG_HOST_REQUIRED is deprecated in php shell code on line 1
bool(false)

33. Deprecated – pdo_odbc.db2_instance_name dyrektywa php.ini

Od wersji 5.1.1 ta dyrektywa została oznaczona jako Deprecated w manualu. Okazuje się jednak że w kodzie nie była oznaczona jako Deprecated (a to psikus), więc zostało to „ujednolicone”. Dyrektywa ta modyfikuje zmienną środowiskową DB2INSTANCE dla systemów nie-Windows. Jak wiadomo zmiana czegoś globalnego to nie jest dobry pomysł…

Więcej informacji:

Podsumowanie

Czy warto zaktualizować do v7.3? Jasne, że tak. Nie ma aż tak dużo zmian, które nie są kompatybilne, większość starego kodu powinna bez problemu działać. Przy zmianach, które mogą robić problemy dodałem ostrzeżenia. PhpStorm już jest gotowy na zmiany: https://www.jetbrains.com/phpstorm/nextversion/#php-73-support.

Mam nadzieję że spodobał Ci się ten post. Starałem się, by wszystkie zmiany wytłumaczyć oraz dodać stosowane źródła. Nie chciałem by ten wpis był tylko tłumaczeniem changeloga.


Artykuł został pierwotnie opublikowany na damian.dziaduch.pl. Zdjęcie główne artykułu pochodzi z pexels.com.

Podobne artykuły

[wpdevart_facebook_comment curent_url="https://justjoin.it/blog/nowego-php-v7-3-opisalismy-wszystkie-34-zmiany" order_type="social" width="100%" count_of_comments="8" ]