Путеводитель по нововведениям PHP 7.0 и 7.1

Два месяца назад я перешёл на PHP7 и в этом посте хочу поделиться нововведениями, которые пришлись по нраву мне больше всего. Во первых, переход на новую ветку PHP обусловлен приростом производительности и уменьшением потребляемых ресурсов, т. е. крупные сайты с PHP7 могут в два раза снизить расходы на хостинг и быстрее генерировать веб-страницу конечному пользователю. Здесь выигрывают сразу и владельцы сайтов, и их посетители.

Это сравнение скорости между версиями 5.6 и 7.0 на различных платформах. Zend Framework даёт прирост скорости на 133%, а WordPress — 129%. Такое улучшение PHP имеет позитивные последствия для бизнеса.

В прошлом году Badoo, WordPress.com, Tumblr и многие другие гиганты перешли на PHP7. Так, например, компании Badoo за счёт снижения CPU в два раза и уменьшения потребления памяти в 8 раз удалось сэкономить 1 млн долларов. Сайт WordPress.com также полностью переведён на PHP7, где прирост производительности действительно заметен:

Быстродействие в новых версиях стало самым крутым и обсуждаемым нововведением. Теперь не нужно заморачиваться по оптимизации каких-то участков кода, а сразу писать понятный и поддерживаемый код. Во вторых, в PHP 7.0 и 7.1 введено большое количество улучшений на уровне синтаксиса и функциональности. Далее на примерах я покажу, что мне понравилось в новых версиях и как эти нововведения поменяют язык PHP в будущем на уровне кода.

Замена тернарного оператора

На замену тернарного оператора пришёл «оператор объединения с null» или «null-коалесцентный оператор». Через два знака вопроса (??) можно указать цепочку значений в одну строку и будет выбрано первое значение, которое не равно null. Раньше этот подход применялся вместе с функцией isset(). Сейчас можно указать даже не существующие переменные и не мучатся c большой вложенностью как с тернарным оператором.

<?php

// PHP 5.6
$test = isset($foo) ? $foo : null;

// PHP 7+
$test = $foo ?? null;

/* ... */

// PHP 5.6
$test = isset($foo) ? $foo : (isset($bar) ? $bar : null);

// PHP 7+
$test = $foo ?? $bar ?? null;

/* ... */

// PHP 7+
someFunction($unknownVariable ?? 'default');

Оператор объединения с null
Тернарный оператор и оператор null-coalescing

Групповое объявление классов, констант и функций

Начиная с версии 7.0 появилась возможность группировать объявления импорта классов, функций и констант, находящиеся в одном пространстве имён, в одной строке с помощью оператора use. Это нововведение на уровне синтаксического сахара, которое может наделить объявление имён каких-то компонентов определённой логикой.

<?php

// PHP 5.6
use App\Bundle\Foo;
use App\Bundle\Bar;
use App\Bundle\Baz as B;

// PHP 7+
use App\Bundle\{Foo, Bar, Baz as B};

// или

use App\Bundle\{
    Foo,
    Bar,
    Baz as B
};

/* ... */

// PHP 5.6
use const app\namespace\ru_RU;
use const app\namespace\en_US;
use function app\namespace\firstFunc;
use function app\namespace\secondFunc;

// PHP 7+
use const app\namespace\{ru_RU, en_US};
use function app\namespace\{firstFunc, secondFunc};

Групповые декларации use

Декларация типов и возвращаемых значений

Это самое мощное нововведение для ООП. Теперь при объявлении метода для каждой переменной можно указать свой тип, а также тип данных, который вернёт этот метод. В PHP 7.0 доступны следующие типы: array, callable, bool, float, int, string, имя класса или интерфейса. В версии 7.1 добавили ещё void и iterable. Тип void можно использовать только в возвращаемых значениях функций, которые ничего не возвращают. Псевдо-тип iterable используется в качестве значения массива или объекта, реализующего интерфейс Traversable.

<?php

class Foo
{
    public static function bar(int $a, float $b, string $c) : int
    {
        return $a + $b + $c;
    }
}

// вернёт int(6)
var_dump( Foo::bar('1', 2, 3.0) );

В примере выше отработала принуждающая декларация типов, т. е. PHP динамически привёл значения к нужному типу, когда в переменную с объявленным типом int мы передали string, например. Вместо того, чтобы сгенерировать ошибку, все значения переменных и результат функции был преобразован к указанному типу на лету. Это поведение установлено по умолчанию.

Строгую типизацию можно включить, если в начале скрипта прописать declare(strict_types=1). Все значения должны полностью соответствовать указанным типам. В противном случае будет сгенерирована ошибка TypeError. Строгая типизация не затрагивает весь остальной код и её нужно прописывать для каждого скрипта отдельно.

<?php

// включили строгую типизацию
declare(strict_types=1);

class Foo
{
    public static function bar(int $a, int $b) : int
    {
        return $a + $b;
    }
}

// вернёт ошибку TypeError, т. к.
// первый аргумент является string,
// а должен int
var_dump( Foo::bar('1', 2) );

// вернёт int(3)
var_dump( Foo::bar(1, 2) );

В версии 7.1 появилась возможность обнулить возвращаемые типы. Это расширяет список возвращаеммых типов до null. Теперь функция может вернуть какой-то явно указанный тип или null. Достигается такое поведение путём добавления префикса в виде знака вопроса к указанному типу:

<?php

declare(strict_types=1);

class Foo
{
    public static function bar(?string $name) : ?string
    {
        return $name;
    }
}

// string(13) "Hello, world!"
var_dump( Foo::bar('Hello, world!') );

// NULL
var_dump( Foo::bar(null) );

// string(0) ""
var_dump( Foo::bar('' ?? null) );

// NULL
var_dump( Foo::bar($unknownVariable ?? null) );

// вернёт ошибку TypeError
var_dump( Foo::bar(1) );

// вернёт ошибку ArgumentCountError
var_dump( Foo::bar() );

Декларация типов и возвращаемых значений выводит PHP на новый уровень и эти нововведения мне нравятся больше всего, т. к. со стороны разработчика повышается читабельность кода; чёткая согласованность входных и выходных данных; программист может быстрее понять, чего ожидать от функции; легче документировать код; появляется возможность изменять типы данных на лету. Это основополагающая функциональность PHP7, которой не знать уже сейчас недопустимо.

Декларация скалярных типов
Декларация возвращаемых значений
Обнуляемые типы
Ничего не возвращающие функции
Псевдо-тип iterable

Обработка ошибок и исключений

В PHP 7.0 появился новый класс для внутренних ошибок Error и интерфейс исключений Throwable. Теперь Error и старый класс Excetion реализуют Throwable (пользовательские классы не могут реализовывать данный интерфейс). Exception можно использовать для отлова исключений, которые будут обработаны и выполнение программы продолжится. Класс Error служит для необратимых исключений и выбрасывается в случае ошибки PHP или на уровне ошибок разработчиков.

Большинство ошибок уровня E_ERROR или E_RECOVERABLE_ERROR будут выбрасывать Error, но некоторые будут выбрасывать объекты подклассов: ArithmeticError, AssertionError, ParseError, DivisionByZeroError, TypeError и ArgumentCountError (с версии 7.1). Эти подклассы ошибок не могут быть брошены самостоятельно, а только лишь словлены. Иерархию всех исключений можно представить в виде дерева:

┌Throwable
├──Error
│  ├──ArithmeticError
│  ├──AssertionError
│  ├──DivisionByZeroError
│  ├──ParseError
│  ├──TypeError
│  └──ArgumentCountError
└──Exception
   ├──ErrorException
   ├──LogicException
   │  ├──BadFunctionCallException
   │  │  └──BadMethodCallException
   │  ├──DomainException
   │  ├──InvalidArgumentException
   │  ├──LengthException
   │  └──OutOfRangeException
   └──RuntimeException
      ├──OutOfBoundsException
      ├──OverflowException
      ├──RangeException
      ├──UnderflowException
      └──UnexpectedValueException

Начиная с версии 7.1 появилась возможность в блоке catch обрабатывать сразу несколько исключений, перечисляя их через символ вертикальной черты. Может быть полезно для обработки одинаковых по логике ошибок или пользовательских исключений.

<?php

try {
    /*
     * код программы
     */
} catch (
    ParseError         |
    TypeError          |
    ArgumentCountError $e
) {
    /*
     * ловим три вида ошибок PHP в одном блоке
     */
} catch (AppException | UserException $e) {
    /*
     * ловим пользовательские исключения
     */
} catch (Exception $e) {
    /*
     * ловим остальные исключения
     */
} catch (Throwable $t) {
    /*
     * ловим и логируем все ошибки и исключения
     */
}

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

Предопределённые исключения
Изменения в обработке ошибок и исключений
Обработка нескольких исключений в одном блоке catch

Остальные нововведения одним списком

Нововведения в PHP7+ это лишь начало большого перехода на новый уровень языка. С каждым релизом приложения будут становиться быстрее и безопаснее. На версии 7.0 и 7.1 нужно отреагировать уже сегодня и будь в курсе новых тенденций PHP, дабы не выпадать из сферы. Ниже привожу одним списком остальные нововведения:

7.0 Оператор spaceship (космический корабль)
7.0 Задание констант массивов с помощью define()
7.0 Появились анонимные классы
7.0 Синтаксис кодирования Unicode
7.0 Добавлен метод в замыкания Closure::call()
7.0 unserialize() с фильтрацией
7.0 Новый класс IntlChar
7.0 Улучшена старая функция assert()
7.0 Выражение return в генераторах
7.0 Делегация генератора с помощью конструкции yield from
7.0 Новая функция intdiv() для целочисленного деления
7.0 session_start() принимает массив опций
7.0 Новая функция preg_replace_callback_array()
7.0 Новые функции random_bytes() и random_int()
7.0 list() может раскрывать объекты реализующие ArrayAccess
7.0 Обращение к методам и свойствам класса при клонировании (clone $foo)->bar()
7.1 Короткий синтаксис для list()
7.1 Публичные и приватные константы классов
7.1 Поддержка ключей в list()
7.1 Поддержка отрицательных смещений для строк
7.1 Расширены функции openssl_encrypt() и openssl_decrypt()
7.1 Преобразование callable в Closure с помощью Closure::fromCallable()
7.1 Новая функция pcntl_async_signals()
7.1 Поддержка Server Push в CURL 7.46

Дополнительное чтиво

Миграция из PHP 5.6.x к PHP 7.0.x
Миграция из PHP 7.0.x к PHP 7.1.x
Сравнение скорости для различных фреймворков в PHP7
Инфографика: Turbocharging the Web with PHP7
Введение в PHP 7: что добавлено, что убрано
PHP 7.1: обзор новых возможностей
Return types и Scalar type в PHP7
Throwable исключения и ошибки в PHP7

Поделиться
Отправить
6 комментариев
dj

Мощно!

seoonly.ru

Благодарю, бро!

Alex Black

Ох, новых знаний прибавилось.

dj

Новые знания тянут все новые знания.

Eskono

// PHP 5.6
$test = isset($foo) ? $foo : (isset($bar) ? $bar : null);
// PHP 7+
$test = $foo ?? $bar ?? null;

в 5.6 можно проще записать)
$test = $foo ?: $bar ?: null;

Александр Денисюк

Тогда вылезет две ошибки, если переменных $foo и $bar не существует:
Notice: Undefined variable: foo
Notice: Undefined variable: bar
https://3v4l.org/fPnsU

Их конечно можно не показывать, но лучше писать валидный код.

Виталий

все хорошо и доходчиво расписано, залинкую.

но в глаза кинулись 2 минуса (для простого смертного веб разработчика) которые в плюсах:

  1. >> крупные сайты с PHP7 могут в два раза снизить расходы на хостинг
    крупные да, но к примеру тот же wordpress, шаре хостинг на 7 версию не скоро перейдет, самый дешевый vps как минимум в 1,5 раза дороже
  2. >> Теперь не нужно заморачиваться по оптимизации каких-то участков кода, а сразу писать понятный
    как правило если не заморачиваться, то тут и php 7 не поможет ((, так что ... лучше писать заморачиваясь и изначально думать о том как будет работать функционал на 5.Х и шаре хостинг

радует что php становится все больше строго типизированным языком программирования!

Александр Денисюк

Забудьте про шаред хостинги, используйте https://elasticweb.org/ru
За полгода я заплатил 2 бакса. Это хостинг с оплатой за использованные ресурсы.

Ваш комментарий
адрес не будет опубликован

ХТМЛ не работает

Ctrl + Enter
Популярное