Witajcie na moim blogu! Cieszę się niezmiernie, że mogę podzielić się z Wami najnowszymi aktualizacjami w fascynującym świecie PHP. Dzisiaj chciałbym poruszyć temat, który jest gorącym punktem dyskusji w społeczności programistów – premiera PHP8.3. To niezwykle ważne wydarzenie, które wywołuje wiele emocji wśród entuzjastów tego języka programowania.
Najnowsza wersja PHP, czyli PHP8.3, właśnie zadebiutowała, przynosząc ze sobą szereg fascynujących nowości i znaczących ulepszeń. Dla każdego programisty to moment pełen oczekiwań i nadziei na jeszcze lepsze narzędzia do tworzenia doskonałych aplikacji.
Niezwykle istotne jest zrozumienie, jakie korzyści niesie za sobą wprowadzenie PHP8.3. Nowe funkcje i usprawnienia mają ogromny potencjał, który może znacząco ułatwić życie każdemu z nas. Chciałbym zaprosić Was do zgłębienia tych zmian razem ze mną.
Pozwólcie mi przedstawić kilka z najbardziej ekscytujących nowości, które wprowadza PHP8.3. Razem zgłębimy ich potencjał i zrozumiemy, jak mogą wpłynąć na naszą pracę jako programistów. Gotowi na fascynującą podróż po najnowszych możliwościach PHP?
Zapraszam do lektury!
Typed class constants [RFC]
Od teraz, stałe klasowe mogą posiadać określone typy danych. Przed wprowadzeniem tej funkcji stałe klasy w PHP nie miały możliwości deklarowania typów danych. Rzućmy okiem na przykład z dokumentacji:
// PHP < 8.3 interface I { // Możemy naiwnie założyć, że stała PHP jest zawsze ciągiem znaków. const PHP = 'PHP 8.2'; } class Foo implements I { // Klasy implementujące mogą zdefiniować go jako tablicę. const PHP = []; }
// PHP 8.3 interface I { const string PHP = 'PHP 8.3'; } class Foo implements I { const string PHP = []; } // Fatal error: Nie można użyć tablicy jako wartości dla stałej klasy // Foo::PHP of type string
Dodanie typów do stałych klasowych jest użyteczne w kontekście zapewnienia, że wartość stałej będzie zawsze odpowiadała określonemu typowi danych. To umożliwia programistom lepszą kontrolę nad danymi, które są przechowywane w stałych klasowych. Może to prowadzić do lepszej czytelności kodu oraz ograniczenia błędów wynikających z niewłaściwego typu danych przypisanego do stałej.
Dynamic class constant fetch [RFC]
Dynamic class constant fetch w PHP8.3 umożliwia dynamiczne pobieranie stałych klasowych. Oznacza to, że można uzyskać dostęp do stałej klasy za pomocą zmiennych lub wyrażeń.
Przed PHP8.3, aby uzyskać dostęp do stałej klasy, konieczne było podanie nazwy stałej bezpośrednio w kodzie. Bez możliwości dynamicznego budowania jej nazwy w trakcie działania programu.
// PHP < 8.3 class Foo { const PHP = 'PHP 8.2'; } $searchableConstant = 'PHP'; var_dump(constant(Foo::class . "::{$searchableConstant}"));
// PHP 8.3 class Foo { const PHP = 'PHP 8.3'; } $searchableConstant = 'PHP'; var_dump(Foo::{$searchableConstant});
Ta funkcjonalność jest przydatna, gdy nazwa stałej klasowej jest obliczana dynamicznie w trakcie wykonywania skryptu. Może to zwiększyć elastyczność i umożliwić bardziej dynamiczne operacje w kodzie. Jednak należy używać tego z umiarem, ponieważ nadmierne stosowanie dynamicznego pobierania stałych klasowych może skomplikować czytelność kodu.
New #[\Override]
attribute [RFC]
Atrybut #[\Override]
w PHP8.3 jest nowym atrybutem, który umożliwia jawnie oznaczenie metody jako przesłaniającą metodę z klasy nadrzędnej. Ten atrybut ma za zadanie zapewnić większą przejrzystość i klarowność w kodzie. Jednocześnie informując czytelnika, że dana metoda jest zamierzonym przesłonięciem metody z klasy nadrzędnej. Zobaczmy różnice przed wersją PHP8.3 i obecnie:
// PHP < 8.3 use PHPUnit\Framework\TestCase; final class MyTest extends TestCase { protected $logFile; protected function setUp(): void { $this->logFile = fopen('/tmp/logfile', 'w'); } protected function taerDown(): void { fclose($this->logFile); unlink('/tmp/logfile'); } } // Plik logów nigdy nie zostanie usunięty, ponieważ // nazwa metody została pomylona (taerDown vs tearDown).
// PHP 8.3 use PHPUnit\Framework\TestCase; final class MyTest extends TestCase { protected $logFile; protected function setUp(): void { $this->logFile = fopen('/tmp/logfile', 'w'); } #[\Override] protected function taerDown(): void { fclose($this->logFile); unlink('/tmp/logfile'); } } // Fatal error: MyTest::taerDown() has #[\Override] attribute, // nie istnieje pasująca metoda nadrzędna
Jest to przydatne zwłaszcza w przypadku dużych projektów z wieloma klasami, gdzie jasne oznaczenie, które metody są przesłonięte, może ułatwić zrozumienie kodu. Jednak warto pamiętać, że atrybut #[\Override]
jest jedynie atrybutem informacyjnym i nie wpływa na działanie samej metody – to nadal programista odpowiada za właściwe przesłanianie metod.
Deep-cloning of readonly properties [RFC]
W najnowszej wersji PHP dodano funkcjonalność głębokiego klonowania (deep-cloning) właściwości tylko do odczytu (readonly properties). To rozszerzenie dotyczy możliwości kopiowania obiektów, szczególnie tych, które zawierają właściwości tylko do odczytu.
Wcześniej, gdy obiekt zawierał właściwości tylko do odczytu (readonly), klonowanie tego obiektu używając funkcji clone
nie zawsze skutkowało głębokim klonowaniem tych właściwości. Było to szczególnie widoczne, gdy obiekt zawierał zagnieżdżone obiekty z właściwościami tylko do odczytu.
W PHP8.3, przy użyciu clone
, obiekty z właściwościami tylko do odczytu są teraz kopiowane w sposób głęboki, co oznacza, że nawet zagnieżdżone obiekty w właściwościach tylko do odczytu są również głęboko klonowane. To zapewnia, że cała struktura danych jest sklonowana, a nie tylko referencje do właściwości tylko do odczytu. Poniżej przykład przed i obecnie:
// PHP < 8.3 class PHP { public string $version = '8.2'; } readonly class Foo { public function __construct( public PHP $php ) {} public function __clone(): void { $this->php = clone $this->php; } } $instance = new Foo(new PHP()); $cloned = clone $instance; // Fatal error: Cannot modify readonly property Foo::$php
// PHP 8.3 class PHP { public string $version = '8.2'; } readonly class Foo { public function __construct( public PHP $php ) {} public function __clone(): void { $this->php = clone $this->php; } } $instance = new Foo(new PHP()); $cloned = clone $instance; $cloned->php->version = '8.3';
i jeszcze prosty przykład, jak działa to głębokie klonowanie w przypadku właściwości tylko do odczytu:
// PHP 8.3 class SomeClass { public readonly array $data; public function __construct(array $data) { $this->data = $data; } } $obj1 = new SomeClass(['a', 'b', 'c']); $obj2 = clone $obj1; $obj2->data[] = 'd'; var_dump($obj1->data); // Wyświetli: array(3) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> string(1) "c" } var_dump($obj2->data); // Wyświetli: array(4) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> string(1) "c" [3]=> string(1) "d" }
W tym przykładzie, mimo że obj2
został sklonowany z obj1
, zmiany dokonane w obj2
nie wpłynęły na obj1
, co świadczy o głębokim klonowaniu właściwości tylko do odczytu ($data
).
New json_validate()
function [RFC] [DOC]
Aby sprawdzić poprawność ciągu JSON przed wersją PHP8.3, trzeba było przekazać go do json_decode()
i sprawdzić, czy wystąpiły błędy i/lub zgłoszone wyjątki (w zależności od podanych flag do funkcji). Korzystając z tego podejścia do sprawdzania poprawności dużych struktur JSON, narażałeś się na ryzyko wyczerpania pamięci przed ustaleniem, czy jest ona poprawna. Dodatkowo może to spowodować przekroczenie limitu pamięci PHP przed faktycznym przetworzeniem struktury. Nowa funkcja jest bardziej wydajna i mniej podatna na błędy.
// PHP < 8.3 function json_validate(string $string): bool { json_decode($string); return json_last_error() === JSON_ERROR_NONE; } var_dump(json_validate('{ "test": { "foo": "bar" } }')); // true
// PHP 8.3 var_dump(json_validate('{ "test": { "foo": "bar" } }')); // true
Podsumowując json_validate()
pozwala sprawdzić, czy ciąg znaków jest poprawny pod względem składni JSON, a jednocześnie jest bardziej wydajny niż json_decode()
.
New Randomizer::getBytesFromString()
method [RFC] [DOC]
Rozszerzenie Random, które zostało dodane w PHP8.2, zostało rozszerzone o nową metodę generowania losowych ciągów składających się tylko z określonych bajtów. Metoda ta pozwala programiście na łatwe generowanie losowych identyfikatorów, takich jak nazwy domen i ciągi liczbowe o dowolnej długości.
// PHP < 8.3 // Ta funkcja musi zostać zaimplementowana ręcznie. function getBytesFromString(string $string, int $length) { $stringLength = strlen($string); $result = ''; for ($i = 0; $i < $length; $i++) { // random_int nie jest seedowalny do testów, ale jest bezpieczny. $result .= $string[random_int(0, $stringLength - 1)]); } return $result; } $randomDomain = sprintf( "%s.example.com", getBytesFromString( 'abcdefghijklmnopqrstuvwxyz0123456789', 16, ), ); echo $randomDomain;
// PHP 8.3 // Do seedowania można przekazać silnik \Random\Engine, // domyślnie jest to bezpieczny silnik. $randomizer = new \Random\Randomizer(); $randomDomain = sprintf( "%s.example.com", $randomizer->getBytesFromString( 'abcdefghijklmnopqrstuvwxyz0123456789', 16, ), ); echo $randomDomain;
New Randomizer::getFloat()
and Randomizer::nextFloat()
methods [RFC] [DOC]
Ze względu na ograniczoną precyzję i niejawne zaokrąglanie liczb zmiennoprzecinkowych, wygenerowanie bezstronnej liczby zmiennoprzecinkowej leżącej w określonym przedziale jest nietrywialne, a powszechnie stosowane rozwiązania użytkownika mogą generować stronnicze wyniki lub liczby spoza żądanego zakresu.
Randomizer został również rozszerzony o dwie metody generowania losowych liczb zmiennoprzecinkowych w sposób bezstronny. Metoda Randomizer::getFloat() wykorzystuje algorytm γ-section, który został opublikowany w artykule Drawing Random Floating-Point Numbers from an Interval. Frédéric Goualard, ACM Trans. Model. Comput. Simul., 32:3, 2022.
// PHP < 8.3 // Zwraca losową liczbę zmiennoprzecinkową pomiędzy $min i $max, obie z uwzględnieniem. function getFloat(float $min, float $max) { // Ten algorytm jest stronniczy dla określonych danych wejściowych i może // zwracać wartości spoza podanego zakresu. Jest to niemożliwe // do obejścia w środowisku użytkownika. $offset = random_int(0, PHP_INT_MAX) / PHP_INT_MAX; return $offset * ($max - $min) + $min; } $temperature = getFloat(-89.2, 56.7); $chanceForTrue = 0.1; // getFloat(0, 1) może zwrócić górną granicę, tj. 1, // wprowadzając niewielkie odchylenie. $myBoolean = getFloat(0, 1) < $chanceForTrue;
// PHP 8.3 $randomizer = new \Random\Randomizer(); $temperature = $randomizer->getFloat( -89.2, 56.7, \Random\IntervalBoundary::ClosedClosed, ); $chanceForTrue = 0.1; // Randomizer::nextFloat() jest równoważne funkcji // Randomizer::getFloat(0, 1, \Random\IntervalBoundary::ClosedOpen). // Górna granica, tj. 1, nie zostanie zwrócona. $myBoolean = $randomizer->nextFloat() < $chanceForTrue;
Pozostałe zmiany w PHP8.3
Nowe klasy, interface’y i funkcje
- Nowe metody:
DOMElement::getAttributeNames()
,DOMElement::insertAdjacentElement()
,DOMElement::insertAdjacentText()
,DOMElement::toggleAttribute()
,DOMNode::contains()
,DOMNode::getRootNode()
,DOMNode::isEqualNode()
,DOMNameSpaceNode::contains()
iDOMParentNode::replaceChildren()
. - Nowe metody:
IntlCalendar::setDate()
,IntlCalendar::setDateTime()
,IntlGregorianCalendar::createFromDate()
iIntlGregorianCalendar::createFromDateTime()
. - Nowe funkcje
ldap_connect_wallet()
ildap_exop_sync()
. - Nowa funkcja
mb_str_pad()
. - Nowe funkcje
posix_sysconf()
,posix_pathconf()
,posix_fpathconf()
iposix_eaccess()
. - Nowa metoda
ReflectionMethod::createFromMethodName()
. - Nowa funkcja
socket_atmark()
. - Nowe funkcje
str_increment()
,str_decrement()
istream_context_set_options()
. - Nowa metoda
ZipArchive::getArchiveFlag()
. - Obsługa generowania kluczy EC z niestandardowymi parametrami EC w rozszerzeniu OpenSSL.
- Nowe ustawienie INI
zend.max_allowed_stack_size
do ustawiania maksymalnego dozwolonego rozmiaru stosu.
Deprecations i przerwy kompatybilności wstecznej
- Bardziej odpowiednie wyjątki daty/czasu.
- Przypisanie ujemnego indeksu n do pustej tablicy spowoduje teraz, że następny indeks będzie wynosił n + 1 zamiast 0.
- Zmiany w funkcji
range()
. - Zmiany w ponownej deklaracji właściwości statycznych w traits.
- Stała
U_MULTIPLE_DECIMAL_SEPERATORS
została wycofana na rzeczU_MULTIPLE_DECIMAL_SEPARATORS
. - Wariant
MT_RAND_PHP
Mt19937 jest przestarzały. ReflectionClass::getStaticProperties()
nie ma już wartości null.- Ustawienia INI
assert.active
,assert.bail
,assert.callback
,assert.exception
iassert.warning
zostały przestarzałe. - Wywoływanie funkcji
get_class()
iget_parent_class()
bez argumentów jest przestarzałe.
PHP8.3 to kolejny krok naprzód w rozwoju tego popularnego języka programowania, przynosząc więcej narzędzi do pracy i ulepszeń, które usprawnią nasze aplikacje. Cieszę się, że mogę eksplorować te nowości i zobaczyć, jak wpłyną na rozwój naszych projektów! Zobacz więcej moich wpisów w tematyce PHP 🙂
Nikt jeszcze nie komentował. Bądź pierwszy!