PHP 8.2 – jakich zmian możemy się spodziewać?

phphub.pl 1 rok temu

PHP 8.2, 7RC zostanie wydany już jutro, czyli 24 listopada 2022 roku. Wydanie wersji gotowej do użycia produkcyjnego przewidzane jest na grudzień 2022. Jest to niesamowite wydarzenie dla wszystkich PHP Deva oraz dowód na to, iż język wciąż rozwija się bardzo dynamicznie. Jest to również odpowiedni moment na to, aby przyjrzeć się funkcjonalnościom, które zostaną wprowadzone w tej wersji. Być może niedługo będziesz miał/a możliwość skorzystania z tej wersji w swoim projekcie. No chyba, iż dostawca platformy, frameworka lub narzędzia, z którym pracujesz, zrobi to dopiero za dwa lata… ¯⁠\⁠_⁠(⁠ツ⁠)⁠_⁠/⁠¯

Jakich zmian możemy się spodziewać w PHP 8.2?

Znakomite pytanie. Z racji, iż będzie to już siódmy release candidate, wybrałem 7 najciekawszych moim zdaniem zmian. Zapraszam do lektury!

1. Klasy readonly

Link do RFC

W PHP 8.1 zostały wprowadzone adekwatności typu readonly. W nowej wersji zostanie dodana analogiczna funkcjonalność dla klas.

Co to w praktyce oznacza? Otóż nie będziemy musieli już oznaczać wszystkich adekwatności danej klasy jako readonly:

class SomeClass { public readonly $name; public readonly $description; }

Wystarczy oznaczyć po prostu klasę jako readonly:

readonly class SomeClass { public $name; public $description; }

Ponadto readonly będzie również kompatybilne z innymi słowami kluczowymi dla klas:

abstract readonly class SomeAbstractClass {} final readonly class SomeFinalClass {}

Należy pamiętać o tym, iż jako readonly nie będziemy mogli oznaczać bytów takich jak:

  • Interface
  • Enum
  • Trait

2. Do Standalone Types dołączy false i null

Link do RFC

W poprzednich wersjach, nie mogliśmy użyć następującej implementacji:

function someFunction(): null { } function anotherFuncton(): false { } // Fatal error: Null can not be used as a standalone type // Fatal error: false can not be used as a standalone type

W PHP 8.2 nadejdzie rozszerzenie zakresu dostępnych Standalone Types o false i null.

3. Deprecjacja dynamic properties

Link do RFC

Jestem bardzo interesujący Twojej opinii na ten temat! To spora zmiana, która wymusi w przyszłości refaktor w wielu systemach!

Weźmy na warsztat następującą implementację:

class User { public $name; } $user = new User; $user->name = "foo";

Niby nic specjalnego. Jednak co by się stało, gdybyśmy spróbowali przypisać wartość do adekwatności, która nie została wcześniej zdefiniowana (na przykład ze wględu na literówkę w naszej implementacji)? Jak tłumaczy Nikita Popov:

// Oops, a typo: $user->nane = "foo"; // PHP <= 8.1: Silently creates dynamic $user->nane property. // PHP 8.2: Raises deprecation warning, still creates dynamic property. // PHP 9.0: Throws Error exception.

W PHP 8.2 zakończy się to jedynie deprecation warningiem. Jednak w wersji 9.0 będzie to już po prostu exception. W mojej ocenie to bardzo dobry kierunek, w którym PHP będzie stawał się coraz bardziej strict.

4. Rozszerzenie Random

Link do RFC

W końcu doczekaliśmy się reimplementacji randomizerów! W nasze ręce wpadnie zupełnie nowe rozszerzenie Random! Jak czytamy w RFC, rozwiąze to sporo problemów z legendarnymi funkcjami takimi jak mt_rand, str_shuffle, mt_srand i innymi. Ma to równiez poprawić bezpieczeństwo, które jest niezbędne przy użyciach na potrzeby rozwiązań kryptograficznych.


Dostaniemy również wspaniały obiektowy interfejs, tylko spójrz na przykłady poniżej:

$rng = $is_production ? new Random\Engine\Secure() : new Random\Engine\PCG64(1234); $randomizer = new Random\Randomizer($rng); $randomizer->shuffleString('foobar'); $engine = new Random\Engine\Secure(); $randomizer = new Random\Randomizer($engine); $items = range(1, 10); $items = $randomizer->shuffleArray($items);

5. Typy DNF

Link do RFC

Typy DNF. Nie wiesz o co chodzi? No to szybkie przypomnienie ze studiów. To taki skrót od Disjunctive Normal Form, czyli Dysjunkcyjna Postać Normalna. interesująca nazwa, co?

DNF to po prostu standaryzacja zapisu formuły logicznej. Jak to się ma do naszego PHP’a? Ano na przykład tak, iż będziemy mogli łączyć union types i intersection types w złożone formuły logiczne. Żeby nie przytłoczyć cię dość złożonymi logicznie przykładami z RFC, spójrz na poniższy, bardzo prosty case:

<?php interface A {} interface B {} function someFunction((A&B)|null $someVariable) { } // PHP 8.1 -> Parse error: syntax error, unexpected token "(", expecting variable in ... // PHP 8.2 -> Wszystko działa!

Dla fanów nieco bardziej skompikowanych formuł zostawiam jeszcze taki przykład użycia DNF:

interface A {} interface B {} interface C extends A {} interface D {} class W implements A {} class X implements B {} class Y implements A, B {} class Z extends Y implements C {} function someFunction((A&B)|(C&D)|(Y&D)|null $someVariable) { } function someOtherFunction((B&A)|null|(D&Y)|(C&D) $someVariable) { } function anotherFunction(null|(C&D)|(B&A)|(Y&D) $someVariable) { }

Już słyszę zacieranie rąk architektów projektujących złożone relacje między klasami!

6. Stałe w Traitach

Link do RFC

Przyznam, iż jestem wielkim fanem użycia stałych. Niestety nie jestem miłośnikiem użycia Traitów. Co się stanie, o ile połączymy te dwa światy? Spójrzmy na poniższy przykład:

trait SomeTrait { public const SOME_CONSTANT = 'SomeCoolConstant'; public function someFunction(): string { return self::SOME_CONSTANT; } }

W PHP 8.2 będziemy mogli dostać się do naszego consta w Traicie jedynie poprzez akcesor self.

W klasie używającej Traita, będzie można dostać się do niego w sposób następujący:

class IHateTraits { use SomeTrait; } IHateTraits::SOME_CONSTANT; // SomeCoolConstant

7. SensitiveParameter attribute

Link do RFC

Naszą przysłowiową wisienką na torcie będzie SensitiveParameter attribute.

Jak prawdopodobnie wiesz, PHP jak wiele innych języków programowania, ma możliwość wyświetlenia stacktrace i backtrace. Standardowo, stacktrace i backtrace możemy znaleźć np. w logach w przypadku wystąpienia jakiegoś błędu.

function someFunction(string $testParameter): void { var_dump(debug_backtrace()); } someFunction('Test'); // Output: /* array(1) { [0]=> array(4) { ["file"]=> string(63) "/home/user/scripts/code.php" ["line"]=> int(8) ["function"]=> string(12) "someFunction" ["args"]=> array(1) { [0]=> string(4) "Test" } } } */

Przyznasz, iż to chyba nic specjalnego, co?

Otóż problem pojawi się w momencie, kiedy weźmiemy pod uwagę funkcję, która zawiera pewne dane wrażliwe takie jak np. hasło użytkownika lub hasło do bazy danych

function login(string $username, string $password): void { var_dump(debug_backtrace()); } login('admin', 'maciuś2013'); // Output: /* array(1) { [0]=> array(4) { ["file"]=> string(63) "/home/user/scripts/code.php" ["line"]=> int(8) ["function"]=> string(5) "login" ["args"]=> array(2) { [0]=> string(5) "admin" [1]=> string(11) "maciuś2007" } } } */

Aż strach pomyśleć co by było gdyby takie dane wyciekły jakimś kanałem!

Na przeciw temu problemowi wychodzi SensitiveParameter attribute:

<?php function login( #[\SensitiveParameter] string $username, #[\SensitiveParameter] string $password ): void { var_dump(debug_backtrace()); } login('admin', 'maciuś2013'); // Output: /* array(1) { [0]=> array(4) { ["file"]=> string(63) "/home/user/scripts/code.php" ["line"]=> int(8) ["function"]=> string(5) "login" ["args"]=> array(2) { [0]=> object(SensitiveParameterValue)#1 (0) { } [1]=> object(SensitiveParameterValue)#2 (0) { } } } } */

Jak widzisz, parametry, które zostały oznaczone atrybutem SensitiveParameter, zostały całkowicie ukryte! Not today, you nasty hacker!

Podsumowanie

To wszystko co na dzisiaj przygotowałem. Zachęcam Cię do przejrzenia listy RFC dla PHP 8.2. Jest tam jeszcze sporo ciekawych rzeczy! Daj znać w komentarzu, co sądzisz o nadchodzących zmianach w PHP 8.2.

Idź do oryginalnego materiału