PHP 8 - co nowego?
O premierze PHP 8 już od jakiegoś czasu w sieci robi się głośno i choć przed nami jeszcze blisko dwa miesiące, już teraz wiemy, co nowego ukaże się w wersji 8 i jakie zmiany mogą realnie utrudnić łatwą przesiadkę z PHP 7 na nową wersję.
Niedawno światło dzienne ujrzała ostatnia z czterech zaplanowych wersji beta, a zatem do planowanej premiery na 26 Listopada 2020 przed nami jeszcze 4 wydania w wersji RC.
Wszelkie prace nad nowymi funkcjonalnoścami zostały zamrożone od pewnego czasu, dlatego możemy już dziś z dużą dozą pewności powiedzieć, co nowego pojawi się, a co odejdzie do lamusa wraz z wydaniem nowej, głównej wersji najpopularniejszego webowego języka, jakim jest PHP.
W naszej agencji, w której na co dzień zajmujemy się dostarczaniem usług drupalowych, wsparciem Drupala, a w swoim zespole mamy wielu PHP developerów, żywo przyglądamy się wszystkim aktualnościom i dlatego w poniższym zestawieniu prezentujemy najważniejsze naszym zdaniem zmiany, które przyniesie odsłona numer 8.
Union types (Unia)
To ukłon w stronę statycznego typowania przy jednocześnym zachowaniu dynamicznej natury języka. Unia pozwala na definiowanie zestawu typów (dwóch lub więcej), zarówno dla danych wejściowych, jak i zwracanych. Dotychczasz składnia języka nie pozwalała na korzystanie z unii, a problem ten był obchodzony poprzez definiowanie typów w adnotacjach.
class Example {
private int|string $id;
public function setId(int|string $id): void {
$this->id = $id;
}
public function getId(): int|string {
return $this->id;
}
}
Niedopuszczalne jest definiowanie wśród zwracanych typów typu void, ponieważ typ ten już określa, że dana funkcja nie zwróci żadnej wartości. Możemy natomiast bez problemu wśród zwracanych typów zdefiniować null do oznaczenia tzw. wartości nullable.
Named arguments (Argumenty nazwane)
To problem, z którym spotkało się wielu programistów PHP. Nie raz przychodzi skorzystać z metod, czy funkcji, które przyjmują większą ilość argumentów opcjonalnych, z czego wiele z nich posiada domyślne wartości. Do tej pory nie pozostawało nic innego jak kopiowanie wszystkich poprzedzających domyślnych wartości z funkcji w tej samej kolejności, aby przekazać do jednego z argumentów własną wartość. Named arguments pozwalają na przekazanie parametru, bazując na jego nazwie a nie na kolejności.
foo(string $b, ?string $a, ?string $r): {
}
Example::foo(
b: 'Foo',
r: 'Bar',
);
Constructor property promotion
Jeżeli przypisywanie wielu argumentów w konstruktorze do właściwości obiektu spędzało Ci sen z powiek, to w PHP 8 możesz o tym zapomnieć. Co prawda nie jest to nic więcej jak tzw. "syntatctic sugar", ale z pewnością funkcjonalność ta zwiększy czytelność nie jednej klasy w twojej aplikacji. Poniżej porównanie konstrukturów w PHP 7 i PHP 8.
// PHP 7
class Example {
public Foo $foo;
protected Bar $bar;
public function __construct(
Foo $foo,
Bar $bar
) {
$this->foo = $foo;
$this->bar = $bar;
}
}
// PHP 8
class Example {
public function __construct(
public Foo $foo,
protected Bar $bar,
) {}
}
Attributes (Atrybuty)
Znane niektórym pod nazwą adnotacji, do tej pory tworzone jedynie w formie komentarzy (odczytywane przez dedykowane biblioteki takie jak Doctrine ORM), w końcu doczekały się awansu do bycia pełnoprawną częścią języka.
Po burzliwej batalii dotyczącej tego, w jaki sposób adnotacje powinny być oznaczane, wybrano podwójny znak większości i mniejszości jako otwarcie, i zamknięcie atrybutu.
use Php\Attributes\Deprecated;
<<Deprecated("Use bar() instead")>>
function foo() {}
Match expression
Choć nazwa tej nowej funkcjonalności z pozoru może sugerować związek z wyrażeniami regularnymi, to jest to raczej bliski krewny instrukcji switch. Dzięki temu mechanizmowy możemy zwrócić interesującą nas wartość na podstawie parametru wejściowego, bez użycia dodatkowych słów kluczowych tj. break, return. Co więcej, match używa silnego typowania do porównia wartości (analogicznie do użycia znaku porównania ===), a jeżeli żaden z przypadków nie jest spełniony, to domyślnie wyrzucany jest wyjątek UnhandeledMatchError.
$controller = match ($status_code) {
200 => new PageController(),
301, 302, 303 => new RedirectController(),
404 => new PageNotFoundController(),
};
JIT (Just in time compiler)
Mechanizm dostępny do testowania już w wersji PHP 7.4 w końcu uzyskał swoje oficjalne wydanie. JIT to nic innego jak kompilacja do kodu maszynowego bezpośrednio przed jego wykonaniem. W praktyce pozwala to wykonywać kod aplikacji "w locie", szybciej niż jest to możliwe z użyciem tradycyjnego interpretera. Można to poniekąd porównać to cachowania raz zinterpretowanego kodu.
Dla tych, którzy kojarzą Hack i HHVM (HipHop Virtual machine) stworzone przez programistów facebook.com zapewne JIT nie jest żadną nowością. W środowisku PHP natomiast do wersji 8 podejmowano ciągłe próby poprawy wydajności wszystkimi dostępnymi sposobami z pominięciem JIT. Dopiero z braku realnych możliwości zdecydowano się pójść w ślady kolegów z portalu Facebook.
Pozostałe nowe funkcjonalności
Wśród nowości jakie zaoferuje nam PHP 8, znajdziemy jeszcze kilka pomniejszych funkcjonalności, które okazać się mogą ciekawe także dla nowych biznesów - PHP uchodzi za idealne rozwiązanie dla startupów.
- nullsafe operator - odpowiednik operatora null coalescing dla metod np. $item->getField()?->getValue();
- static - dodano jako typ zwracanej wartości, wcześniej dostępny był jednie self;
- mixed - nowy typ wartości, który oznacza to samo co znana wartość mixed w komentarzach, a zatem dowolny typ prosty;
- WeakMaps - mechanizm do przechowywania referencji, który jednocześnie pozwala na ich usuwanie przez garbage collector;
- użycie magicznej metody ::class na obiektach - pozwala na uzyskanie tej samej wartości, jaka zwracana jest z funkcji get_class();
- trailing comma w liście parametrów funkcji;
- przechwytywanie wyjątków bez konieczności przypisania do zmiennej;
- nowy interfesj Stringable - automatycznie przypisany do wszystkich klas, które implementują metodę __toString();
- walidacja metod abstrakcyjnych pochodzących z trait'ów.
Nowe funkcje
Poza wymienionym do tej pory zmianami w składni języka, wraz z wersją PHP 8, pojawi się kilka przydatnych nowych funkcji, które w większości stanowią tzw. lukier składniowy, jednakże znacznie podnosząc komfort codziennej pracy z językiem. Do najważniejszych z nich należy zaliczyć:
str_contains()
Z pewnością nie raz przyszło wam sprawdzać, czy dany string zawiera w sobie jakąś zdefiniowaną subfrazę z użyciem funkcji strpos i sprawdzeniem, czy zwracana wartość jest różna od FALSE. Funkcja str_contains potrafi wykonać to sprawdzenie za nas w tle.
str_starts_with() i str_ends_with()
Obie funkcje zajmujące się dokładnie tym, na co nazwa wskazuje, a zatem sprawdzeniem, czy dany string zaczyna lub kończy się na określoną wartość.
get_debug_type()
To funkcja, która jest rozwinięciem funkcji gettype() z tym, że zwraca ona dokładny typ, taki jaki definujemy w kodzie, a zatem int zamiast integer, float zamiast double, czy \Foo\Bar zamiast object.
Zmiany ogólne
Jak na wydanie głównej wersji przystało, nie obędzie się także bez różnych zmian w istniejących już elementach języka. W PHP 8 widać wyraźny krok w kierunku uporządkowania wszystkich mechanizmów tak, aby były one bardziej przejrzyste, przewidywalne i nie wprowadzały niepotrzebnego zamieszania.
Do ważnych zmian należy zaliczyć zwracanie wyjątków TypeError i ValueError dla funkcji wbudowanych. Poprawiono mechanizmy porównywania zmiennych różnych typów, kolejności konkatenacji, czy weryfikacji typów przy operacjach arytmetycznych i bitowych. Usunięto możliwość wywoływania statycznie metod, które nie są statyczne.
Ponadto usunięto takie funkcje jak: create_function(), each(), natomiast zmieniono mechanizmy funkcjonowania m.in. funkcji array_key_exists() czy define().
Ważne zmiany zaszły także w domyślnych mechanizmach dotyczących kontroli i wyświetlania błędów. Domyślną wartością dla raportowania błędów będzie E_ALL, a operator @ nie będzie już więcej maskował błędów krytycznych.
Podsumowanie
Nowa wersja PHP 8 to pewny krok do uporządkowania języka, a zarazem wydanie, które wnosi wiele długo oczekiwanych funkcjonalności.
W powyższym tekście uwzględniłem najbardziej kluczowe zmiany dotyczące tego, czego możemy się spodziewać, a co może być istotne w kontekście realizowania usług PHP developmentu. Akcent jednak chciałbym położyć na kompiler JIT, który jest tematem oddzielnego wpisu.