CakeFest 2024: The Official CakePHP Conference

Новая функциональность

Объявления скалярных типов

Скалярные типы объявляют в двух режимах: нестрогом, в котором PHP работает по умолчанию, и строгом. Теперь как в нестрогом, так и в строгом режимах разрешается задавать следующие типы параметров: строки (string), целые числа (int), числа с плавающей точкой (float) и логические значения (bool). Перечисленные типы дополняют другие типы, которые появились в PHP 5: имена классов, интерфейсов, массивы (array) и callable.

<?php

// Нестрогий режим с приведением типов
function sumOfInts(int ...$ints)
{
return
array_sum($ints);
}

var_dump(sumOfInts(2, '3', 4.1));

?>

Результат выполнения приведённого примера:

int(9)

Для установки строгого режима, в самом начале файла необходимо поместить одну директиву declare. Это означает, что строгость объявления скалярных типов работает на уровне файла и не затрагивает весь остальной код. Эта директива затрагивает не только объявления параметров, но и возвращаемые значения функций (смотрите объявления возвращаемого типа), встроенные функции PHP и функции загруженных модулей.

Подробную документацию и примеры использования читайте в разделе декларация типов.

Объявления возвращаемых значений

В PHP 7 добавлена поддержка объявления возвращаемого типа. Аналогично как и объявления типов аргументов, объявление типа возвращаемого значения указывает, значение какого типа должна вернуть функция. Для объявления типа возвращаемого значения доступны все те же типы, что и для объявления типов аргументов.

<?php

function arraysSum(array ...$arrays): array
{
return
array_map(function(array $array): int {
return
array_sum($array);
},
$arrays);
}

print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));

?>

Результат выполнения приведённого примера:

Array
(
    [0] => 6
    [1] => 15
    [2] => 24
)

Полную документацию и примеры использования читайте в разделе про объявление возвращаемого типа.

Оператор объединения с null

Был добавлен оператор объединения с null (??), являющийся синтаксическим сахаром для достаточно распространённого действия, когда совместно используются тернарный оператор и функция isset(). Он возвращает первый операнд, если он задан и не равен null, а в обратном случае возвращает второй операнд.

<?php

// Извлекаем значение $_GET['user'], а если оно не задано,
// то возвращаем 'nobody'
$username = $_GET['user'] ?? 'nobody';

// Это идентично следующему коду:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

// Этот оператор можно использовать в цепочке.

// В этом примере мы сперва проверяем, задан ли $_GET['user'], если нет,
// то проверяем $_POST['user'], и если он тоже не задан, то присваеваем 'nobody'.
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';

?>

Оператор spaceship (космический корабль)

Этот оператор предназначен для сравнения двух выражений. Он возвращает -1, 0 или 1 если $a, соответственно, меньше, равно или больше чем $b. Сравнение производится в соответствии с правилами сравнения типов PHP.

<?php

// Целые числа
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1

// Числа с плавающей точкой
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1

// Строки
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1

?>

Определение констант массивов с помощью define()

Можно определить константу типа array с помощью функции define(). В PHP 5.6 такие константы можно было задавать только с помощью const.

<?php

define
('ANIMALS', [
'dog',
'cat',
'bird'
]);

echo
ANIMALS[1]; // выводит "cat"

?>

Анонимные классы

Была добавлена поддержка анонимных классов с помощью new class. Их можно использовать тогда, когда нужен одноразовый класс и создавать полноценный класс, а потом его объект не имеет смысла:

<?php

interface Logger
{
public function
log(string $msg);
}

class
Application
{
private
$logger;

public function
getLogger(): Logger {
return
$this->logger;
}

public function
setLogger(Logger $logger) {
$this->logger = $logger;
}
}

$app = new Application;
$app->setLogger(new class implements Logger {
public function
log(string $msg) {
echo
$msg;
}
});

var_dump($app->getLogger());

?>

Результат выполнения приведённого примера:

object(class@anonymous)#2 (0) {
}

Подробную документацию и примеры использования читайте в разделе про анонимные классы.

Синтаксис кодирования Unicode

Он принимает шестнадцатеричный код Unicode и записываем его в формате UTF-8 в двойных кавычках или формате heredoc. Любой корректный код будет принят. Ведущие нули по желанию.

echo "\u{aa}";
echo "\u{0000aa}";
echo "\u{9999}";

Результат выполнения приведённого примера:

ª
ª (То же самое, что и первый вариант, но с ведущими нулями)
香

Closure::call()

Closure::call() — более производительный и короткий способ временного связывания области действия объекта с замыканием и его вызовом.

<?php

class A
{
private
$x = 1;
}

// До PHP 7
$getX = function() {
return
$this->x;
};
$getXCB = $getX->bindTo(new A, 'A'); // Промежуточное замыкание
echo $getXCB();

// PHP 7+
$getX = function() {
return
$this->x;
};
echo
$getX->call(new A);

?>

Результат выполнения приведённого примера:

1
1

unserialize() с фильтрацией

Эта функциональность обеспечивает более высокий уровень безопасности при десериализации объектов с непроверенными данными. Это позволяет предотвратить возможную инъекцию кода, позволяя разработчику использовать белый список классов для десериализации.

<?php

// Преобразование всех объектов в __PHP_Incomplete_Class
$data = unserialize($foo, ["allowed_classes" => false]);

// Преобразование всех объектов, кроме MyClass и MyClass2 в __PHP_Incomplete_Class
$data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]]);

// Поведение по умолчанию принимает все классы (можно просто не задавать второй аргумент)
$data = unserialize($foo, ["allowed_classes" => true]);

?>

IntlChar

Новый класс IntlChar добавляет новую функциональность в ICU. Класс определяет несколько статических методов и констант для манипулирования символами Unicode.

<?php

printf
('%x', IntlChar::CODEPOINT_MAX);
echo
IntlChar::charName('@');
var_dump(IntlChar::ispunct('!'));

?>

Результат выполнения приведённого примера:

10ffff
COMMERCIAL AT
bool(true)

Для работы с этим классом требуется установить модуль Intl.

Ожидания

Ожидания являются улучшенной, обратно совместимой версией старой функции assert(). Они позволяют делать предположения с нулевой стоимостью в промышленном коде и предоставляют возможность выбрасывать пользовательские исключения в случае провала ожидания.

Вместе тем, что старое API поддерживается, assert() теперь является языковой конструкцией, принимающей первым аргументом выражения, а не только строки (string) для оценки или логические значения (bool) для проверки.

<?php

ini_set
('assert.exception', 1);

class
CustomError extends AssertionError {}

assert(false, new CustomError('Сообщение об ошибке'));

?>

Результат выполнения приведённого примера:

Fatal error: Uncaught CustomError: Сообщение об ошибке

Подробное описание этого функционала, а также инструкции для его конфигурирования для тестовых и промышленных сред, можно найти на странице руководства, посвящённой функции assert().

Групповые объявления use

Классы, функции и константы импортируемые из одного и того же namespace, теперь можно группировать в одном операторе use.

<?php

// До PHP 7
use some\namespace\ClassA;
use
some\namespace\ClassB;
use
some\namespace\ClassC as C;

use function
some\namespace\fn_a;
use function
some\namespace\fn_b;
use function
some\namespace\fn_c;

use const
some\namespace\ConstA;
use const
some\namespace\ConstB;
use const
some\namespace\ConstC;

// PHP 7+
use some\namespace\{ClassA, ClassB, ClassC as C};
use function
some\namespace\{fn_a, fn_b, fn_c};
use const
some\namespace\{ConstA, ConstB, ConstC};

?>

Выражение return в генераторах

Эта функциональность добавлена к генераторам, введённым в PHP 5.5. Она позволяет использовать оператор return в генераторах в качестве окончательного возвращаемого значения (возврат по ссылке недопустим). Это значение можно извлечь с помощью нового метода Generator::getReturn(), который можно использовать только после того, как генератор вернул все сгенерированные значение.

<?php

$gen
= (function() {
yield
1;
yield
2;

return
3;
})();

foreach (
$gen as $val) {
echo
$val, PHP_EOL;
}

echo
$gen->getReturn(), PHP_EOL;

?>

Результат выполнения приведённого примера:

1
2
3

Возможность явно получать окончательное значение генератора является очень полезной, так как позволяет клиентскому коду, использующему генератор, получать и обработать самое последнее значение генератора, после которого точно ничего больше не будет. Это сильно проще, чем вынуждать разработчика проверять, последнее ли значение вернулось и как-то по особенному его обрабатывать.

Делегация генератора

Теперь генератор может автоматически делегировать другому генератору, объекту класса, реализующий Traversable или массиву без необходимости писать в нем дополнительную обработку полученных значений. Достигается это с помощью конструкции yield from.

<?php

function gen()
{
yield
1;
yield
2;
yield from
gen2();
}

function
gen2()
{
yield
3;
yield
4;
}

foreach (
gen() as $val)
{
echo
$val, PHP_EOL;
}

?>

Результат выполнения приведённого примера:

1
2
3
4

Функция целочисленного деления intdiv()

Новая функция intdiv() производит целочисленное деление операндов и возвращает его результат.

<?php

var_dump
(intdiv(10, 3));

?>

Результат выполнения приведённого примера:

int(3)

Опции сессий

Теперь session_start() принимает массив опций, которые переопределят конфигурационные директивы сессии установленные в php.ini.

Также опции были расширены включённой по умолчанию опцией session.lazy_write, которая говорит PHP о том, что файл сессии надо перезаписывать, только если изменились данные сессии, и опцией read_and_close, которую можно задать только через session_start() для того, чтобы PHP закрывал сессию сразу же как прочитает её данные и не вносил в неё каких-либо изменений.

К примеру, для установки session.cache_limiter равным private и немедленному закрытию сессии после чтения её данных:

<?php

session_start
([
'cache_limiter' => 'private',
'read_and_close' => true,
]);

?>

preg_replace_callback_array()

Новая функция preg_replace_callback_array() помогает писать более чистый код, когда требуется вызвать функцию preg_replace_callback(). До PHP 7 при обработке разных регулярных выражений разными функциями приходилось для каждой такой обработки писать отдельный вызов функции.

Теперь можно использовать одну функцию и передавать в неё ассоциативный массив, в котором ключи — регулярные выражения, а значения — функции обратного вызова.

Функции CSPRNG

Были добавлены две новые кроссплатформенные функции для генерации криптографически безопасных строк и целых чисел: random_bytes() и random_int().

Теперь функция list() всегда может распаковывать объекты, реализующие ArrayAccess

Ранее функция list() не гарантировала корректную обработку объектов, реализующих ArrayAccess. Теперь это исправлено.

Прочие изменения

  • Добавлена возможность доступа к методам и свойствам класса при клонировании, то есть (clone $foo)->bar().
add a note

User Contributed Notes 2 notes

up
55
Adrian Wiik
4 years ago
A good rule of thumb for remembering what the spaceship operator expression returns is to replace the spaceship operator with a minus sign (-). If the result is negative, 0 or positive, the expression will return -1, 0 or 1 respectively.

Example:
<?php
echo 5 <=> 8; // 5 - 8 = -3, prints -1
echo 2 <=> 2; // 2 - 2 = 0, prints 0
echo 4 <=> 2; // 4 - 2 = 2, prints 1
up
12
Julian Sawicki
3 years ago
In php 7.0 it's possible to curry functions in a way that's similar to JavaScript.

<?php

// A curried function
function add($a) {
return function(
$b) use ($a) {
return
$a + $b;
};
}

// Invoking curried function in PHP 7
$result = add(10)(15);

var_dump($result); // int 25

?>

Currying in this way is not possible in php 5.6.
To Top