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

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

Скалярные типы объявляют в двух режимах: нестрогом, в котором 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) {
    }

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

### Синтаксис экранирования кодовых точек Юникода

Синтаксис принимает кодовую точку Юникода в шестнадцатеричном формате, которую записали в кодировке UTF-8 как строку в двойных кавычках или heredoc-синтаксисом, и выводит эту кодовую точку в формате UTF-8. Синтаксис примет каждую допустимую кодовую точку. Ведущие нули в шестнадцатеричной последовательности указывать необязательно.

    <?php

    echo "\u{aa}", PHP_EOL;
    echo "\u{0000aa}", PHP_EOL;

    echo "\u{9999}", PHP_EOL;

    echo <<<EOT
    \u{01f418}
    EOT;

    ?>

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

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

### 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

Явно получать конечное значение генератора полезно, поскольку разрешает клиентскому коду, который запустил генератор, получать и обрабатывать финальное значение генератора (возможно, из какой-то формы сопрограммных вычислений). Это значительно проще, чем заставлять клиентский код проверять, последнее ли значение вернул генератор, а затем, если это так, отдельно обрабатывать значение.

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

Теперь генераторы за счёт конструкции `yield from` умеют автоматически делегировать выдачу значений другому генератору, Traversable-объекту или массиву без написания шаблонного кода во внешнем генераторе.

    <?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()`.

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open