PHP 7.0: Главные нововведения
Ветка PHP 7.0 — это не «ещё один минор», а смена поколения после долгой линейки PHP 5. В языке появляются скалярные объявления типов (по умолчанию работают в coercive-режиме, а strict_types включается осознанно), возвращаемые типы, операторы ?? (null coalescing) и <=> (spaceship), анонимные классы, метод Closure::call(), делегирование итерации через yield from и явный return из генератора с чтением результата через Generator::getReturn(), функции intdiv(), криптографически стойкие random_bytes() / random_int(), ограниченный unserialize() с белым списком классов и preg_replace_callback_array().
Под капотом сотни сценариев, которые раньше заканчивались fatal, превращаются в Error и родственные типы в иерархии Throwable. Обработчик, зарегистрированный через set_exception_handler, если он типизирован как Exception, при первом же TypeError или ParseError может сам вызвать новый fatal — миграцию фронт-контроллеров и логгеров стоит спланировать заранее.
Оглавление
- Скалярные типы и
strict_types - Возвращаемые типы
- Оператор
?? - Оператор
<=> - Анонимные классы
Closure::call()- Генераторы:
yield fromи возврат значения intdiv(), CSPRNG и опцииunserialize- Групповой импорт
use - Практические рецепты
- Обратная несовместимость (обзор)
- Удалённые расширения и SAPI
- Deprecated
- Прочие миграционные нюансы
Скалярные типы и strict_types
К параметрам можно добавлять string, int, float, bool наряду с уже привычными классами, array и callable. Если файл не начинается с declare(strict_types=1);, движок ведёт себя в духе «мягкой» типизации: строка "42" спокойно дойдёт до параметра int. Включили strict_types — любое несоответствие превращается в TypeError, без тихих приведений.
declare(strict_types=1);
function increment(int $x): int {
return $x + 1;
}
Возвращаемые типы
У функций и методов можно объявить тип результата. Возврат null, если он не разрешён сигнатурой, или значение «не того» типа даёт TypeError. (Тип void и связанные с ним правила приходят уже в PHP 7.1 — на 7.0 речь о значениях, которые реально возвращаются.)
Оператор ??
$name = $_GET['name'] ?? 'guest';
Левая часть проверяется на существование и не-null без всплывающих notice для несуществующих ключей — удобнее и короче, чем вложенные isset() ? … : ….
Оператор <=>
Возвращает -1, 0 или 1 в зависимости от соотношения операндов — естественная основа для компараторов в usort(), usort() с составными ключами и любых трёхзначных сравнений.
usort($rows, function ($a, $b) {
return $a['score'] <=> $b['score'];
});
Анонимные классы
Удобно подставлять разовую реализацию интерфейса без отдельного файла класса — например, логгер или стаб в тестах.
$logger = new class implements LoggerInterface {
public function log($level, $message, array $context = []) { /* … */ }
};
Closure::call()
Временно привязывает $this и сразу вызывает замыкание — меньше шума, чем связка bindTo() + __invoke().
$getter = function () { return $this->value; };
$getter->call($object);
Генераторы: yield from и возврат значения
yield fromпередаёт управление другому генератору, массиву или объектуTraversableбез ручного цикла.return $итог;внутри генератора после завершения итерации доступен вызывающему коду через$gen->getReturn()(пока генератор не исчерпан, метод недоступен).
intdiv(), CSPRNG и опции unserialize
intdiv($a, $b)— целочисленное деление; деление на ноль бросаетArithmeticError.random_bytes()/random_int()дают кроссплатформенный CSPRNG — для токенов, сессий и соли предпочтительнееmt_rand().unserialize($data, ['allowed_classes' => ['My\DTO']])ограничивает, какие классы могут восстановиться из потока — базовая защита от «неожиданных» объектов в данных.
Групповой импорт use
use Foo\Bar\{Baz, Qux};
Сокращает вертикаль из однотипных use при работе с одним пространством имён.
Практические рецепты
Безопасные значения из запроса
$limit = (int) ($_GET['limit'] ?? 25);
Сортировка по строковому ключу
usort($items, function ($a, $b) {
return strcmp($a['id'], $b['id']);
});
Обратная несовместимость (обзор)
Полный перечень — в официальном migration70 incompatible. Ниже — то, что чаще всего «стреляет» в легаси без статического анализа.
Ошибки и исключения
- Появилась иерархия
Throwable; многие бывшие fatal сталиError,TypeError,ParseError. - Обработчик
set_exception_handler(function (Exception $e) { … })на PHP 7 ломается, если прилетаетError— сигнатура должна бытьThrowableили без типа.
Парсер и переменные
- Косвенный доступ вроде
$$foo['bar']['baz']разбирается строго слева направо. Чтобы сохранить семантику PHP 5, расставьте фигурные скобки явно, как в таблице мануала. list()присваивает в порядке перечисления переменных (не в обратном, как в старых версиях). Пустойlist()запрещён. Строку черезlist()распаковать нельзя — толькоstr_split()и аналоги.
Массивы, foreach, ссылки
- Порядок элементов при автоматическом создании через ссылочные присваивания отличается от PHP 5 — перепроверьте хаки с
$a['x'] =& $a['y']. foreachбольше не двигает внутренний указатель массива так, как раньше; итерация по значению идёт по копии массива.- Лишние скобки вокруг аргумента не заглушают предупреждение «Only variables should be passed by reference».
Строки и числа
- Шестнадцатеричные строки
"0xFF"в числовом контексте не интерпретируются как числа автоматически. - Сложные конструкции
"${...}"в двойных кавычках изменились — шаблоны с подстановкой переменных стоит прогнать по тестам.
Текст в UTF-8
substr(),strlen()и соседи работают в байтах. Для пользовательского текста комбинируйте сmb_*.
Детали по конкретным расширениям (удаление mysql, ereg и т.д.) — в разделе removed.
Удалённые расширения и SAPI
Из поставки исчезают mysql, семейство ereg*, ряд редких драйверов и устаревших SAPI — см. migration70 removed. Практичный маршрут: mysqli или PDO вместо mysql_*, preg_* вместо ereg_*.
Deprecated
Конструкторы «в стиле PHP 4» с именем класса, статические вызовы не-static методов, ручная соль в password_hash(), ldap_sort(), опция capture_session_meta у SSL-контекста и другие пункты — migration70 deprecated.
Прочие миграционные нюансы
- У
assert()появляется режим expectations и директиваzend.assertions; строковый аргумент уassert()в последующих 7.x всё больше считается легаси. - Проверьте удалённые INI, поведение
json_encode/json_decodeпри ошибках и отсутствие функцииsplit()— заменаpreg_split()илиexplode().
Итог
Переезд 5.x → 7.0 — отдельный этап: статанализ, замена mysql/ereg, единая точка catch (Throwable $e) на входе приложения и регрессия по list()/foreach. Когда 7.0 стабилен, миноры 7.1+ идут уже более предсказуемыми шагами — nullable-типы, затем предупреждения count() в 7.2, затем JSON-исключения и heredoc в 7.3.