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

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

Что нового в обновленной версии PHP

Оглавление

Очередная версия РHP 8.2 оказалась достаточно кардинальной во многих аспектах. Внесенные изменения затронули не только ядро PHP и системы типов, но и методы работы со многими сторонними сервисами. Рассмотрим эти изменения более подробно.

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

В PHP используется номинальная система типов с сильной поведенческой связью между подтипами. Она поддерживает разновидности базовых типов, которые используются для создания более сложных или комплексных типов. Реализация этой возможности, то есть создание комплексных типов и построение системы четкой типизации шла постепенно от версии к версии. Но более совершенной она стала с выходом версии 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 класса запрещено объявлять статические или нетипизированные свойства, поскольку такие свойства не могут быть отмечены указанным модификатором, как это было раньше. В противном случае, парсером сдана фатальная ошибка, как показано ниже:В пределах объявленного с помощью модификатора readonly класса запрещено объявлять статические или нетипизированные свойства, поскольку такие свойства не могут быть отмечены указанным модификатором, как это было раньше. В противном случае, парсером здана фатальная ошибка, как показано ниже:

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

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

Стандартные функции

PHP 8.2 добавляет две полезные стандартные функции, оптимизирующие работу приложений:

  • memory_reset_peak_usage();
  • ini_parse_quantity().

Функция 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";
  • ["self", "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