PHP 7.2 и 7.3
PHP 7.2 — Безопасность и типы
PHP 7.2 (ноябрь 2017) добавил новые возможности типизации и встроил криптографическую библиотеку Sodium.
Object type hint
<?php
declare(strict_types=1);
// Тип object — принимает любой объект
function serialize(object $obj): string
{
return json_encode($obj);
}
function createFromArray(string $class, array $data): object
{
$obj = new $class();
foreach ($data as $key => $value) {
$obj->$key = $value;
}
return $obj;
}
// Использование
$user = new stdClass();
$user->name = 'Alice';
echo serialize($user); // {"name":"Alice"}
Важно:
object— это конкретный тип, не интерфейс. Он принимает экземпляр любого класса, но не скалярные значения и не массивы.
Расширение Sodium (libsodium)
<?php
// Sodium встроен в PHP 7.2+ (раньше был PECL-расширением)
// Шифрование (symmetric)
$key = sodium_crypto_secretbox_keygen();
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$message = 'Secret data';
$cipher = sodium_crypto_secretbox($message, $nonce, $key);
$decrypted = sodium_crypto_secretbox_open($cipher, $nonce, $key);
echo $decrypted; // Secret data
// Хеширование паролей (лучше чем password_hash для некоторых случаев)
$hash = sodium_crypto_pwhash_str(
'my_password',
SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);
$valid = sodium_crypto_pwhash_str_verify($hash, 'my_password'); // true
// Очистка чувствительных данных из памяти
sodium_memzero($key);
sodium_memzero($message);
Parameter type widening
<?php
// Дочерний класс может расширять типы параметров
class ParentClass
{
public function process(int $value): void
{
echo $value;
}
}
class ChildClass extends ParentClass
{
// Убираем type hint — расширяем тип (было int, стало любой)
public function process($value): void
{
echo $value;
}
}
// Это соответствует принципу подстановки Лисков (LSP):
// Дочерний класс принимает ВСЁ, что принимает родитель + больше
Принцип: параметры можно расширять (contravariance), возвращаемые типы — сужать (covariance). Полная поддержка covariance/contravariance появилась в PHP 7.4.
Trailing comma в группировке use
<?php
use App\Models\{
User,
Order,
Product, // Trailing comma — теперь разрешена
};
Abstract method override
<?php
abstract class Base
{
abstract function test(string $value): void;
}
abstract class Middle extends Base
{
// Абстрактный метод можно переопределить в абстрактном классе
abstract function test(string $value): void;
}
PHP 7.3 — Удобство разработчика
PHP 7.3 (декабрь 2018) сфокусировался на улучшении developer experience.
Flexible Heredoc/Nowdoc
<?php
// До PHP 7.3 — закрывающий маркер должен быть в начале строки
$old = <<<EOT
Hello
World
EOT;
// PHP 7.3+ — закрывающий маркер может быть с отступом
// Отступ закрывающего маркера определяет "базовый" отступ
$html = <<<HTML
<div>
<h1>Title</h1>
<p>Content</p>
</div>
HTML;
// Результат: <div>\n <h1>Title</h1>... (4 пробела убраны)
// Можно использовать в аргументах функций
$data = [
'description' => <<<DESC
This is a multi-line
description text.
DESC,
'name' => 'Product',
];
// Nowdoc (без интерполяции) — те же правила
$sql = <<<'SQL'
SELECT *
FROM users
WHERE active = 1
SQL;
Ключевое правило: отступ закрывающего маркера определяет, сколько пробелов будет удалено из начала каждой строки. Если строка имеет меньший отступ, чем маркер, будет Parse error.
Trailing comma в вызовах функций
<?php
// Trailing comma теперь разрешена в вызовах функций
function createUser(
string $name,
string $email,
int $age,
) {
// Trailing comma в объявлении была с PHP 7.0
}
// Теперь и в вызове:
$user = createUser(
'Alice',
'[email protected]',
30, // Trailing comma — OK с PHP 7.3
);
// Упрощает diff при добавлении аргументов
// и уменьшает merge conflicts
Новые функции для массивов
<?php
$array = ['a' => 1, 'b' => 2, 'c' => 3];
// array_key_first() — первый ключ без reset()
$firstKey = array_key_first($array); // 'a'
// array_key_last() — последний ключ без end()
$lastKey = array_key_last($array); // 'c'
// До PHP 7.3 приходилось делать:
$oldFirst = array_keys($array)[0];
// или
reset($array);
$oldFirst = key($array);
// is_countable() — проверка, можно ли передать в count()
$value = 'hello';
if (is_countable($value)) {
echo count($value);
} else {
echo "Not countable";
}
// Раньше count() на не-countable выдавал Warning
// Теперь можно проверить заранее
JSON_THROW_ON_ERROR
<?php
// До PHP 7.3 — нужно проверять json_last_error()
$data = json_decode($invalid);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException(json_last_error_msg());
}
// PHP 7.3+ — выброс исключения автоматически
try {
$data = json_decode('invalid json', true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
echo "JSON error: " . $e->getMessage();
// "JSON error: Syntax error"
}
// Работает и для json_encode
try {
$json = json_encode("\xB1\x31", JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
echo "Encoding error: " . $e->getMessage();
}
Для экзамена:
JSON_THROW_ON_ERRORдобавлен в PHP 7.3, классJsonExceptionнаследует\Exception(не\RuntimeException).
Миграция на PCRE2
<?php
// PHP 7.3 перешёл с PCRE на PCRE2
// Основное отличие — более строгие правила
// Раньше работало, теперь Warning:
// preg_match('/[\w-.]+/', $string);
// Дефис должен быть экранирован или стоять в начале/конце
preg_match('/[\w\-.]+/', $string); // Правильно
// PCRE2 также добавил поддержку Unicode 11
Ссылочное присваивание с list()
<?php
$array = [1, 2];
// PHP 7.3 — деструктуризация по ссылке
[&$a, &$b] = $array;
$a = 10;
echo $array[0]; // 10 — изменился оригинальный массив
Сводная таблица: PHP 7.2 vs 7.3
| Возможность | PHP 7.2 | PHP 7.3 |
|---|---|---|
object type hint |
Да | -- |
| Sodium extension | Встроен | -- |
| Parameter type widening | Да | -- |
| Flexible Heredoc/Nowdoc | -- | Да |
| Trailing comma в вызовах | -- | Да |
array_key_first/last() |
-- | Да |
is_countable() |
-- | Да |
JSON_THROW_ON_ERROR |
-- | Да |
| PCRE2 | -- | Да |
| Ссылки в list() | -- | Да |
Типичные вопросы на экзамене
- Что такое parameter type widening? Дочерний класс может убрать или расширить тип параметра метода родителя.
- Чем
JSON_THROW_ON_ERRORлучшеjson_last_error()? Исключение прерывает поток выполнения, его нельзя случайно пропустить. - Какой класс исключения бросает
json_decodeсJSON_THROW_ON_ERROR?JsonException. - Как работает отступ в Flexible Heredoc? Отступ закрывающего маркера определяет базовый уровень, который удаляется из всех строк.
- Что вернёт
array_key_first([])?null.
Практические задания
Задание 1: Sodium
Напишите функцию encryptMessage(string $message, string $password): string с использованием Sodium для симметричного шифрования.
Задание 2: JSON обработка
Создайте класс JsonParser с методом parse(string $json): array, который использует JSON_THROW_ON_ERROR и оборачивает JsonException в доменное исключение.
Задание 3: Flexible Heredoc
Перепишите шаблон email-письма, используя Flexible Heredoc с правильными отступами.