<? phpukraine ЕКОСИСТЕМА
⌕Пошук по платформі
PHP · ЩО НОВОГО

Що нового в PHP 8.1

  1. 01Enum: закритий перелік значень як окремий тип, з методами, cases() і from().
  2. 02Readonly-властивості: значення записується один раз, далі лише читання.
  3. 03Fibers, тип never, first-class callable strlen(...) і new у значеннях параметрів за замовчуванням.
СТАТУС Не підтримується
Реліз
25 листопада 2021
Останній патч
8.1.34
Активна підтримка до
25.11.2023
Безпека до
31.12.2025
НОВІ МОЖЛИВОСТІ · 5

Нові можливості

1.1 · RFC

Enum

Enum задає фіксований набір варіантів, і параметр типу Status вже не прийме довільний рядок. Backed enum привʼязує кожен case до int чи string для бази й API, from() і tryFrom() перетворюють значення назад, а cases() віддає всі варіанти. Enum може мати методи, константи й реалізовувати інтерфейси.

+ PHP 8.1
enum Status: string
{
    case Draft = 'draft';
    case Published = 'published';
}

function publish(Status $status): void { /* лише Status */ }
− PHP 8.0
final class Status
{
    public const DRAFT = 'draft';
    public const PUBLISHED = 'published';
}

function publish(string $status): void { /* будь-який рядок */ }
1.2 · RFC

Readonly-властивості

Readonly-властивість ініціалізується один раз зсередини класу, а спроба змінити її пізніше кидає Error. Для value objects і DTO це прибирає пару «приватне поле плюс гетер». Працює лише з типізованими властивостями й добре поєднується з промоцією в конструкторі.

+ PHP 8.1
public function __construct(
    public readonly int $amount,
) {}
− PHP 8.0
private int $amount;

public function amount(): int
{
    return $this->amount;
}
1.3 · RFC

Fibers

Fiber виконує функцію з власним стеком викликів: її можна зупинити будь-де через Fiber::suspend() і продовжити через resume(). Код при цьому лишається однопотоковим. На Fibers побудовані AMPHP 3 і react/async, тож асинхронний код пишеться послідовно, без ланцюжків then().

+ PHP 8.1
// await() з react/async працює на Fiber
$response = await($client->get($url));
echo $response->getStatusCode();
− PHP 8.0
$client->get($url)->then(function ($response) {
    echo $response->getStatusCode();
});
1.4 · RFC

Тип never

never позначає функцію, що завжди кидає виняток, викликає exit() або крутиться вічно. PHPStan та IDE знають, що код після такого виклику недосяжний. Якщо функція все ж дійшла до кінця, PHP кидає TypeError.

+ PHP 8.1
function abort(int $code): never
{
    throw new HttpException($code);
}
− PHP 8.0
/** @return never */
function abort(int $code): void
{
    throw new HttpException($code);
}
1.5 · RFC

Типи-перетини

Тип Countable&Traversable приймає лише обʼєкт, який реалізує обидва інтерфейси. Раніше таку вимогу писали в PHPDoc або перевіряли instanceof усередині функції. У 8.1 перетини складаються тільки з класів та інтерфейсів і не поєднуються з | чи null, це дозволили DNF-типи в 8.2.

+ PHP 8.1
function report(Countable&Traversable $items): string
− PHP 8.0
/** @param Countable&Traversable $items */
function report($items): string
СИНТАКСИС · 5

Синтаксис

2.1 · RFC

First-class callable

Виклик із трьома крапками замість аргументів повертає Closure на функцію чи метод. Він замінює рядки на кшталт 'strlen' і масиви [$this, 'method']: IDE бачить звичайне посилання, перейменування методу його не зламає, а Closure від приватного методу можна віддати назовні.

+ PHP 8.1
array_map($slug->make(...), $titles);
$length = strlen(...);
− PHP 8.0
array_map([$slug, 'make'], $titles);
$length = 'strlen';
2.2 · RFC

new у значеннях за замовчуванням

new можна писати у значенні параметра за замовчуванням, в аргументах атрибутів, статичних змінних і глобальних константах. Запасна реалізація залежності вже не потребує ?Logger $logger = null і рядка з ?? у конструкторі. У властивостях і константах класу new і далі заборонений.

+ PHP 8.1
public function __construct(
    private Logger $logger = new NullLogger(),
) {}
− PHP 8.0
public function __construct(?Logger $logger = null)
{
    $this->logger = $logger ?? new NullLogger();
}
2.3 · RFC

final для констант класу

Константу з final дочірній клас не перевизначить, PHP зупиниться з фатальною помилкою. Константи інтерфейсів, навпаки, тепер можна перевизначати в класах, що їх реалізують, якщо вони не final. Для перевірки зʼявився ReflectionClassConstant::isFinal().

+ PHP 8.1
class Http
{
    final public const VERSION = '1.1';
}
− PHP 8.0
class Http
{
    /** не перевизначати в нащадках */
    public const VERSION = '1.1';
}
2.4 · RFC

Префікс 0o для вісімкових чисел

Вісімкове число можна записати з явним префіксом 0o, як шістнадцяткове з 0x і двійкове з 0b. Старий запис 0755 працює, але 0o755 не сплутаєш з десятковим 755 під час читання коду.

+ PHP 8.1
chmod($path, 0o755);
− PHP 8.0
chmod($path, 0755);
2.5 · RFC

Розпакування масивів з рядковими ключами

Оператор ... у літералі масиву раніше приймав лише числові ключі, а на рядкових кидав Error. Тепер рядкові ключі зливаються за правилами array_merge(): пізніше значення перекриває попереднє, числові ключі перенумеровуються.

+ PHP 8.1
$config = [...$defaults, ...$env];
− PHP 8.0
$config = array_merge($defaults, $env);
ФУНКЦІЇ · 4

Нові функції

3.1 · RFC

array_is_list()

Функція перевіряє, що масив є списком: ключі 0, 1, 2 і далі без дірок. Від цього залежить json_encode(): список стає JSON-масивом, а масив після array_filter() з пропуском у ключах перетворюється на обʼєкт.

+ PHP 8.1
$isList = array_is_list($items);
− PHP 8.0
$isList = array_values($items) === $items;
3.2 · НОВЕ

xxHash і MurmurHash3

hash() отримав алгоритми xxh32, xxh64, xxh3, xxh128 і murmur3a, murmur3c, murmur3f. Вони значно швидші за md5() і sha1() там, де криптостійкість не потрібна: ключі кешу, шардинг, порівняння файлів. Новий параметр options передає seed. Для паролів і підписів ці алгоритми не годяться.

+ PHP 8.1
$key = hash('xxh3', $url);
− PHP 8.0
$key = md5($url);
3.3 · RFC

fsync() і fdatasync()

fflush() передає дані операційній системі, але вони ще якийсь час лежать у її кеші. fsync() просить записати їх на носій, fdatasync() робить те саме без метаданих файлу. Це потрібно для журналів, черг і всього, що не має загубитися при збої живлення.

+ PHP 8.1
fwrite($log, $line);
fsync($log);
− PHP 8.0
fwrite($log, $line);
fflush($log);
3.4 · НОВЕ

full_path у $_FILES

Коли форма завантажує теку через input з атрибутом webkitdirectory, браузер передає шлях кожного файлу всередині неї. Раніше PHP лишав у name тільки імʼя, тепер шлях доступний у full_path. Значення приходить від клієнта, тож перед записом на диск його треба перевіряти.

+ PHP 8.1
$_FILES['docs']['full_path'][0];
// q3/finance/report.pdf
− PHP 8.0
$_FILES['docs']['name'][0];
// report.pdf
ПРОДУКТИВНІСТЬ · 1

Продуктивність

4.1 · ДВИГУН

Кеш наслідування

OPcache і раніше зберігав скомпільовані класи, але звʼязування з батьком, інтерфейсами й трейтами виконувалося на кожному запиті заново. Тепер звʼязаний клас теж лежить у спільній памʼяті. Найбільше це відчувають фреймворки з глибокими ієрархіями, налаштовувати нічого не треба.

+ PHP 8.1
opcache.enable=1
; звʼязані класи беруться з кешу
− PHP 8.0
opcache.enable=1
; класи звʼязуються з батьками на кожному запиті
БЕЗПЕКА · 1

Безпека

5.1 · ЗМІНА

htmlspecialchars() екранує одинарні лапки

Прапорці за замовчуванням змінились з ENT_COMPAT на ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, так само в htmlentities() і функціях декодування. Значення в атрибуті з одинарними лапками більше не вирветься назовні, а некоректний UTF-8 замінюється символом �, тоді як раніше весь рядок ставав порожнім.

+ PHP 8.1
htmlspecialchars($value);
− PHP 8.0
htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE);
DEPRECATED

Застаріло

Ще працює, але дає попередження і зникне в одній із наступних версій.

null у параметрах вбудованих функційstrlen(null) і подібні виклики. Перевіряйте на null або приводьте тип явно.
Вбудовані методи без типу поверненняМетод з ArrayAccess, Countable чи Iterator має оголосити сумісний тип або #[\ReturnTypeWillChange].
Serializable без __serialize()Реалізуйте __serialize() і __unserialize(), старий інтерфейс лишайте лише для сумісності.
Неявне float у int з втратою точностіДробова частина, яку PHP мовчки відкидав у ключах масиву чи операторі %, тепер дає Deprecated.
strftime() і gmstrftime()Залежать від локалі системи. Використовуйте date(), DateTimeInterface::format() або IntlDateFormatter.
FILTER_SANITIZE_STRINGРазом з FILTER_SANITIZE_STRIPPED. Для виводу в HTML беріть htmlspecialchars(), для тексту без тегів strip_tags().
ctype_*() з числамиctype_digit(5) перевіряв символ з кодом 5, а не рядок '5'. Передавайте рядок.
BREAKING

Ламає сумісність

Перевірте це до оновлення: такий код перестане працювати або поводитиметься інакше.

Обмеження $GLOBALSВесь масив тепер лише для читання, $GLOBALS = [] чи посилання на нього не компілюються. Запис $GLOBALS['x'] працює як раніше.
mysqli кидає виняткиРежим помилок за замовчуванням тепер MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT, тож замість false летить mysqli_sql_exception.
PDO повертає числа як int і floatMySQL з емульованими prepared statements і SQLite віддають числа рідними типами, а не рядками. Старе поводження вмикає PDO::ATTR_STRINGIFY_FETCHES.
Ресурси стали обʼєктамиfinfo, FTP, IMAP, LDAP, PgSql і PSpell тепер повертають обʼєкти, тож перевірка is_resource() дає false.
Статичні змінні в успадкованих методахБатьківський і дочірній клас тепер ділять одну static-змінну, якщо метод не перевизначено.

Як оновитися

0 / 6