Всё, что появится в PHP 8.5
Оператор конвейера |>
В PHP 8.5 будет введён оператор pipe/конвейера (|>
), позволяющий писать код в безточечном стиле, ограничивающем использование необязательных промежуточных переменных.
Итак, следующий код…
$value = "hello world";
$result1 = function3($value);
$result2 = function2($result1);
$result = function1($result2);
…можно переписать с помощью оператора конвейера так:
$value = "hello world";
$result = $value
|> function3(...)
|> function2(...)
|> function1(...);
Оператор |>
, или "pipe", принимает вызываемый объект с одним параметром справа и передаёт ему значение с левой стороны, вычисляя результат вызываемого объекта. Конвейер (|>
) вычисляется слева направо, передавая значение (или результат выражения) слева в качестве первого и единственного параметра вызываемому объекту справа.
Вот более реальный пример:
$fullName = 'Fred Flintstone';
$result = $fullName
|> fn($x) => explode(' ', $x) // Создаёт массив отдельных слов
|> fn($x) => implode('_', $x) // Соединяет эти слова с помощью символа _
|> strtolower(...) // Преобразует всё в нижний регистр
;
// $result === 'fred_flintstone'
Новые методы массива
В PHP 8.5 будут добавлены две новые функции массива, array_first()
и array_last()
, упрощающие получение первого и последнего элементов массива без изменения внутреннего указателя и использования ключей.
$array = [1, 2, 3, 4, 5];
$first = array_first($array); // 1
$last = array_last($array); // 5
$array = ['a' => 1, 'b' => 2, 'c' => 3];
$first = array_first($array); // 1
$last = array_last($array); // 3
Для пустых массивов обе функции возвращают null
вместо выброса ошибки.
$first = array_first([]); // null
$last = array_last([]); // null
Атрибут #[\NoDiscard]
В PHP 8.5 добавлен новый атрибут #[\NoDiscard]
, позволяющий разработчикам указывать, что возвращаемое значение функции или метода не должно игнорироваться. Если разработчик вызывает функцию, помеченную #[\NoDiscard]
, и не использует возвращаемое значение, PHP выдаст предупреждение.
#[\NoDiscard("as the operation result is important")]
function performOperation(): int {
// Выполнение какой-либо операции
return 1; // 1 — в случае успеха, 0 — в случае неудачи
}
// Вызов функции без использования возвращаемого значения
// Warning: The return value of function performOperation() is expected to be consumed, as the operation result is important in test.php on line 10
performOperation();
// Вызов функции и использование возвращаемого значения
// Это действие не вызовет предупреждение.
$status = performOperation();
Это отличный способ убедиться, что разработчики случайно не проигнорируют важные возвращаемые значения, особенно в тех случаях, когда возвращаемое значение имеет решающее значение для успеха или неудачи операции.
Продвижение final
свойства
class Example {
public function __construct(
final string $id
) {}
}
- Свойство
$id
теперь является как продвинутым (созданным и инициализированным через конструктор), так и окончательным (не может быть переопределено). - Если используете
final
, не нужно указывать видимость (например,public
илиprivate
); по умолчанию онаpublic
, но при желании можно комбинироватьfinal
с видимостью.
Это делает синтаксис продвижения свойств конструктора более последовательным, и уменьшает количество шаблонного кода, который необходимо писать.
Атрибуты констант
Как вы, возможно, знаете, атрибуты — это способ добавления метаданных к элементам кода (таким как классы, методы, свойства и т. д.) с помощью специального синтаксиса. Например:
#[MyAttribute]
class MyClass {}
Теперь, с PHP 8.5, помимо таких вещей, как классы, методы и константы классов, можно также добавлять атрибуты к глобальным (неклассовым) константам.
Теперь можно добавлять атрибуты к неклассовым константам периода компиляции, например:
#[MyAttribute]
const MY_CONST = 42;
Следует иметь в виду, что это не работает для констант, определённых с помощью define()
, а только для объявленных с помощью const
.
Теперь можно использовать ReflectionConstant::getAttributes()
для чтения атрибутов констант в runtime. Кроме того, атрибут #[\Deprecated]
обновлён, чтобы позволить ориентироваться на константы; при применении константа помечается как CONST_DEPRECATED
.
#[Deprecated(reason: 'Use NEW_API_URL instead. This will be removed in v2.0.')]
const OLD_API_URL = 'https://old-api.example.com';
const NEW_API_URL = 'https://api.example.com';
// Пример использования
function fetchData() {
// IDE и статические анализаторы теперь могут предупреждать об использовании OLD_API_URL
$data = file_get_contents(OLD_API_URL);
return $data;
}
Улучшенный класс Directory
В PHP 8.5 класс Directory
изменён так, что теперь он ведёт себя как строгий, немодифицируемый ресурсный объект. По сути, класс Directory
в PHP используется для представления дескрипторов каталогов, обычно создаваемых функцией dir()
. Исторически он вёл себя как обычный класс, но это могло приводить к ошибкам и неправильному использованию (например, созданию недопустимых объектов Directory
с помощью new Directory()
).
Чтобы исправить это, в PHP 8.5 класс Directory
ведёт себя как настоящий "ресурсный объект" (иногда называемый "непрозрачным объектом").
Это означает:
- Конечный класс: Нельзя расширять (наследовать) класс
Directory
. - Отсутствие прямого создания экземпляров: Нельзя создать объект
Directory
с помощьюnew Directory()
. Только функцияdir()
может создавать валидные экземпляры. - Отсутствие клонирования: Нельзя клонировать объект
Directory
. - Отсутствие сериализации: Нельзя сериализовать или десериализовать объекты
Directory
. - Отсутствие динамических свойств: Нельзя добавлять новые свойства к объектам
Directory
во время выполнения.
Теперь, при попытке создать объект Directory
с помощью new Directory()
, будет выброшена ошибка:
$dir = new Directory(); // Выбрасывает ошибку
$dir = dir('/tmp'); // Корректный способ создания объекта Directory
Трассировка фатальных ошибок
PHP 8.5 появится автоматическая трассировка стека к сообщениям о фатальных ошибках PHP, что значительно упростит отладку.
Сейчас в PHP, когда происходит фатальная ошибка (например, истечение времени выполнения или памяти), сообщение об ошибке не содержит трассировку (список вызовов функций, которые привели к ошибке). Без трассировки трудно понять, что вызвало ошибку, особенно в больших или сложных кодовых базах.
Когда эта опция включена (а она может быть включена по умолчанию), PHP будет выводить трассировку стека для фатальных ошибок. Трассировка стека показывает последовательность вызовов функций, приведших к ошибке, аналогично тому, что вы видите при исключениях.
Так выглядела трассировка ранее:
Fatal error: Maximum execution time of 1 second exceeded in example.php on line 7
После включения новой опции INI она будет выглядеть следующим образом:
Fatal error: Maximum execution time of 1 second exceeded in example.php on line 6
Stack trace:
#0 example.php(6): usleep(100000)
#1 example.php(7): recurse()
#2 example.php(7): recurse()
...
#11 {main}
Ключевые моменты о новой трассировке ошибок:
- Чтобы избежать проблем с производительностью и памятью, трассировка выполняется только для фатальных ошибок (а не для предупреждений или уведомлений).
- Трассировка учитывает настройки конфиденциальности (например, атрибуты
SensitiveParameter
). - Трассировка также доступна программно через
error_get_last()
в функциях завершения работы.
Улучшения постоянных дескрипторов cURL
PHP 8.5 улучшает способ управления постоянными дескрипторами cURL, делая их более безопасными и простыми в использовании.
По сути, дескрипторы cURL позволяют нескольким запросам cURL совместно использовать данные (например, кэш DNS) для повышения эффективности. Недавно в PHP была добавлена поддержка постоянных дескрипторов cURL, которые можно повторно использовать в нескольких PHP запросах. Первоначальная реализация имела некоторые риски и проблемы с удобством использования, особенно в отношении совместного использования cookie-файлов и управления постоянными идентификаторами.
PHP 8.5 вводит новую функцию curl_share_init_persistent()
, создающую постоянный дескриптор cURL. Эта функция более безопасна и последовательна, чем предыдущая curl_share_init()
. Больше не нужно предоставлять настраиваемый постоянный идентификатор; PHP управляет этим автоматически на основе переданных вами параметров. Если повторно вызвать функцию с теми же параметрами, вы получите тот же дескриптор (он будет повторно использован).
$options = [CURL_LOCK_DATA_DNS];
$shareHandle = curl_share_init_persistent($options);
//Использование $shareHandle с CURLOPT_SHARE в запросах cURL
curl_setopt($ch, CURLOPT_SHARE, $shareHandle);
Это улучшение важно, поскольку предотвращает случайную передачу конфиденциальных cookie-файлов. Кроме того, разработчикам не нужно управлять постоянными идентификаторами или беспокоиться о несоответствии дескрипторов.
Callable объекты первого класса в константных выражениях
PHP 8.5 позволит использовать callable объекты первого класса (FCC) в константных выражениях PHP.
Как вы, возможно, знаете, callable объекты первого класса — это лаконичный способ ссылки на функции или статические методы в качестве вызываемых объектов с помощью синтаксиса … . Например:
// $callable теперь callable strlen()
$callable = strlen(...);
// callable MyClass::myMethod()
$callable = MyClass::myMethod(...);
Раньше нельзя было использовать FCC внутри константных выражений (таких как значения свойств по умолчанию, аргументы атрибутов или определения констант). В PHP 8.5 это изменилось, и теперь можно использовать FCC в константных выражениях.
const MY_CALLABLE = strlen(...);
#[Attr(self::myMethod(...))]
class C {}
Это делает использование FCC более последовательным в PHP и упрощает определение повторно используемых callable объектов в качестве констант, их использование в атрибутах или в качестве значений по умолчанию, что делает код более выразительным и DRY.
Использование замыканий в константных выражениях
PHP 8.5 позволит использовать статические замыкания (анонимные функции) в константных выражениях PHP. Чтобы понять, что изменилось, давайте сначала разберёмся, что такое константные выражения.
Константное выражение в PHP — это значение, которое должно быть полностью определено во время компиляции. Примеры:
- Значения по умолчанию для параметров функций.
- Аргументы атрибутов.
- Константы классов.
- Значения по умолчанию свойств.
До PHP 8.5 в константах нельзя было использовать замыкания (анонимные функции). В PHP 8.5 это изменилось. Теперь можно делать что-то вроде этого.
function my_array_filter(
array $array,
Closure $callback = static function ($item) { return !empty($item); }
) {
// ...
}
Или используйте замыкания в качестве аргументов атрибутов, значений свойств по умолчанию или констант классов.
Существует несколько ограничений:
- Должно быть статическим: замыкание не может использовать
$this
или захватывать переменные из окружающей области видимости (нельзя использоватьuse($foo)
и стрелочные функции). - Запрет на захват переменных: допускаются только чистые статические замыкания, поскольку константные выражения не могут зависеть от runtime-значений.
- Проверка во время компиляции: PHP выдаст ошибку, если попытаться использовать нестатическое замыкание или замыкание, захватывающее переменные.
Возможность использовать замыкания в константных выражениях позволяет писать более чистый код, поскольку можно предоставлять стандартные обратные вызовы или валидаторы непосредственно в сигнатурах функций, атрибутах или константах.
Кроме того, библиотеки могут использовать замыкания в атрибутах для таких целей, как валидация, форматирование или генерация наборов тестов, как показано ниже.
final class Locale
{
#[Validator\Custom(static function (string $languageCode): bool {
return preg_match('/^[a-z][a-z]$/', $languageCode);
})]
public string $languageCode;
}
final class CalculatorTest
{
#[Test\CaseGenerator(static function (): iterable {
for ($i = -10; $i <= 10; $i++) {
yield [$i, $i, 0];
yield [$i, 0, $i];
yield [0, $i, ($i * -1)];
}
})]
public function testSubtraction(int $minuend, int $subtrahend, int $result)
{
\assert(Calculator::subtract($minuend, $subtrahend) === $result);
}
}
final class LogEntry
{
public string $message;
#[Serialize\Custom(static function (string $severity): string {
return \strtoupper($severity);
})]
public string $severity;
}
В целом, это хорошее улучшение, делающее код более выразительным и лаконичным.
Функции обработки ошибок и исключений
В PHP 8.5 будут добавлены функции get_error_handler()
и get_exception_handler()
, позволяющие напрямую получать текущие обработчики ошибок и исключений.
В PHP можно настроить собственные обработчики ошибок и исключений с помощью функций set_error_handler()
и set_exception_handler()
. Однако не было прямого способа проверить, какой обработчик используется в данный момент.
Разработчикам приходилось использовать обходной путь: устанавливать новый обработчик, сохранять старый, а затем восстанавливать его, что было неудобным и чреватым ошибками процессом.
В PHP 8.5 добавлены две новые функции:
get_error_handler(): ?callable
get_exception_handler(): ?callable
Эти функции возвращают текущий зарегистрированный обработчик ошибок или исключений, либо null
, если ни один из них не установлен.
set_error_handler(null);
get_error_handler(); // null
$handler = [$this, 'error_handler'];
set_error_handler($handler);
get_error_handler() === $handler; // true
$new_handler = $this->error_handler(...);
$old_handler = set_error_handler($new_handler);
get_error_handler() === $new_handler; // true
restore_error_handler();
get_error_handler() === $old_handler; // true
Как можно догадаться, это делает процесс настройки обработчиков надёжным, поскольку вы получаете именно тот обработчик, который настроили, что упрощает отладку и управление обработчиками.
Кроме того, фреймворки и библиотеки теперь могут безопасно проверять или восстанавливать обработчики без побочных эффектов.
Новая опция INI diff
В PHP 8.5 добавлена опция INI diff
, отображающая все настройки INI, которые отличаются от встроенных настроек PHP по умолчанию.
php --ini=diff
Эта команда выводит список всех директив конфигурации INI, которые были изменены по сравнению с их встроенными значениями по умолчанию. Это быстрый способ увидеть, какие настройки были настроены в вашей среде, что особенно удобно для отладки, устранения неполадок или обмена информацией о различиях в конфигурации.
Non-default INI settings:
memory_limit: "128M" -> "512M"
display_errors: "1" -> ""
date.timezone: "UTC" -> "Europe/Amsterdam"
Здесь левое значение является значением по умолчанию, а правое — текущей настройкой. Кроме того, отображаются только настройки, отличающиеся от значений по умолчанию.
Это позволяет быстро обнаружить изменения в конфигурации, влияющие на поведение приложения, и легко сравнивать различные среды (dev
, stage
, prod
).
Также это позволяет увидеть, что изменилось в контейнерных или автоматизированных настройках.