• База знань
  • /
  • Блог
  • /
  • Wiki
  • /
  • ONLINE CHAT
+380 (44) 364 05 71

Стаття також доступна російською (перейти до перегляду).

Що нового у оновленій версії PHP

Вступ

Чергова версія РHP 8.2 виявилася досить кардинальною у багатьох аспектах. Внесені зміни торкнулися не тільки ядра РHP та системи типів, а й методів роботи з багатьма сторонніми пакетами. Розглянемо ці зміни більш детально.

Система типів

У РHP використовується номінальна система типів із сильним поведінковим зв'язком між підтипами. Вона підтримує різновиди базових типів, котрі використовуються для створення більш складних складових або комплексних типів. Реалізація цієї можливості, тобто, створення комплексних типів та побудова системи чіткої типізації йшла поступово від версії до версії. Але найбільш досконалою вона стала із виходом версії 8.2. Перерахуємо зміни, які відбулися у системі типів:

  • Поява нового типу DNF, завдяки чому стало можливим комбінувати типи, створені за допомогою операцій об'єднання та перетину;
  • Додані нові логічні типи false, true та null.

Розглянемо більш детально внесені зміни.

Тип DNF

Починаючи з версії 8.0, з'явилася можливість об'єднання типів. Це реалізується шляхом оголошення більш ніж одного типу для аргументів, типів, що повертаються та властивостей класу. Для об'єднання використовується символ «|». Наприклад, стало можливим створити наступний клас:

class Example {
    private int|float $fee;
    public function squareAndAdd(float|int $tan): int|float {
        return $tan ** 5 + $fee;
    }
}

Інтерпретатор слідкує за тим, щоб параметри функції, типи, що повертаються та властивості класу належали одному із оголошених типів.

Із версії 8.1 стало можливим використання типу перетину для класів та інтерфейсів. Він приймає значення, котрі задовольняють кільком оголошенням типу класу. Окремі типи, котрі утворюють тип перетину з'єднуються між собою символом «&». Наприклад, завдяки цьому типу з'явилася можливість перевіряти типи об'єктів класу для реалізації інтерфейсів Iterator і Countable:

function count_iterate(Iterator&\Countable $value) {
    foreach($value as $val) {}
    count($value);
}

До версії 8.2 недоліком і, відповідно, недосконалістю системи типів було те, що неможливо було скомбінувати два комплексних типи – тип об'єднання та тип перетину. Тепер це стало можливим. Достатньо лише оголосити тип шляхом об'єднання типів перетину та об'єднання. При цьому форма об'єднання вказаних типів повинна відповідати формі DNF (Disjunctive Normal Form), у котрій функція має вигляд диз'юнкції кількох простих кон'юнктів. Лише в цьому випадку парсер не буде видавати повідомлення про помилку. Тому утворений таким чином комплексний тип отримав назву тип DNF. Наведемо приклади правильних типів, записаних у формі DNF:

  • D|E|F
  • D|E|(F&G)
  • (D&E&F)|null

Використання типів DNF дозволяє оголошувати точні та виразні типи параметрів, повертаємих значень і властивостей, що, вочевидь, сприяє покращенню системи типів. Одним із найбільш розповсюджених варіантів використання є оголошення типу, котрий приймає тип перетину або null:

function respond(): (JSONResponse&SuccessResponse)|HTMLResponse|string {
}

Тут функція відповіді оголошує тип, що повертається як тип перетину JSONResponse&SuccessResponse, або HTMLResponse чи строку.

При розширенні класу або реалізації інтерфейсу типи DNF повинні відповідати наступним принципам:

  • Типи параметрів повинні бути незмінними;
  • Дозволена коваріація типів, що повертаються;
  • Дозволена контрадисперсія типу параметру, що означає можливість використання додаткових кон'юнкцій при оголошенні параметру підкласу.

Типи null, false і true

До версії 8.2 можливо було використання null та false лише як частини об'єднаного типу, але заборонялось їх використання у якості автономних типів. Нижче наведені приклади того, як можна було використовувати null та false:

function faa(): string|null {}
function strpos(): int|false {}

Тут null та false являються частинами об'єднаного типу, тому їх використання правомірно. Але, спроба використати їх у якості автономних типів призводить до фатальної помилки часу компіляції:

function faa(): null {}
function tan(): false {}
Fatal error: Null can not be used as a standalone type in ... on line ...
Fatal error: False can not be used as a standalone type ......

Із версії 8.2 дозволяється їх використання у якості автономних типів, і повідомлення про помилку не з'являється. Нижче наведений один із прикладів використання false у якості автономного типу:

class Anonther {

     public function isMeen(): false {
          return false;
      }
  }

Все сказане стосується також і застосування нового типу true, котрий теж можна оголошувати у якості автономного:

public function allTrue(): true { /* ..... */ *}

Поява вказаних типів дає змогу точно оголошувати типи повернення, параметрів та властивостей, що сприяє повноті системи типів РHP та її виразності.

Класи

У нову версію мови РHP внесені дві значні зміни у принципах побудови та використання класів. Це такі зміни:

  • Заборона використання динамічних властивостей;
  • Можливість використання модифікатора readonly для класів.

Відтепер не рекомендується динамічно оголошувати властивості класів. Натомість, рекомендується оголошувати властивості класу при його оголошенні. І краще, якщо це буде з оголошенням типу. Наведемо приклад того, як це використовувалося раніше:

class Ozon {
    public int $oid;
}

$ozon = new Ozon();
$ozon->name = 'saa';

У прикладі динамічно змінюються властивості Ozon: використання $name є застарілим.
У новому варіанті це повинно бути виражено наступним чином:

   class Ozon {
    public int $oid;
    public string $name;

}

$ozon = new Ozon();
$ozon->name = 'saa';

У другому варіанті ми оголосили властивість при оголошенні класу. Тепер це відповідає новим вимогам, що до використання динамічних властивостей класів.

Починаючи з версії 8.1, з'явилася можливість для окремої властивості оголошувати заборону на її зміну після ініціалізації. Це стало можливим зробити за допомогою модифікатора readonly, котрий можна було застосовувати лише до типізованих властивостей. Статичні властивості також неможливо відмітити вказаним модифікатором. Відмічену таким чином властивість можна ініціалізувати лише раз і тільки із області, у котрій вона була оголошена. Приклад використання:

<?php
class test1 {
   public readonly string $prep;
   public function __construct(string $prep) {
       
       $this->prep = $prep;
   }
}

?>

У версії 8.2 було вдосконалено вказану вище можливість «фіксувати» значення властивості за допомогою модифікатора readonly. Тепер це можна зробити для всього класу. Це додасть модифікатор до всіх оголошених властивостей та попередить створення динамічних властивостей, котрі є застарілими і, відповідно, не потрібні. Причому, клас типу readonly може бути розширений лише у випадку, якщо дочірній клас також відноситься до типу readonly. Із урахуванням змін, наведений вище код можна записати наступним чином:

<?php
readonly class test1 {
   public string $prep;
   public function __construct(string $prep) {
       
       $this->prep = $prep;
   }
}
?>

У межах оголошеного за допомогою модифікатора readonly класу заборонено оголошувати статичні або не типізовані властивості, оскільки такі властивості не можуть бути відмічені вказаним модифікатором, як це було і раніше. У іншому випадку, парсером буд видана фатальна помилка, як показано нижче:

<?php
readonly class Fii
{
    public $tan;
}

// Fatal error: Readonly property Fii::$tan must have type
?>

Стандартні функції

PHP 8.2 додає дві корисні стандартні функції, котрі оптимізують роботу додатків:

Функція memory_reset_peak_usage() скидає пікове використання пам'яті, котре повертається за допомогою функції memory_get_peak_usage (). Функція не має параметрів і не повертає ніякого значення після виконання. Це підвищує швидкість роботи додатків, котрі викликаються, якщо це повторюється кілька разів, при цьому вони повинні занотовувати пікове значення пам'яті при кожному своєму виклику. Приклад додатку з використанням функції наведений нижче:

<?php

var_dump(memory_get_peak_usage());

$b = str_repeat("Bravo", 525252);
var_dump(memory_get_peak_usage());

unset($b);
memory_reset_peak_usage();

$b = str_repeat("Bravo", 2525);
var_dump(memory_get_peak_usage());

?>

Функція ini_parse_quantity() аналізує будь-який розмір даних, котрі розпізнаються значеннями PHP INI та повертає розмір, виражений у байтах. Після заданого числа може йти необов'язковий множник типу: k/K, m/M або g/G. Задане число може бути десятковим, двійковим, шістнадцятковим або вісімковим. Приклад:

var_dump(ini_parse_quantity('512K'));
var_dump(ini_parse_quantity('1024M'));
var_dump(ini_parse_quantity('0b1010k'));

Після виконання функція поверне наступні результати:

int(524288)
int(1073741824)
int(10240)

Константи

Константа є ідентифікатором для простого значення, яке не може змінюватися у ході виконання програми. У версію 8.2 на рівні ядра було внесено зміни, щодо використання констант:

  • Константи тепер можуть бути визначені у трейтах;

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

trait Agy { 
 
    public const CONSTANT = 50;
 }    
class Nee {
 
    use Agy;
 }
var_dump(Nee::CONSTANT); // 50

Як видно із наведеного прикладу, доступ до константи можна отримати лише посередництвом класу, котрий використовує трейт, але не через трейт.

Ядро

На рівні ядра у новій версії PHP було додано атрибут та директиву, котрі напряму впливають на гнучкість керування безпекою при використанні конфіденційних та системних даних:

  • Атрибут SensitiveParameter;
  • INI-директива error_log_mode.

Атрибут #[\SensitiveParameter] призначений для редагування конфіденційних даних у трасуваннях стеку викликів. Він виправляє фактичні значення у трасуваннях стеку і повідомленнях про помилки.

Всі функції, котрі приймають конфіденційні дані тепер можуть оголошувати свої параметри за допомогою вказаного атрибуту. Якщо виклик функції викликає помилку, то фактичне значення параметру буде замінено об'єктом \SensitiveparameterValue.

У попередніх версіях PHP оголошення вказаних функцій виглядало наступним чином:

function passwordHash(string $password)  {        
       debug_print_backtrace();
}

passwordHash('winter');

Із урахуванням змін, тепер це виглядає так:

function passwordHash(#[\SensitiveParameter] string $password)  {        
        debug_print_backtrace();
}

passwordHash('winter');

При наявності вказаного атрибуту у всіх трасуваннях стеку редагуються фактичні значення, котрі передаються параметру, як показано нижче:

array(1) {
 [0]=> array(4) {
   ["file"]=> string(25) "..."
   ["lins"]=> int(7)
   ["function"]=> string(3) "tee"
   ["args"]=> array(1) {
     [0]=> object(SensitiveParameterValue)#1 (0) {}
   }
 }
}

INI-директива error_log_mode призначена для встановлення дозволів для файлу журналу помилок, котрий визначається за допомогою функції error_log ().

Приклад визначення файлу, у котрий відправляється повідомлення про помилку message виглядає наступним чином:

error_log(
    string $message,
    int $message_type = 3,
    ?string $destination = file5,
    ?string $additional_headers = null
): bool

Атрибутом message_type визначається тип журналу, а атрибутом destination – ім'я файлу.

Модуль Random

Вказаний модуль є генератором випадкових чисел або RNG (Random Number Generators). До версії 8.2 у різних версіях PHP використовувалися різні типи генераторів глобального рівня із застосуванням різних алгоритмів генерування чисел. Розробники вирішили змінити підхід і замість одного глобального RNG надати можливість використовувати кілька незалежних генераторів із різним рівнем продуктивності в залежності від ситуації. Це забезпечується посередництвом об'єктно-орієнтованого API, для котрого доступно кілька генераторів, представлених окремими класами, котрі є реалізацією загального інтерфейсу Engine. В цих класах зберігаються внутрішні стани, що і дозволяє мати незалежні варіанти RNG.

Клас Random\Randomizer надає високорівневий API для випадковості, котра забезпечується класом або інтерфейсом Random\Engine. Вказаний інтерфейс дозволяє міняти місцями алгоритми генерування випадкової послідовності чисел. Кожен з алгоритмів має свої властивості, що до швидкості та якості згенерованої послідовності чисел. Усе залежить від потреб проекту.

На даний час більшість з методів класу Random\Randomizer ще не документовані.

Нові функціональності для сторонніх сервісів

У нову версію було додано чималу кількість функціональностей та параметрів для покращення роботи зі сторонніми сервісами. Вони наведені у таблиці.

Назва сервісу Функциональність / параметр Опис

COM

DISP_E_PARAMNOTFOUND,
LOCALE_NEUTRAL
Додано дві глобальні константи
cURL CURLINFO_EFFECTIVE_METHOD Повертає останній використаний метод HTTP у повернутому значенні функції curl_getinfo()
cURL curl_upkeep() Виконує будь-які перевірки поновлення з'єднання
cURL CURLALTSVC_H1, ..., CURL_VERSION_ZSTD Стали доступними 77 глобальних констант із бібліотеки libcurl 7.62 - 7.80
DBA DBA_LMDB_USE_SUB_DIR,
DBA_LMDB_NO_SUB_DIR
Нові глобальні константи використовуються як прапорці для драйверу LMDB для визначення потреби у створенні підкаталогу при створенні файлу бази даних
OCI8 oci8.prefetch_lob_size, oci_set_prefetch_lob() INI-директива та функція для налаштування LOB-запитів шляхом зменшення кількості обходів між PHP та Oracle
OpenSSL chacha20-poly1305 Додана підтримка AEAD-алгоритму
ODBC odbc_connection_string_is_quoted(),
odbc_connection_string_quote(),
odbc_connection_string_should_quote()
Вказані внутрішні функції ODBC тепер доступні ззовні. Це полегшить модульне тестування і зробить можливим екранування строк із користувацьких додатків
PCRE NO_AUTO_CAPTURE Доданий модифікатор робить прості неіменовані групи типу xyz не перехоплюваними
Сокеты SO_INCOMING_CPU, ..., MSG_ZEROCOPY Відтепер визначаються 16 опцій сокетів для різних ОС, у випадку, якщо вони підтримуються

Застарілі функціональності

Внесено ряд змін, котрі виключають подальше використання декотрих властивостей, функцій, методів та синтаксису ядра PHP та декотрих сторонніх сервісів. Розглянемо їх більш детально.

Ядро

Нижче перераховано застарілі функціональності ядра PHP:

  • Динамічні властивості;
  • Виклик методів;
  • Стиль інтерполяції строк.

Динамічні властивості оголошено застарілими, тобто їх вже неможна створювати. Винятком є випадок, коли клас не обробляє їх використання за допомогою атрибуту #[\AllowDynamicProperties]. Зміни також не впливають на роботу із методами __get() та __set().

Виклик методів із відносним ім'ям, котрі не відповідають синтаксису $callable() оголошено застарілими. Зокрема, це такі виклики:

  • "parent::method";
  • "parent::method";
  • "static::method".

Вказані зміни не впливають на виклики звичайних методів.

Стиль інтерполяції строк виду "${var}" та "${expr}" оголошено застарілим. Замість них прийнятно використання синтаксису виду "$var"/"{$var}" та "{${expr}}" відповідно.

Стандартні функції

Функції перетворення строк із системи кодування ISO-8859-1 в UTF-8 та в зворотному напрямку, починаючи з версії 8.2 наполегливо рекомендовано не вживати. Це такі функції - utf8_encode() та utf8_decode().

Модулі та бібліотеки

Нижче перераховані бібліотеки, декотрі функції котрих визнано застарілими:

  • MBString;
  • SPL.

Для всіх функцій MBString використання текстових кодувань типу Base64,QPrint, Uuencode та HTML-ENTITIES оголошено застарілим. Це пов'язано з тим, що вказані кодування не кодують послідовності кодових точок системи Unicode, а лише послідовність необроблених байтів.

У бібліотеці SPL (Standard PHP Library) внутрішній метод типу SplFileInfo::_bad_state_ex() оголошено застарілим та рекомендовано не використовувати.

FREEhost.UA першим в Україні додав нову версію PHP на свої сервери. Запрошуємо Вас скористатися нашим віртуальним хостингом з підтримкою PHP 8.2 вже зараз. Протестувати хостинг можна 7 днів безкоштовно.

Підписуйтесь на наш телеграм–канал https://t.me/freehostua, щоб бути в курсі нових корисних матеріалів.

Дивіться наш канал Youtube на https://www.youtube.com/freehostua.

Ми у чомусь помилилися, чи щось пропустили?

Напишіть Про це у коментарях, ми з задоволенням відповімо та обговорюємо Ваші зауваження та пропозиції.

Дата: 20.12.2022
Автор: Євген
Голосування

Авторам статті важлива Ваша думка. Будемо раді його обговорити з Вами:

comments powered by Disqus
navigate
go
exit
Дякуємо, що обираєте FREEhost.UA