PHP 8 jest tutaj! Został wydany 26 listopada 2020 r. Możesz go pobrać tutaj. Jest to nowa wersja główna, co oznacza, że wprowadzi kilka przełomowych zmian, a także wiele nowych funkcji i ulepszeń wydajności.
Ze względu na istotne zmiany istnieje większa szansa, że będziesz musiał dokonać pewnych zmian w swoim kodzie, aby uruchomić go w PHP 8. Jeśli jednak jesteś na bieżąco z najnowszymi wydaniami, aktualizacja nie powinna być zbyt trudne, ponieważ większość przełomowych zmian została wcześniej wycofana w wersjach 7.*. I nie martw się, wszystkie te deprecjacje są wymienione w tym poście.
Nowe funkcje
Zacznijmy od wszystkich nowych funkcji, to całkiem spora lista!
Union Type rfc
Biorąc pod uwagę dynamiczną naturę PHP, istnieje wiele przypadków, w których typy unii mogą być przydatne. Typy Unii to zbiór dwóch lub więcej typów, które wskazują, że można użyć jednego z nich.
public function foo(Foo|Bar $input): int|float;
Zauważ, że void
nigdy nie może być częścią union type, ponieważ wskazuje „brak wartości zwracanej w ogóle”. Co więcej, nullable
związki można zapisać za pomocą |null
lub za pomocą istniejącej ?
notacji:
public function foo(Foo|null $foo): void; public function bar(?Bar $bar): void;
JIT rfc
Kompilator JIT — w sam raz — obiecuje znaczną poprawę wydajności, choć nie zawsze w kontekście żądań internetowych.
Operator nullsafe rfc
Jeśli znasz operator łączenia wartości null, znasz już jego wady: nie działa on w przypadku wywołań metod. Zamiast tego potrzebujesz pośrednich kontroli lub polegaj na optional
pomocnikach dostarczanych przez niektóre frameworki:
$startDate = $booking->getStartDate(); $dateAsString = $startDate ? $startDate->asDateTimeString() : null;
Dzięki dodaniu operatora nullsafe możemy teraz mieć na metodach zachowanie podobne do łączenia wartości null!
$dateAsString = $booking->getStartDate()?->asDateTimeString();
Nazwane argumenty rfc
Nazwane argumenty umożliwiają przekazywanie wartości do funkcji poprzez określenie nazwy wartości, dzięki czemu nie trzeba brać pod uwagę ich kolejności, a także można pominąć parametry opcjonalne!
function foo(string $a, string $b, ?string $c = null, ?string $d = null) { /* … */ } foo( b: 'value b', a: 'value a', d: 'value d', );
Możesz przeczytać o nich szczegółowo w tym poście .
Atrybuty rfc
Atrybuty , powszechnie znane jako adnotacje w innych językach, umożliwiają dodawanie metadanych do klas bez konieczności analizowania bloków docblock.
Jeśli chodzi o szybki przegląd, oto przykład tego, jak wyglądają atrybuty, z RFC:
use App\Attributes\ExampleAttribute; #[ExampleAttribute] class Foo { #[ExampleAttribute] public const FOO = 'foo'; #[ExampleAttribute] public $x; #[ExampleAttribute] public function foo(#[ExampleAttribute] $bar) { } }
#[Attribute] class ExampleAttribute { public $value; public function __construct($value) { $this->value = $value; } }
Zauważ, że ta baza była Attribute
kiedyś wywoływana PhpAttribute
. w oryginalnym dokumencie RFC, ale później została zmieniona w innym dokumencie RFC .
Dopasuj wyrażenie rfc
Można to nazwać starszym bratem switch
wyrażenia: match
może zwracać wartości, nie wymaga break
instrukcji, potrafi łączyć warunki, używa ścisłych porównań typów i nie wykonuje żadnego wymuszania typu.
To wygląda tak:
$result = match($input) { 0 => "hello", '1', '2', '3' => "world", };
Constructor Property Promotion rfc
Ten dokument RFC dodaje cukier składniowy do tworzenia obiektów wartości lub obiektów transferu danych. Zamiast określać właściwości klas i ich konstruktor, PHP może teraz połączyć je w jedno.
Zamiast tego:
class Money { public Currency $currency; public int $amount; public function __construct( Currency $currency, int $amount, ) { $this->currency = $currency; $this->amount = $amount; } }
Możesz teraz to zrobić:
class Money { public function __construct( public Currency $currency, public int $amount, ) {} }
Nowy static
typ zwrotu rfc
Chociaż zwrot był już możliwy self
, static
nie był prawidłowym typem zwracanym aż do PHP 8. Biorąc pod uwagę dynamiczną naturę PHP, jest to funkcja, która przyda się wielu programistom.
class Foo { public function test(): static { return new static(); } }
Nowy mixed
typ rfc
Niektórzy mogą nazwać to złem koniecznym: ten mixed
typ powoduje, że wielu ma mieszane uczucia. Jest jednak bardzo dobry argument, aby to zrobić: brakujący typ może oznaczać wiele rzeczy w PHP:
- Funkcja nie zwraca nic lub null
- Spodziewamy się jednego z kilku typów
- Spodziewamy się typu, który nie może być podpowiedzią typu w PHP
Ze względu na powyższe powody dobrze mixed
jest dodać typ. mixed
samo oznacza jeden z tych typów:
array
bool
callable
int
float
null
object
resource
string
Zauważ, że mixed
może być również używany jako typ parametru lub właściwości, a nie tylko jako typ zwracany.
Zwróć też uwagę, że ponieważ mixed
zawiera już null
, nie można uczynić go wartością null. Następujące zdarzenia wywołają błąd:
// Fatal error: Mixed types cannot be nullable, null is already part of the mixed type. function bar(): ?mixed {}
Throw expression rfc
Ten dokument RFC zmienia się throw
z instrukcji na wyrażenie, co umożliwia zgłaszanie wyjątków w wielu nowych miejscach:
$triggerError = fn () => throw new MyError(); $foo = $bar['offset'] ?? throw new OffsetDoesNotExist('offset');
Dziedziczenie metodami prywatnymi rfc
Wcześniej PHP stosowało te same kontrole dziedziczenia w metodach publicznych, chronionych i prywatnych. Innymi słowy: metody prywatne powinny podlegać tym samym regułom podpisywania metod, co metody chronione i publiczne. To nie ma sensu, ponieważ metody prywatne nie będą dostępne dla klas podrzędnych.
Ten dokument RFC zmienił to zachowanie, dzięki czemu sprawdzanie dziedziczenia nie jest już wykonywane na metodach prywatnych. Co więcej, użycie final private function
również nie miało sensu, więc zrobienie tego spowoduje teraz wyświetlenie ostrzeżenia:
Warning: Private methods cannot be final as they are never overridden by other classes
Słabe mapy rfc
Zbudowana na podstawie słabych referencji RFC, które zostały dodane w PHP 7.4, WeakMap
implementacja została dodana w PHP 8. WeakMap
przechowuje odniesienia do obiektów, które nie zapobiegają zbieraniu śmieci.
Weźmy na przykład ORM-y, często implementują pamięci podręczne, które przechowują odniesienia do klas encji, aby poprawić wydajność relacji między encjami. Te obiekty encji nie mogą być zbierane bezużytecznie, o ile ta pamięć podręczna ma do nich odniesienie, nawet jeśli pamięć podręczna jest jedyną rzeczą, która się do nich odwołuje.
Jeśli ta warstwa buforowania używa zamiast tego słabych referencji i map, PHP zbierze te obiekty, gdy nic więcej się do nich nie odniesie. Zwłaszcza w przypadku ORM-ów, które mogą zarządzać kilkoma setkami, jeśli nie tysiącami podmiotów w ramach żądania; słabe mapy mogą oferować lepszy, bardziej przyjazny dla zasobów sposób radzenia sobie z tymi obiektami.
Oto jak wyglądają słabe mapy, przykład z RFC:
class Foo { private WeakMap $cache; public function getSomethingWithCaching(object $obj): object { return $this->cache[$obj] ??= $this->computeSomethingExpensive($obj); } }
Przyzwolenie ::class
na przedmioty rfc
Mała, ale użyteczna nowa funkcja: teraz można jej używać ::class
na obiektach, zamiast get_class()
na nich. Działa tak samo jak get_class()
.
$foo = new Foo(); var_dump($foo::class);
Nieprzechwytujące połowy rfc
Za każdym razem, gdy chciałeś złapać wyjątek przed PHP 8, musiałeś przechowywać go w zmiennej, niezależnie od tego, czy użyłeś tej zmiennej, czy nie. W przypadku połowów nie przechwytujących możesz pominąć zmienną, więc zamiast tego:
try { // Something goes wrong } catch (MySpecialException $exception) { Log::error("Something went wrong"); }
Możesz teraz to zrobić:
try { // Something goes wrong } catch (MySpecialException) { Log::error("Something went wrong"); }
Pamiętaj, że wymagane jest zawsze określenie typu, nie możesz mieć pustego catch
. Jeśli chcesz przechwycić wszystkie wyjątki i błędy, możesz użyć Throwable
jako typu przechwytywania.
Przecinek końcowy na listach parametrów rfc
Było to już możliwe podczas wywoływania funkcji, ale w listach parametrów wciąż brakowało obsługi końcowych przecinków. Jest to teraz dozwolone w PHP 8, co oznacza, że możesz wykonać następujące czynności:
public function( string $parameterA, int $parameterB, Foo $objectfoo, ) { // … }
Na marginesie: końcowe przecinki są również obsługiwane na use
liście zamknięć, było to przeoczenie i teraz zostało dodane w osobnym dokumencie RFC .
Twórz DateTime
obiekty z interfejsu
Możesz już utworzyć DateTime
obiekt za pomocą DateTimeImmutable
, ale odwrotna droga była trudna. Istnieje teraz uogólniony sposób na konwersję i obiekty do siebie.
DateTime::createFromInterface(DateTimeInterface $other); DateTimeImmutable::createFromInterface(DateTimeInterface $other);
Nowy Stringable
interfejs rfc
Stringable
Interfejs może być używany do niczego wpisz podpowiedź, który implementuje __toString()
. Ilekroć klasa implementuje __toString()
, automatycznie implementuje interfejs zakulisowo i nie ma potrzeby ręcznej implementacji.
class Foo { public function __toString(): string { return 'foo'; } } function bar(string|Stringable $stringable) { /* … */ } bar(new Foo()); bar('abc');
Nowa str_contains()
funkcja rfc
Niektórzy mogą powiedzieć, że to już dawno spóźnione, ale w końcu nie musimy strpos()
już polegać na tym, czy łańcuch zawiera inny łańcuch.
Zamiast tego:
if (strpos('string with lots of words', 'words') !== false) { /* … */ }
Teraz możesz to zrobić
if (str_contains('string with lots of words', 'words')) { /* … */ }
Nowe str_starts_with()
i str_ends_with()
funkcje rfc
Dwie inne już dawno spóźnione, te dwie funkcje zostały teraz dodane do rdzenia.
str_starts_with('haystack', 'hay'); // true str_ends_with('haystack', 'stack'); // true
Nowa fdiv()
funkcja pr
Nowa fdiv()
funkcja robi coś podobnego do funkcji fmod()
i intdiv()
, co pozwala na dzielenie przez 0. Zamiast błędów otrzymasz INF
, -INF
lub NAN
, w zależności od przypadku.
Nowa get_debug_type()
funkcja rfc
get_debug_type()
zwraca typ zmiennej. Brzmi jak coś gettype()
by zrobiło? get_debug_type()
zwraca bardziej przydatne dane wyjściowe dla tablic, łańcuchów, klas anonimowych i obiektów.
Na przykład wywołanie gettype()
klasy \Foo\Bar
zwróci object
. Użycie get_debug_type()
zwróci nazwę klasy.
Pełną listę różnic między get_debug_type()
i gettype()
można znaleźć w RFC.
Nowa get_resource_id()
funkcja pr
Zasoby to specjalne zmienne w PHP, odnoszące się do zasobów zewnętrznych. Jednym z przykładów jest połączenie MySQL, inny uchwyt pliku.
Każdemu z tych zasobów przypisywany jest identyfikator, choć wcześniej jedynym sposobem poznania tego identyfikatora było rzucenie zasobu na int
:
$resourceId = (int) $resource;
PHP 8 dodaje get_resource_id()
funkcje, dzięki czemu ta operacja jest bardziej oczywista i bezpieczna dla typów:
$resourceId = get_resource_id($resource);
Metody abstrakcyjne w poprawie cech rfc
Cechy mogą określać metody abstrakcyjne, które muszą być zaimplementowane przez korzystające z nich klasy. Jest jednak zastrzeżenie: przed PHP 8 sygnatury implementacji tych metod nie były sprawdzane. Obowiązywały następujące informacje:
trait Test { abstract public function test(int $input): int; } class UsesTrait { use Test; public function test($input) { return $input; } }
PHP 8 wykona odpowiednią walidację podpisu metody podczas używania cechy i implementacji jej abstrakcyjnych metod. Oznacza to, że zamiast tego musisz napisać to:
class UsesTrait { use Test; public function test(int $input): int { return $input; } }
Implementacja obiektowa token_get_all()
rfc
token_get_all()
Zwraca tablicę wartości. Ten dokument RFC dodaje PhpToken
klasę z metodą. Ta implementacja działa z obiektami zamiast zwykłych wartości. Zużywa mniej pamięci i jest łatwiejszy do odczytania.PhpToken::tokenize()
Poprawki składni zmiennej rfc
Z RFC: „Uniform Variable Syntax RFC rozwiązał szereg niespójności w składni zmiennych PHP. Ten dokument RFC ma na celu zajęcie się niewielką garstką przypadków, które zostały przeoczone.”
Wpisz adnotacje dla funkcji wewnętrznych
Wiele osób rzuciło się, aby dodać odpowiednie adnotacje do wszystkich funkcji wewnętrznych. To był długotrwały problem i ostatecznie można go było rozwiązać po wszystkich zmianach wprowadzonych w PHP w poprzednich wersjach. Oznacza to, że wewnętrzne funkcje i metody będą miały pełną informację o typie w odbiciu.
ext-json
zawsze dostępne rfc
Wcześniej można było skompilować PHP bez włączonego rozszerzenia JSON, nie jest to już możliwe. Ponieważ JSON jest tak szeroko stosowany, najlepsi programiści mogą zawsze polegać na tym, że istnieje, zamiast upewniać się, że rozszerzenie istnieje.
Przełamujące zmiany
Jak wspomniano wcześniej: jest to duża aktualizacja, a zatem nastąpią przełomowe zmiany. Najlepszą rzeczą do zrobienia jest przyjrzenie się pełnej liście najważniejszych zmian w dokumencie UPGRRADING .
Wiele z tych przełomowych zmian zostało jednak przestarzałych w poprzednich wersjach 7.*, więc jeśli przez lata byłeś na bieżąco, aktualizacja do PHP 8 nie powinna być aż tak trudna.
Masz dość zarządzania serwerami? Sprawdź bezserwerowe objaśnienie wizualne autorstwa Matthieu Napoli i dowiedz się, jak tworzyć skalowalne aplikacje PHP na AWS.
Spójne błędy typu rfc
Funkcje zdefiniowane przez użytkownika w PHP będą już rzucały TypeError
, ale funkcje wewnętrzne nie , raczej emitowały ostrzeżenia i zwracały null
. Od PHP 8 zachowanie funkcji wewnętrznych zostało ujednolicone.
Przeklasyfikowane ostrzeżenia silnika rfc
Wiele błędów, które wcześniej powodowały tylko ostrzeżenia lub powiadomienia, zostało przekonwertowanych na poprawne błędy. Następujące ostrzeżenia zostały zmienione.
- Niezdefiniowana zmienna:
Error
wyjątek zamiast powiadomienia - Niezdefiniowany indeks tablicy: ostrzeżenie zamiast powiadomienia
- Dzielenie przez zero:
DivisionByZeroError
wyjątek zamiast ostrzeżenia - Próba zwiększenia/zmniejszenia właściwości '%s’ nieobiektu:
Error
wyjątek zamiast ostrzeżenia - Próba zmodyfikowania właściwości '%s’ nie-obiektu:
Error
wyjątek zamiast ostrzeżenia - Próba przypisania właściwości '%s’ nie-obiektu:
Error
wyjątek zamiast ostrzeżenia - Tworzenie domyślnego obiektu z pustej wartości:
Error
wyjątek zamiast ostrzeżenia - Próbuję uzyskać właściwość '%s’ nie-obiektu: ostrzeżenie zamiast powiadomienia
- Niezdefiniowana właściwość: %s::$%s: ostrzeżenie zamiast powiadomienia
- Nie można dodać elementu do tablicy, ponieważ następny element jest już zajęty:
Error
wyjątek zamiast ostrzeżenia - Nie można cofnąć przesunięcia w zmiennej nietablicy:
Error
wyjątek zamiast ostrzeżenia - Nie można użyć wartości skalarnej jako tablicy:
Error
wyjątek zamiast ostrzeżenia - Tylko tablice i
Traversables
można je rozpakować:TypeError
wyjątek zamiast ostrzeżenia - Nieprawidłowy argument podany dla foreach():
TypeError
wyjątek zamiast ostrzeżenia - Niedozwolony typ przesunięcia:
TypeError
wyjątek zamiast ostrzeżenia - Niedozwolony typ przesunięcia w isset lub pusty:
TypeError
wyjątek zamiast ostrzeżenia - Niedozwolony typ przesunięcia w unset:
TypeError
wyjątek zamiast ostrzeżenia - Konwersja tablicy na ciąg: ostrzeżenie zamiast powiadomienia
- Identyfikator zasobu #%d używany jako przesunięcie, rzutowanie na liczbę całkowitą (%d): ostrzeżenie zamiast powiadomienia
- Wystąpiło rzutowanie ciągu znaków: ostrzeżenie zamiast powiadomienia
- Niezainicjowane przesunięcie ciągu znaków: %d: ostrzeżenie zamiast powiadomienia
- Nie można przypisać pustego ciągu do przesunięcia ciągu:
Error
wyjątek zamiast ostrzeżenia - Dostarczony zasób nie jest prawidłowym zasobem strumienia:
TypeError
wyjątek zamiast ostrzeżenia
Operator @ nie wycisza już błędów krytycznych
Możliwe, że ta zmiana może ujawnić błędy, które ponownie były ukryte przed PHP 8. Upewnij się, że ustawiłeś je na swoich serwerach produkcyjnych!display_errors=Off
Domyślny poziom raportowania błędów
To teraz E_ALL
zamiast wszystkiego, ale E_NOTICE
i E_DEPRECATED
. Oznacza to, że może pojawić się wiele błędów, które wcześniej były po cichu ignorowane, chociaż prawdopodobnie istniały już przed PHP 8.
Domyślny tryb błędu PDO rfc
Z RFC: Bieżący domyślny tryb błędu dla PDO jest cichy. Oznacza to, że w przypadku wystąpienia błędu SQL nie mogą być emitowane żadne błędy ani ostrzeżenia, ani wyjątki, chyba że deweloper zaimplementuje własną jawną obsługę błędów.
Ten dokument RFC zmienia domyślny błąd w PHP 8. PDO::ERRMODE_EXCEPTION
Pierwszeństwo konkatenacji rfc
Ta zmiana jest już przestarzała w PHP 7.4, ale została teraz wprowadzona w życie. Gdybyś napisał coś takiego:
echo "sum: " . $a + $b;
PHP wcześniej zinterpretowałby to w ten sposób:
echo ("sum: " . $a) + $b;
PHP 8 sprawi, że będzie to interpretowane w ten sposób:
echo "sum: " . ($a + $b);
Bardziej rygorystyczne kontrole typu dla operatorów arytmetycznych i bitowych rfc
Przed PHP 8 możliwe było stosowanie operatorów arytmetycznych lub bitowych na tablicach, zasobach lub obiektach. To już nie jest możliwe i wyrzuci TypeError
:
[] % [42]; $object + 4;
Nazwy w przestrzeni nazw będące pojedynczym tokenem rfc
PHP używane do interpretowania każdej części przestrzeni nazw (oddzielonej odwrotnym ukośnikiem \
) jako sekwencji tokenów. Ten dokument RFC zmienił to zachowanie, co oznacza, że zastrzeżone nazwy mogą być teraz używane w przestrzeniach nazw.
Zrozumiałe ciągi numeryczne rfc
System typów PHP próbuje robić wiele inteligentnych rzeczy, gdy napotyka liczby w łańcuchach. Ten dokument RFC sprawia, że to zachowanie jest bardziej spójne i jasne.
Lepsze porównania ciągów do liczb rfc
Ten dokument RFC naprawia bardzo dziwny przypadek w PHP, w którym 0 == "foo"
rezultatem jest true
. Jest kilka innych skrajnych przypadków, takich jak ten, i ten RFC je naprawia.
Zmiany odbicia
Kilka metod refleksji zostało przestarzałych:
ReflectionFunction::isDisabled()
ReflectionParameter::getClass()
ReflectionParameter::isCallable()
Powinieneś teraz użyć, ReflectionType
aby uzyskać informacje o typie parametru:
$reflectionParameter->getType()->allowsNull();
Jeśli typ jest pojedynczym typem, zwraca instancję , z której możesz uzyskać jego nazwę i czy jest wbudowana:ReflectionParameter::getType()
ReflectionNamedType
$reflectionParameter->getType()->getName(); $reflectionParameter->getType()->isBuiltin();
Jeśli jednak typ jest typem unii, otrzymasz instancję ReflectionUnionType
, która może dać ci tablicę w następujący ReflectionNamedType
sposób:
$reflectionParameter->getType()->getTypes();
Sprawdzenie, czy typ jest sumą, czy nie, można wykonać za pomocą instanceof
sprawdzenia:
if ($reflectionParameter->getType() instanceof ReflectionNamedType) { // It's a single type } if ($reflectionParameter->getType() instanceof ReflectionUnionType) { // It's a union type }
Następnie zmieniono trzy sygnatury metod klas odbić:
ReflectionClass::newInstance($args); ReflectionFunction::invoke($args); ReflectionMethod::invoke($object, $args);
Teraz stały się:
ReflectionClass::newInstance(...$args); ReflectionFunction::invoke(...$args); ReflectionMethod::invoke($object, ...$args);
Przewodnik aktualizacji określa, że jeśli rozszerzysz te klasy i nadal chcesz obsługiwać zarówno PHP 7, jak i PHP 8, dozwolone są następujące sygnatury:
ReflectionClass::newInstance($arg = null, ...$args); ReflectionFunction::invoke($arg = null, ...$args); ReflectionMethod::invoke($object, $arg = null, ...$args);
Masz dość zarządzania serwerami? Sprawdź bezserwerowe objaśnienie wizualne autorstwa Matthieu Napoli i dowiedz się, jak tworzyć skalowalne aplikacje PHP na AWS.
Stabilne sortowanie rfc
Przed PHP 8 algorytmy sortowania były niestabilne. Oznacza to, że kolejność równych elementów nie była gwarantowana. PHP 8 zmienia zachowanie wszystkich funkcji sortujących na sortowanie stabilne.
Błąd krytyczny dla niezgodnych sygnatur metod rfc
Z RFC: Błędy dziedziczenia z powodu niezgodnych sygnatur metod obecnie generują błąd krytyczny lub ostrzeżenie w zależności od przyczyny błędu i hierarchii dziedziczenia.
[…] mój ostatni wpis co zmieniło sie w PHP8.0, ale już na horyzoncie jest 8.1 z cała gamą świetnych nowości! Sprawdź je i […]