Nowa wersja interpretera PHP 8.0 zostanie wydana 26 listopada 2020 roku. – sprawdź jakie nowości ta zawiera ta przełomowa wersja PHP.
Wersja PHP 8.0 to nowe główne wydanie interpretera, co oznacza, że wprowadza ona sporo istotnych zmian, a także wiele nowych funkcji i ulepszeń wydajności. Obecnie PHP 8.0 jest w fazie zamrożenia, czyli nie można już dodawać żadnych nowych funkcji. Z powodu istotnych zmian istnieje spora szansa, że będziesz musiał wprowadzić pewne zmiany w swoim dotychczasowym kodzie, aby zadziałał w PHP 8. Nowa, stabilna wersja PHP 8.0 zostanie wydana 26 listopada 2020 roku.
Przeczytaj również: Jak włączyć PHP 7.4 na serwerze hostowanym w home.pl?
Jeśli jednak jesteś na bieżąco z najnowszymi wydaniami, aktualizacja nie powinna przysporzyć kłopotów, ponieważ większość istotnych zmian została uznana za przestarzałą już w wersjach 7. *. Jeśli jednak coś będziesz musiał zmienić, to istnieje duże prawdopodobieństwo, że znajdziesz odpowiedź w tym wpisie.
Oprócz przełomowych zmian, PHP 8 oferuje również ładny zestaw nowych funkcji, takich jak długo wyczekiwany kompilator JIT (just in time), typy unii, atrybuty i wiele innych.
Nowości w PHP 8.0
Typy unii RFC
Biorąc pod uwagę dynamiczną naturę języka 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.
Zwróć uwagę, że void
nigdy nie może być częścią typu unii, ponieważ oznacza „brak wartości zwracanej”. Ponadto związki dopuszczające wartość null
able można zapisać przy użyciu |null
lub przy użyciu istniejącej ?
notacji:
public function foo(Foo|Bar $input): int|float;
JIT (Just In Time) RFC
Kompilator JIT ma zapewnić znaczną poprawę wydajności stron internetowych, choć nie zawsze w kontekście żądań internetowych. Wygląda jednak na to, że w testach porównawczych dla rzeczywistych aplikacji internetowych JIT nie robi tak dużej różnicy. Zobaczymy jak to będzie wyglądało w praktyce.
Operator nullsafe RFC
Jeśli znasz operator koalescencji null
, znasz już jego wady: nie działa on na wywołaniach metod. Zamiast tego potrzebujesz sprawdzeń pośrednich lub polegasz na optional
– wsparciu dostarczanym przez niektóre frameworki:
$startDate = $booking->getStartDate();
$dateAsString = $startDate ? $startDate->asDateTimeString() : null;
Po dodaniu operatora nullsafe
, możemy teraz uzyskać w metodach zachowanie podobne do koalescencji null
!
$dateAsString = $booking->getStartDate()?->asDateTimeString();
Nazwane argumenty RFC
Nazwane argumenty umożliwiają przekazywanie wartości do funkcji, określając nazwę wartości, dzięki czemu nie musisz brać pod uwagę ich kolejności, a także możesz 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',
);
Atrybuty RFC
Atrybuty, powszechnie znane jako adnotacje w innych językach, oferują sposób dodawania metadanych do klas bez konieczności analizowania bloków dokumentów.
Oto przykład wyglądu atrybutów ze specyfikacji 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;
}
}
Zwróć uwagę, że ten podstawowy Attribute
nosił nazwę PhpAttribute
w oryginalnym dokumencie RFC, ale został później zmieniony w innym dokumencie RFC.
Wyrażenie dopasowania RFC
Można to nazwaćstarszym bratem wyrażenia switch
: match
może zwracać wartości, nie wymaga instrukcji break
, może łą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 trochę ulepszeń składniowych do tworzenia obiektów wartości lub obiektów transferu danych. Zamiast określać właściwości klasy i konstruktora dla nich, PHP może teraz połączyć je w jedną.
Zamiast robić tak:
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ć tak:
class Money
{
public function __construct(
public Currency $currency,
public int $amount,
) {}
}
Nowy zwracany typ static
RFC
Chociaż zwracanie self
było już możliwe, static
nie był poprawnym typem zwracanym aż do PHP 8. Biorąc pod uwagę dynamiczny charakter PHP, jest to funkcja przydatna dla wielu programistów.
class Foo
{
public function test(): static
{
return new static();
}
}
Nowy typu mixed
RFC
Niektórzy mogą nazwać to złem koniecznym: typ mixed
powoduje, że wielu ma mieszane uczucia. Jest na to bardzo dobry argument: 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órego nie można wskazać w PHP.
Z powyższych powodów dobrze jest dodać typ mixed.
Sam mixed
oznacza jeden z tych typów:
array
bool
callable
int
float
null
object
resource
string
Zwróć uwagę, że mixed
może być również używany jako parametr lub typ właściwości, a nie tylko jako typ zwracany.
Należy również pamiętać, że ponieważ mixed
zawiera już wartość null
, nie można nadawać jej tej wartości. Poniższe spowoduje błąd:
// Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.
function bar(): ?mixed {}
Wyrażenie throw
RFC
Ta zmiana RFC zmienia throw
z instrukcji w wyrażenie, co umożliwia zgłoszenie wyjątku w wielu nowych miejscach:
$triggerError = fn () => throw new MyError();
$foo = $bar['offset'] ?? throw new OffsetDoesNotExist('offset');
Dziedziczenie metod prywatnych RFC
Wcześniej PHP stosowało te same kontrole dziedziczenia dla metod publicznych, chronionych i prywatnych. Innymi słowy: metody prywatne powinny przestrzegać tych samych reguł sygnatur 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, tak że te sprawdzenia dziedziczenia nie są już wykonywane na metodach prywatnych. Co więcej, użycie ostatecznej funkcji prywatnej również nie miało sensu, więc teraz spowoduje to ostrzeżenia:
Warning: Private methods cannot be final as they are never overridden by other classes
WeakMap RFC
Zbudowana na podstawie weakrefs RFC, która została dodana w PHP 7.4, implementacja WeakMap
została dodana w PHP 8. WeakMap
przechowuje odniesienia do obiektów, które nie chronią tych obiektów przed zbieraniem śmieci.
Weźmy na przykład ORM-y, które często implementują pamięci podręczne, które zawierają odwołania do klas jednostek, aby poprawić wydajność relacji między jednostkami. Te obiekty encji nie mogą być usuwane jako elementy bezużyteczne, o ile ta pamięć podręczna ma do nich odniesienie, nawet jeśli pamięć podręczna jest jedyną rzeczą, do której się odwołuje.
Jeśli ta warstwa pamięci podręcznej używa zamiast tego słabych odniesień i map, PHP będzie zbierać te obiekty bezużyteczne, gdy nic więcej już do nich się nie odwołuje. Zwłaszcza w przypadku ORM-ów, które mogą obsługiwać kilkaset, jeśli nie tysiące podmiotów w ramach zapytania; Weak Maps mogą oferować lepszy, bardziej przyjazny dla zasobów sposób radzenia sobie z tymi obiektami.
Oto jak wyglądają Weak Maps, przykład z RFC:
class Foo
{
private WeakMap $cache;
public function getSomethingWithCaching(object $obj): object
{
return $this->cache[$obj]
??= $this->computeSomethingExpensive($obj);
}
}
Zezwalanie ::class
na obiektach RFC
Mała, ale użyteczna nowa funkcja: można teraz używać ::class
na obiektach, zamiast używać na nich get_class()
. Działa tak samo, jak get_class()
.
$foo = new Foo();
var_dump($foo::class);
Niezabezpieczone przechwytywanie RFC
Ilekroć 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 przechwytywania można pominąć zmienną, więc zamiast tego:
try {
// Something goes wrong
} catch (MySpecialException $exception) {
Log::error("Something went wrong");
}
Możesz teraz zrobić to:
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 wychwycić wszystkie wyjątki i błędy, możesz użyć Throwable
jako typu łapania.
Końcowy przecinek na listach parametrów RFC
Możliwe jest to już podczas wywoływania funkcji, na listach parametrów nadal 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 liście use
, było to przeoczenie i teraz zostało dodane za pośrednictwem oddzielnego RFC.
Tworzenie obiektów DateTime
z poziomu interfejsu
Możesz już utworzyć obiekt DateTime z obiektu DateTimeImmutable
przy użyciu DateTime::createFromImmutable($immutableDateTime)
, ale odwrotna sytuacja była trudna. Dodając DateTime::createFromInterface()
i DatetimeImmutable::createFromInterface()
istnieje teraz uogólniony sposób konwersji obiektów DateTime
i DateTimeImmutable
na siebie.
DateTime::createFromInterface(DateTimeInterface $other);
DateTimeImmutable::createFromInterface(DateTimeInterface $other);
Nowy interfejs Stringable
RFC
Interfejs Stringable
może służyć do wpisywania podpowiedzi, które implementują __toString()
. Za każdym razem, gdy klasa implementuje __toString ()
, automatycznie implementuje interfejs w tle 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 funkcja str_contains()
RFC
Niektórzy mogą powiedzieć, że jest to już dawno spóźniona opcja, ale w końcu nie musimy już polegać na strpos()
, aby wiedzieć, czy ciąg zawiera inny ciąg.
Zamiast to robić w ten sposób:
if (strpos('string with lots of words', 'words') !== false) { /* … */ }
Możesz teraz to zrobić tak:
if (str_contains('string with lots of words', 'words')) { /* … */ }
Nowe funkcje str_starts_with()
i str_ends_with()
RFC
Dwie różne funkcje i od dawna spóźnione, są teraz dodane w corze.
str_starts_with('haystack', 'hay'); // true
str_ends_with('haystack', 'stack'); // true
Nowa funkcja fdiv()
PR
Nowa funkcja fdiv()
robi coś podobnego do funkcji fmod()
i intdiv()
, które pozwalają na dzielenie przez 0. Zamiast błędów, w zależności od przypadku, otrzymasz INF
, -INF
lub NAN
.
Nowa funkcja get_debug_type()
RFC
get_debug_type()
zwraca typ zmiennej. Wygląda na to, że zrobi coś w stylu gettype()
? Funkcja get_debug_type()
zwraca bardziej przydatne dane wyjściowe dla tablic, łańcuchów znaków, anonimowych klas i obiektów.
Na przykład wywołanie metody gettype()
w klasie \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 tym RFC.
Nowa funkcja get_resource_id()
PR
Zasoby to specjalne zmienne w PHP, odnoszące się do zasobów zewnętrznych. Jednym z przykładów jest połączenie MySQL, innym uchwyt pliku.
Każdemu z tych zasobów przypisywany jest identyfikator, chociaż wcześniej jedynym sposobem na poznanie tego identyfikatora było rzutowanie zasobu na int
:
$resourceId = (int) $resource;
PHP 8 dodaje funkcje get_resource_id()
, dzięki czemu ta operacja jest bardziej oczywista i bezpieczniejsza dla typów:
$resourceId = get_resource_id($resource);
Abstrakcyjne metody doskonalenia cech RFC
Cechy mogą określać abstrakcyjne metody, które muszą być implementowane przez wykorzystujące je klasy. Jest jednak pewne zastrzeżenie: przed PHP 8 podpis tych implementacji metod nie był sprawdzany. Obowiązuje:
trait Test {
abstract public function test(int $input): int;
}
class UsesTrait
{
use Test;
public function test($input)
{
return $input;
}
}
PHP 8 przeprowadzi poprawną 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 obiektu token_get_all()
RFC
Funkcja token_get_all()
zwraca tablicę wartości. Ten dokument RFC dodaje klasę PhpToken
z metodą PhpToken::getAll()
. Ta implementacja działa z obiektami zamiast zwykłymi wartościami. Zużywa mniej pamięci i jest łatwiejszy do odczytania.
Poprawki składni zmiennej RFC
Z dokumentu RFC: Uniform Variable Syntax RFC rozwiązał szereg niespójności w składni zmiennej PHP. Ten dokument RFC ma na celu zajęcie się niewielką garstką przypadków, które zostały przeoczone.
Adnotacje typu dla funkcji wewnętrznych EXTERNALS
Wiele osób oczekiwało dodawania odpowiednich adnotacji typu do wszystkich funkcji wewnętrznych. Był to długotrwały problem i ostatecznie rozwiązany 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.
ext-json
zawsze dostępny RFC
Wcześniej można było skompilować PHP bez włączonego rozszerzenia JSON, teraz już nie będzie to możliwe. Ponieważ JSON jest tak szeroko stosowany, najlepsi programiści zawsze mogą polegać na tym, że istnieje, zamiast najpierw upewnić się, że rozszerzenie istnieje.
Przełomowe zmiany
Wersja ósma PHP to poważna aktualizacja, dlatego zawiera także istotne zmiany. Najlepiej przejrzeć pełną listy ważnych zmian w dokumencie UPGRADING.
Wiele z tych przełomowych zmian zostało jednak wycofanych w poprzednich wersjach 7. *, więc jeśli przez lata byłeś na bieżąco, aktualizacja do PHP 8 nie powinna być taka trudna.
Spójne błędy typu RFC
Funkcje zdefiniowane przez użytkownika w PHP będą już zgłaszać TypeError
, ale funkcje wewnętrzne nie, raczej dadzą ostrzeżenia i będą zwracały wartość null
. Od PHP 8 zachowanie funkcji wewnętrznych zostało ujednolicone.
Przeklasyfikowane ostrzeżenia dotyczące silnika RFC
Wiele błędów, które wcześniej powodowały tylko ostrzeżenia lub powiadomienia, zostało przekształconych w prawidłowe błędy. Zmienione zostały poniższe ostrzeżenia:
- Niezdefiniowana zmienna: wyjątek
Error
zamiast powiadomienia - Niezdefiniowany indeks tablicy: ostrzeżenie zamiast powiadomienia
- Dzielenie przez zero: wyjątek
DivisionByZeroError
zamiast ostrzeżenia - Próba zwiększenia/zmniejszenia właściwości „%s” obiektu niebędącego obiektem: wyjątek
Error
zamiast powiadomienia - Próba zmodyfikowania właściwości „%s” obiektu niebędącego obiektem: wyjątek
Error
zamiast powiadomienia - Próba przypisania właściwości „%s” obiektu niebędącego obiektem: wyjątek
Error
zamiast powiadomienia - Tworzenie obiektu domyślnego z pustej wartości: wyjątek
Error
zamiast powiadomienia - Próba uzyskania właściwości „%s” obiektu niebędącego przedmiotem: 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: wyjątek
Error
zamiast powiadomienia - Nie można usunąć przesunięcia w zmiennej innej niż tablica: wyjątek
Error
zamiast powiadomienia - Nie można użyć wartości skalarnej jako tablicy: wyjątek
Error
zamiast powiadomienia - Rozpakować można tylko tablice i
Trawersable
: wyjątekTypeError
zamiast ostrzeżenia - Podano nieprawidłowy argument dla funkcji
foreach()
: wyjątekTypeError
zamiast ostrzeżenia - Niedozwolony typ przesunięcia: wyjątek
TypeError
zamiast ostrzeżenia - Niedozwolony typ przesunięcia w isset lub empty: wyjątek
TypeError
zamiast ostrzeżenia - Nieprawidłowy typ przesunięcia w unset: wyjątek
TypeError
zamiast ostrzeżenia - Konwersja tablicy na ciąg: ostrzeżenie zamiast powiadomienia
- Identyfikator zasobu ID#%d używany jako przesunięcie, rzutowanie na liczbę całkowitą (%d): ostrzeżenie zamiast powiadomienia
- Wystąpiło rzutowanie przesunięcia ciągu: ostrzeżenie zamiast powiadomienia
- Przesunięcie niezainicjowanego ciągu %d: ostrzeżenie zamiast powiadomienia
- Nie można przypisać pustego ciągu do przesunięcia ciągu: wyjątek
Error
zamiast ostrzeżenia - Dostarczony zasób nie jest prawidłowym zasobem strumienia: wyjątek
TypeError
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ś display_errors=Off
na serwerach produkcyjnych!
Domyślny poziom raportowania błędów
Teraz jest 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 dyskretnie ignorowane, chociaż prawdopodobnie istniały już przed PHP 8.
Domyślny tryb błędu PDO RFC
Z dokumentu RFC: Bieżący domyślny tryb błędu dla PDO jest wyciszony. 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 programista zaimplementuje własną, jawną obsługę błędów.
Ten dokument RFC zmienia domyślny błąd zmieni się na PDO::ERRMODE_EXCEPTION
w PHP 8.
Pierwszeństwo konkatenacji RFC
Chociaż jest już przestarzałe w PHP 7.4, ta zmiana została wprowadzona w życie. Jeśli napisałbyś coś takiego:
echo "sum: " . $a + $b;
PHP wcześniej zinterpretowałby to następująco:
echo ("sum: " . $a) + $b;
PHP 8 sprawi, że będzie to interpretowane następująco:
echo "sum: " . ($a + $b);
Bardziej rygorystyczne sprawdzanie typów dla operatorów arytmetycznych i bitowych RFC
Przed PHP 8 można było stosować operatory arytmetyczne lub bitowe na tablicach, zasobach lub obiektach. Nie jest to już możliwe i spowoduje zgłoszenie TypeError
:
[] % [42];
$object + 4;
Nazwy w przestrzeni nazw będące pojedynczym tokenem RFC
PHP używane do interpretacji każdej części przestrzeni nazw (oddzielonej ukośnikiem odwrotnym – backslashem \
) jako sekwencji tokenów. Ten dokument RFC zmienił to zachowanie, co oznacza, że zarezerwowane nazwy mogą być teraz używane w przestrzeniach nazw.
Lepsze ciągi liczbowe RFC
System typów PHP próbuje zrobić wiele inteligentnych rzeczy, gdy napotyka liczby w łańcuchach znaków. Ten dokument RFC sprawia, że to zachowanie jest bardziej spójne i jasne.
Bardziej rozsądny ciąg do porównań liczbowych RFC
To RFC naprawia bardzo dziwny przypadek w PHP, w którym 0 == "foo"
daje w wyniku true
. Istnieją inne skrajne przypadki, takie jak ten, a niniejszy dokument RFC je rozwiązuje.
Zmiana sygnatury metody Reflection
Zmieniono trzy sygnatury metod klas Reflection
:
ReflectionClass::newInstance($args);
ReflectionFunction::invoke($args);
ReflectionMethod::invoke($object, $args);
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 podpisy:
ReflectionClass::newInstance($arg = null, ...$args);
ReflectionFunction::invoke($arg = null, ...$args);
ReflectionMethod::invoke($object, $arg = null, ...$args);
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 sortowania na stabilne sortowanie.
Błąd krytyczny dla niekompatybilnych podpisów metod RFC
Z dokumentu RFC: Inheritance errors z powodu niezgodnych sygnatur metod obecnie generują błąd krytyczny lub ostrzeżenie, w zależności od przyczyny błędu i hierarchii dziedziczenia.
Zobacz także:
źródło: PHP.net | Stitcher.io (1)
ciekawe… fajnie