PHP 8.1: Основни нововъведения
Път за обновяване от PHP 8.0.x: нови езикови възможности, по-строг runtime и чеклисти за staging.
Съдържание
- Enums
- Readonly properties
- First-class callable syntax
- Fibers
- Intersection types
- never return type
- new in initializers
- Синтактични и езикови подобрения (0o, unpack, named args след unpack)
- Обратно несъвместими промени (бележки за миграция)
- Deprecated (какво е добре да оправите рано)
- Extensions: важни промени
Ако 8.0 нулира платформата, 8.1 я напълва с ежедневни абстракции: Enums и readonly, Fibers за библиотеки, intersection/never за типове. Триенето идва от по-строг runtime: презапис на $GLOBALS, MySQLi по подразбиране с изключения и deprecations, които в следващите 8.x стават hard errors.
Enums
Enums са първокласен, type-safe начин да представите “затворен” набор от стойности.
- Backed enums пазят скаларна стойност (
string|int), удобна за съхранение/пренасяне през API. - Pure enums са само идентичност — отлични за домейн състояния и изчерпателна обработка.
enum Status: string
{
case Draft = 'draft';
case Published = 'published';
case Archived = 'archived';
}
function canEdit(Status $status): bool
{
return $status !== Status::Archived;
}
$status = Status::from('draft'); // Status::Draft
$value = $status->value; // 'draft'
Практични насоки
- Използвайте enums вместо “string флагове” (
'draft'|'published') в сигнатури и DTO. - За БД и публични API често са по-удобни backed enums; за вътрешни workflow състояния — pure enums.
- Комбинирайте с
matchза изчерпателна обработка:
function label(Status $status): string
{
return match ($status) {
Status::Draft => 'Draft',
Status::Published => 'Published',
Status::Archived => 'Archived',
};
}
Readonly properties
Readonly properties могат да бъдат присвоени само веднъж — най-често в конструктора. Това е голям плюс за immutable DTO, value objects и по-сигурни домейн модели.
final class UserProfile
{
public function __construct(
public readonly int $id,
public readonly string $email,
) {}
}
Какво променя архитектурно
- Насърчава обекти “конструираш напълно — после не мутираш”.
- Намалява нуждата от private + getter-и за DTO-подобни типове.
- Работи чудесно с constructor property promotion.
First-class callable syntax
PHP 8.1 добавя удобен синтаксис за създаване на closures от callables:
function normalize(string $s): string
{
return strtolower(trim($s));
}
$fn = normalize(...); // Closure
$out = array_map($fn, [' A ', 'B ']); // ['a', 'b']
Еквивалентно е на Closure::fromCallable('normalize'), но е по-кратко и се чете по-добре в pipeline-и.
Fibers
Fibers са ниско-нивов примитив за кооперативна конкурентност. Те сами по себе си не правят кода async, но позволяват на библиотеки/фреймворкове да изграждат async runtime-и, scheduler-и и structured concurrency.
$fiber = new Fiber(function (): void {
$value = Fiber::suspend('paused');
echo "resumed with: {$value}\n";
});
echo $fiber->start() . "\n"; // paused
$fiber->resume('payload'); // resumed with: payload
Кога има значение
- Ако използвате async framework/event loop: Fibers могат да улеснят интеграциите.
- За класически request/response приложения Fibers са предимно “инфраструктура за библиотеки”.
Intersection types
Intersection types означават “трябва да удовлетворява всички тези интерфейси/класове едновременно”.
function export(iterable&Countable $items): array
{
if (count($items) === 0) {
return [];
}
return iterator_to_array($items, preserve_keys: true);
}
Важно: intersection types не могат да се комбинират с union types.
never return type
Return type never означава, че функцията никога не връща управление: тя винаги хвърля exception или извиква exit.
function fail(string $message): never
{
throw new RuntimeException($message);
}
Това подобрява статичния анализ и прави control flow по-ясен.
new in initializers
PHP 8.1 позволява new изрази на повече места: defaults на параметри, static variables, инициализатори на константи и аргументи на атрибути.
final class Clock
{
public function now(): DateTimeImmutable
{
return new DateTimeImmutable('now');
}
}
function handler(Clock $clock = new Clock()): DateTimeImmutable
{
return $clock->now();
}
Това премахва доста “factory boilerplate” в простите случаи. (В DI контейнер внимавайте с lifetime-а на услугите.)
Синтактични и езикови подобрения (0o, unpack, named args след unpack)
Octal integer literal prefix: 0o / 0O
$mask = 0o755;
Array unpacking with string keys
$a = [1, 'a' => 'b'];
$b = [...$a, 'c' => 'd']; // [1, 'a' => 'b', 'c' => 'd']
Named argument after argument unpacking
foo(...$args, named: $arg);
full_path for file uploads
В $_FILES вече има ключ full_path (основно за webkitdirectory uploads).
Практични рецепти
Backed enum от ненадежден вход (tryFrom)
$status = Status::tryFrom($row['status']) ?? Status::Draft;
Пайплайни с first-class callable
$normalize = static fn(string $s): string => strtolower(trim($s));
$mapper = $normalize(...);
$lines = array_map($mapper, $raw);
Обратно несъвместими промени (бележки за миграция)
Този раздел е прагматичен: фокусира се върху неща, които най-често реално чупят ъпгрейда.
PHP core / language
- Ограничения за запис в $GLOBALS: запис към “целия”
$GLOBALSвече не е позволен (напр.array_pop($GLOBALS)дава error). Достъпът до елементи$GLOBALS['x']продължава да работи. - static variables в наследени методи: наследените (не override-нати) методи вече споделят static variables с родителския метод.
- Optional преди required параметри: optional параметри, декларирани преди required, се третират като required; в PHP 8.1 това може да доведе до
ArgumentCountErrorпри извикване (дори с named arguments). - Return type compatibility с internal classes: override на вътрешни методи без съвместим return type води до deprecation; за cross-version използвайте
#[ReturnTypeWillChange]. - Нови ключови думи:
readonlyвече е keyword (но все още може да се използва като име на функция).neverвече е reserved word (не може да се използва за имена на class/interface/trait и е забранено в namespaces).
Resource → object migration (още)
Няколко разширения мигрират ресурси към обекти (проверки с is_resource() заменете с проверки за false или с object types):
- FileInfo:
finfoobjects вместоfileinforesources. - FTP:
FTP\Connectionobjects. - IMAP:
IMAP\Connectionobjects. - LDAP:
LDAP\Connection,LDAP\Result,LDAP\ResultEntryobjects. - PgSQL:
PgSql\Connection,PgSql\Result,PgSql\Lobobjects. - PSpell:
PSpell\DictionaryиPSpell\Configobjects.
PDO / MySQLi behavior changes
- MySQLi: default error reporting mode се промени от “silent” към “exceptions”. За да върнете старото поведение:
mysqli_report(MYSQLI_REPORT_OFF); - PDO: промени в
PDO::ATTR_STRINGIFY_FETCHESза bool; SQLite/MySQL драйверите по-консистентно връщат ints/floats като нативни PHP типове.
Standard library behavior changes
version_compare()вече не приема недокументирани съкращения за оператори.- HTML escaping функциите по подразбиране използват
ENT_QUOTES | ENT_SUBSTITUTE(кавычките се escape-ват; невалиден UTF-8 се заменя).
Deprecated (какво е добре да оправите рано)
Deprecations в 8.1 са “бъдещи грешки”. Ако ги оправите сега, следващите ъпгрейди към PHP 8.2+ ще са много по-лесни.
Core deprecations
- Подаване на
nullкъм non-nullable параметри на built-in функции е deprecated. - Неявни lossy float → int конверсии са deprecated (array keys, int type declarations в coercive mode, int оператори).
- Извикване на static елемент върху trait е deprecated.
- Autovivification от
falseе deprecated ($x = false; $x[] = 1;).
Notable extension deprecations
- Date:
strftime()/gmstrftime()иstrptime()са deprecated (предпочитайтеdate()/date_parse_from_format()/IntlDateFormatter). - Filter:
FILTER_SANITIZE_STRINGиFILTER_SANITIZE_STRIPPEDса deprecated. - Hash:
mhash*()са deprecated (използвайтеhash_*()). - PDO:
PDO::FETCH_SERIALIZEе deprecated.
Extensions: важни промени
Тук са събрани “добре е да се знае” промени, които не винаги чупят кода директно, но влияят на поведение и операции.
- Reflection:
ReflectionProperty::setAccessible()/ReflectionMethod::setAccessible()вече нямат ефект (всичко е “достъпно” през Reflection). - Phar: SHA256 е default за подписи; поддържат се OpenSSL_SHA256/OpenSSL_SHA512 подписи.
- OpenSSL: OpenSSL 3.0 е поддържан; наличността на cipher-и и валидирането на параметри са по-строги.
- CLI:
php -aбез readline вече дава error. - PHPDBG: remote функционалността е премахната.