PHP 8.1 – jakie zmiany?

zegarek z godziną 8:01

Data wypuszczenia PHP 8.1 przypada na 25 listopada 2021 roku. Nie jest to skok dużej wersji, więc rewolucji nie ma się co spodziewać, ale na pewno jest kilka zmian wartych omówienia. Czy wszystkie na plus? Jak zwykle, zależy dla kogo. Ja postaram się przedstawić swój punkt widzenia, ale też opisać owe zmiany w taki sposób, by każdy z Was był w stanie sam ocenić.

Co nowego w PHP 8.1

Typy never i intersection

Pojawia się kilka usprawnień w typowaniu. Tak jak nie jestem zadowolony z ostatnich zmian, czyli typu mixed i typów łączonych, tak tym razem jestem trochę bardziej optymistycznie nastawiony. Typ never przyda się wówczas, gdy oczekuje się, że program skończy swoje działanie w danej funkcji. Innymi słowy, jedynymi opcjami na powodzenie w tym przypadku jest rzucenie wyjątku, bądź użycie natywnych funkcji die() lub exit(). Nie jest to więc to samo, co znany wszystkim do tej pory typ void. Zresztą z typu void da się wyjść wcześniej używając return; za to typ never na to nie pozwoli. Jeśli powyższe warunki nie zostaną spełnione to operacja zakończy się błędem TypeError. Warto też zaznaczyć, że jest to typ zwracany, więc nie można zadeklarować zmiennej o takim typie. Co z resztą chyba i tak nie miałoby sensu. Dodatkowo jeśli Wasze metody bądź klasy zawierają słowo kluczowe never to czas z niego zrezygnować, bo rzecz jasna w PHP 8.1 staje się ono zarezerwowane.

Druga zmiana w typowaniu, której tłumaczenia nazwy się nie podejmę, to tak zwane typy intersection. Są nieco podobne do typów łączonych (union types). Idea jest jednak inna. W tych pierwszych zezwala się na wartość jednego bądź drugiego typu, a w tych drugich chodzi o wymuszenie obu typów. Rzecz jasna ma to sens dla interfejsów, bo zmienna nie może być zarówno typu integer jak i string. W sumie dałoby się zmontować na przykład integera i nulla. Tak czy inaczej, ta zmiana działa tylko dla obiektów. Mogą wystąpić sytuacje, gdzie oczekuje się że obiekt będzie spełniał więcej niż jeden interfejs i właśnie na to zezwala owa zmiana. Składnia nowego mechanizmu prezentuje się następująco.

public function add(FirstInterface&SecondInterface $koddlo) {}

Trzeba dodać, że opcja nullable nie jest wspierana w tej kombinacji, więc poniższy kod spowoduje błąd.

public function koddlo(?FirstInterface&SecondInterface $koddlo) {}

Tak jak napisałem wcześniej, tego rodzaju usprawnienia są krokiem w dobrą stronę. Mają swoje konkretne zastosowania, ale raczej nie ma tutaj miejsca na nadużycia jak w przypadku typu mixed czy union types.

Enums (Enumerations)

Każdy z Was, kto interesuje się chociaż trochę nową wersją, pewnie obstawiał że od tej zmiany zacznę. Przewrotnie tego nie zrobiłem, ale fakt faktem jest to chyba najważniejsze usprawnienie. Wydaje mi się, że sporo osób czekało na tego rodzaju nowość. Zresztą wielu programistów korzystało z zewnętrznych paczek, które na takową implementację pozwalały. Często też sytuacje, gdzie typ wyliczeniowy by się nadał ogarniało się za pomocą stałych.

enum Status {
  case CREATED;
  case CLOSED;
  case CANCELED;
}

Powyższa implementacja to najprostsza z możliwych, a z taką konstrukcją można już zrobić wiele. Przede wszystkim powstaje typ Status, którego można używać w typowaniu. Do wartości Enuma można odwoływać się jak do stałych Status::CREATED, stąd też użyłem dużych liter. Chyba taka konwencja się przyjmie i z tego co kojarzę w innych językach jest tak samo. Ciekawą opcją jest to, że typy wyliczeniowe są też obiektami. Mogą więc zawierać metody, implementować interfejsy i korzystać z traitów. Zmiana w moim odczuciu jak najbardziej na plus – typ ten znajdzie wiele zastosowań.

Optymalizacja opcache

Wraz z PHP 8.1 pojawi się poprawa optymalizacyjna. Poprawki dotyczą mechanizmu opcache i szacuje się, że mogą poprawić wydajność aplikacji nawet o kilka procent. Na pewno zmiana w dobrym kierunku i nie mogłem jej pominąć.

Readonly

Bardzo ciekawe usprawnienie. Można oznaczyć pole klasy jako tylko do odczytu. Co oznacza tyle, że będzie można jednokrotnie ustawić jego wartość i będzie ona niemutowalna. Ten sam rezultat można oczywiście uzyskać aktualnie, pomijając akcesory dla własności prywatnych. Readonly działa jednak także dla pól publicznych, więc fajne rozwiązanie na przykład w kontekście niemutowalnych DTO. Co ważne, nie da się użyć tego słowa kluczowego jeśli pole nie ma określonego typu.

Niestety taka niemutowalność nie zadziała dla obiektów, które jak wiemy w PHP są używane za pomocą referencji. Przydałoby się jeszcze usprawnienie dla list i kolekcji, tak jak w niektórych językach można zwrócić niemodyfikowalny zbiór. W PHP trzeba ratować się własną implementacją, a zwracanie oryginalnej kolekcji może prowadzić do wielu nieoczekiwanych rezultatów, o czym pisałem przy okazji wpisu o enkapsulacji kolekcji.

Fiber

Temat wydaje się trochę bardziej skomplikowany, a ja przyznam szczerze, że się na nim nie znam. Mogę jednak zapewnić, że większość z Was, tak jak ja, nie musi go zgłębiać. Jedyne co, to przejrzałem RFC do którego Was odsyłam. Wiem na pewno, zę prawdopodobnie bezpośrednio z tego nie skorzystam. Usprawnienia dotykają tematu asynchroniczności w PHP. Do tego wykorzystuje się kilka popularnych bibliotek i pewnie ich twórcy będą mogli ten mechanizm z powodzeniem wykorzystać.

Obiekt jako domyślna wartość

public function blog(Koddlo $blog = new Koddlo()) {}

Tak jak typy skalarne do tej pory można było przypisać jako domyślne, tak obiektów już nie. Od tej pory będzie to możliwe, chociaż nie widzę zbyt wielu zastosowań.

Stałe jako final

Stałe klasy można nadpisywać podczas dziedziczenia. PHP 8.1 umożliwia oznaczenie const jako final, dzięki czemu nie będzie możliwości jej zmiany.

Rozpakowywanie tablic

Funkcjonalność, która zawitała w wersji 7.4, ale nie radziła sobie z tablicami asocjacyjnymi. Przy okazji wersji 8.1 to się zmieni i tego rodzaju rozpakowania ...$koddlo, będzie można już użyć również w tym kontekście. Myślę, że przydatna rzecz, chociaż przyznam że nie często z niej korzystam. Stary dobry array_merge() nie zawodzi.

Funkcja array_is_list()

Nowa wbudowana funkcja, która pozwala na sprawdzenie, czy tablica jest listą. W tym kontekście, lista to tablica, która ma standardowe klucze, czyli numerowane liczbami rozpoczynając od 0 i kolejno 1,2,3… przy czym kolejność musi być zachowana.

Kilka innych zmian

Na sam koniec wypunktuję jeszcze kilka mniejszych zmian, i oczywiście zainteresowanych odsyłam do RFC:

  • Poziom raportowania błędów dla MySQLi domyślnie ustawiony na exceptions;
  • Nowe funkcje fsync() i fdatasync();
  • Nowa wartość full_path w zmiennej $_FILES przy wgrywaniu katalogów;
  • Bezstratne kodowanie WebP w rozszerzeniu GD;
  • Interfejs Serializable oznaczony jako deprecated;
  • Przekazanie null do wbudowanych funkcji, które na to nie pozwalają oznaczone jako deprecated;
  • Automatyczna konwersja float do int oznaczona jako deprecated.

PHP 8.1 – podsumowanie

To oczywiście nie wszystkie zmiany, ale te które z jakiegoś powodu uznałem za warte poruszenia. Mam nadzieję, że tego rodzaju materiał pozwoli Wam rozeznać się w nowej wersji bez konieczności przegrzebywania się przez długie RFC. Jeśli jednak macie taką ochotę to zostawiam link. Pełna lista zmian znajduje się także w skróconej wersji pod tym linkiem.

Bardzo przystępnie i dużo szerzej zmiany zostały opisane na stronie php.watch. Gorąco polecam, bo z ciekawości przejrzałem sobie jak inni twórcy podeszli do tematu i chyba najbardziej ten materiał przypadł mi do gustu. W zasadzie mogłem do niego zalinkować i odpuścić sobie własny materiał, ale stwierdziłem że może dla kogoś właśnie ten będzie pomocny. Dorzuciłem do niego też kilka swoich unikalnych uwag i przemyśleń, z którymi możecie się zgadzać lub nie. Tak, czy inaczej PHP 8.1 wydaje się być całkiem przyjemną wersją – nie dostrzegam tu zmian, które bardzo by mi przeszkadzały. Wręcz przeciwnie, raczej mam pozytywny odbiór.

Krystian Żądło
Programista PHP i właściciel marki Koddlo. Pasjonat czystego kodu i dobrych praktyk programowania obiektowego. Prywatnie fan angielskiej piłki nożnej, dobrego humoru oraz podcastów.