За разлика от PHP 8.5, която донесе големи езикови промени като |>, URI extension и clone with, PHP 8.6 изглежда е по-скоро еволюционно издание с множество подобрения в езика, типовата система, стандартните функции и производителността.
По-интересните нововъведения в PHP 8.6
| Новост | Какво дава |
|---|---|
| Подобрения при типовете | По-строго и последователно поведение на типовете |
| Подобрения на attributes | Повече възможности за работа с метаданни |
| Подобрения при generics-подобни конструкции | По-добра работа на статичните анализатори |
| Нови/подобрени функции | Допълнителни функции в стандартната библиотека |
| Подобрения на DOM | По-добра работа с HTML/XML |
| Подобрения на Date/Time | Допълнителни възможности и корекции |
| Подобрения на PHP engine | Оптимизации на изпълнението |
| Подобрения на JIT | Оптимизации за определени натоварвания |
| Подобрения на Fibers | По-стабилна работа с асинхронни/кооперативни конструкции |
| Подобрения на OpenSSL/cryptography | По-добра съвместимост със съвременни криптографски библиотеки |
Важно е обаче да не се смесват RFC предложенията за PHP 8.6 с вече приетите промени. Тъй като версията още е Beta, окончателният списък трябва да се гледа в NEWS и UPGRADING на самия release.
PHP 8.6 — пълен практически преглед
1. clamp() — нова стандартна функция
Една от най-практичните нови функции.
clamp() гарантира, че дадена стойност е в определен диапазон.
Преди
$value = max(0, min(100, $value));
или:
$value = $value < 0 ? 0 : ($value > 100 ? 100 : $value);
PHP 8.6
$value = clamp($value, 0, 100);
Примери:
clamp(50, 0, 100); // 50clamp(-10, 0, 100); // 0clamp(150, 0, 100); // 100
Функцията проверява и невалидни граници и има дефинирано поведение при NAN. RFC-ът вече е имплементиран в PHP 8.6.
Практическа употреба:
$discount = clamp($discount, 0, 50);$quantity = clamp($quantity, 1, 100);$rating = clamp($rating, 1, 5);
2. #[\Override] вече работи и върху class constants
Това е логично продължение на #[Override].
В PHP 8.3 атрибутът беше добавен за методи, а в PHP 8.5 — за properties. PHP 8.6 го разширява и към class constants.
Преди
class Base{ public const VERSION = 1;}class Child extends Base{ public const VERSION = 2;}
От кода не е очевидно дали:
VERSION
умишлено override-ва родителската константа или просто има същото име.
PHP 8.6
class Base{ public const VERSION = 1;}class Child extends Base{ #[\Override] public const VERSION = 2;}
Ако няма какво да бъде override-нато:
class Child{ #[\Override] public const VERSION = 2;}
PHP ще генерира грешка.
Това е особено полезно за големи codebase-и и framework-и.
3. ReflectionProperty isReadable() и isWritable()
PHP 8.6 добавя два много полезни метода:
ReflectionProperty::isReadable()
ReflectionProperty::isWritable()
Те решават проблем, който стана по-сложен след въвеждането на readonly properties и asymmetric visibility в PHP 8.4.
Преди
Трябваше да анализирате комбинация от:
$property->isPublic();
$property->isPrivate();
$property->isProtected();
$property->isReadOnly();
а при asymmetric visibility логиката става още по-сложна.
PHP 8.6
$reflection = new ReflectionClass(User::class);$property = $reflection->getProperty('email');if ($property->isReadable()) { // може да бъде прочетено}if ($property->isWritable()) { // може да бъде записано}
Това е особено полезно за:
- ORM;
- serializer-и;
- dependency injection;
- form libraries;
- API mapper-и;
- автоматично генериране на документация.
4. __debugInfo() вече е позволен в enum
Преди enum не можеше да дефинира __debugInfo().
PHP 8.6 премахва това ограничение. RFC-ът е имплементиран.
Преди
enum Status: string{ case ACTIVE = 'active'; public function __debugInfo(): array { return [ 'status' => $this->value ]; }}
Това не беше позволено.
PHP 8.6
enum Status: string{ case ACTIVE = 'active'; public function __debugInfo(): array { return [ 'status' => $this->value ]; }}
Сега:
var_dump(Status::ACTIVE);
може да предостави контролирано debug представяне.
5. Оптимизация на closures
Това е промяна, която няма да променя кода, но може да подобри производителността.
RFC-ът въвежда две оптимизации.
5.1. PHP може автоматично да направи closure-а static
Имаме:
class UserService{ public function getNames(array $users): array { return array_map( function ($user) { return $user['name']; }, $users ); }}
Closure-ът не използва $this.
PHP 8.6 може вътрешно да го третира като static.
Еквивалентът концептуално е:
static function ($user) { return $user['name'];}
Това позволява оптимизация на closure-а.
5.2. Stateless closures могат да бъдат кеширани
Например:
array_map( static fn($x) => $x * 2, $numbers);
Closure-ите, които:
- са
static; - не capture-ват променливи;
- нямат static variables;
могат да бъдат кеширани между употребите.
Това е особено интересно при код, който генерира много closures.
6. По-сигурни default настройки за sessions
Това е една от по-важните промени за production приложения.
RFC-ът за secure session defaults променя няколко настройки по подразбиране.
session.use_strict_mode
Преди
session.use_strict_mode=0
PHP 8.6
session.use_strict_mode=1
Това предотвратява приемането на произволни session IDs, предоставени от клиента.
session.cookie_httponly
Session cookie вече трябва да бъде защитена срещу достъп през JavaScript.
Концептуално:
session.cookie_httponly=1
Така:
document.cookie
не може да прочете session cookie.
session.cookie_samesite
Целта е по-сигурно поведение при cross-site заявки.
Това е значимо за приложения с:
- login;
- административни панели;
- cookies;
- CSRF защита;
- payment системи.
За ново PHP приложение това означава по-добра сигурност без да трябва изрично да се конфигурира всяка настройка от нулата.
7. mb_ereg*() / mbregex са deprecated
Това е важно при стари PHP приложения.
Oniguruma, библиотеката, използвана от PHP за mbregex, вече не се поддържа upstream.
Затова PHP 8.6 започва процеса:
PHP 8.6 → deprecated
PHP 9.0 → removal
RFC-ът е имплементиран.
Засегнати са например:
mb_ereg(), mb_ereg_match(), mb_ereg_replace(), mb_ereg_replace_callback(), mb_ereg_search(), mb_ereg_search_getpos(), mb_ereg_search_getregs(), mb_ereg_search_init(), mb_ereg_search_pos(), mb_ereg_search_regs(), mb_ereg_search_setpos(), mb_eregi(), mb_eregi_replace(), mb_regex_encoding(), mb_regex_set_options(), mb_split()
Преди
$result = mb_ereg_replace( '[0-9]+', '', $text);
PHP 8.6
Получавате deprecation warning.
В много случаи трябва да преминете към PCRE:
$result = preg_replace( '/[0-9]+/u', '', $text);
Това е едно от нещата, които трябва да се проверят първо при миграция на стар PHP проект към 8.6.
8. Ограничаване на прекалено много stream filters
PHP 8.6 въвежда защита срещу злоупотреба с голям брой stream filters.
При използване на повече от 16 filters се предвижда deprecation warning. RFC-ът е насочен към защита от атаки чрез filter chains.
Потенциално проблемен стар код
$stream = fopen($file, 'r');for ($i = 0; $i < 100; $i++) { stream_filter_append( $stream, 'convert.base64-decode' );}
PHP 8.6 започва да ограничава такива конструкции.
Ако реално имате нужда от повече filters, RFC-ът предвижда настройка:
filter.max_filter_count
Това е предимно security hardening и вероятно няма да засегне нормалните приложения.
9. По-безопасни persistent MySQL connections
Това е особено интересно за PHP + MySQL приложения.
RFC за минималните поддържани версии на PHP 8.6 предвижда използване на:
COM_RESET_CONNECTION
при persistent connections.
Минималните версии, предложени за тази функционалност, са:
MySQL 5.7.3+MariaDB 10.2.4+
Целта е persistent connection да бъде върната в чисто състояние между заявките.
Това е важно, защото при persistent connection не искате:
Request A ↓connection state ↓Request B
да наследява неочаквано състояние от предишната заявка.