Что нового в PHP 7.2?

    Несмотря на то, что мы активно работаем с Python и Go, всё же существенная часть нашего серверного кода написана на PHP. Поэтому мы внимательно следим за всеми нововведениями языка. Прошло меньше года после релиза предыдущей минорной версии, и вот уже последний бета-релиз запланирован на 17 августа. Его ещё не рекомендуется использовать в production, но уже можно скачать docker-образ. Пора разбираться, что изменилось в новой версии языка.



    Содержание



    Оптимизация


    В Opcache добавлена глобальная оптимизация на основе анализа потока данных с использованием SSA (Static single assignment form): Sparse Conditional Constant Propagation (SCCP), удаление мертвого кода (Dead Code Elimination — DCE) и удаление неиспользуемых локальных переменных.


    Оптимизирована работа встроенной функции in_array() с помощью поиска хеша в перевернутом массиве.


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


    Добавлена возможность загружать расширения по имени (RFC)


    Раньше extension= и zend_extension= в файле php.ini содержали пути до файла расширения.
    Но, к сожалению, имя файла зависело от платформы. Например, в unix-подобных системах оно строилось как <extension-name>.<suffix>, где suffix это .so на всех системах кроме HP-UX, где он sl. В Windows имя файла формируется как php_<extension-name>.dll. Всё это порождало много ошибок.


    Теперь вы можете писать:


    extension=bz2
    zend_extension=xdebug

    И нужные расширения будут подгружены в зависимости от ОС.


    Этот механизм будет работать при установке extension и zend_extension в ini-файле, а также как аргумент для функции dl().


    Но абсолютные пути по-прежнему необходимо будет указывать при флаге -z в CLI-режиме, а также при указании абсолютного пути. Следующий пример работать не будет:


    extension=/path/to/extensions/bz2


    Добавлена возможность перегружать абстрактные функции (RFC)


    Теперь вы сможете перегрузить абстрактные функции точно так же, как и обычные функции:


    abstract class A           { abstract function bar(stdClass $x);  }
    abstract class B extends A { abstract function bar($x): stdClass; }
    class C extends B          { function bar($x): stdClass{} }

    До PHP 7.2 выдавалась ошибка вида:


    Fatal error: Can't inherit abstract function A::bar() (previously declared abstract in B)


    Запрещено number_format() возвращать -0 (RFC)


    Вызов number_format(-0.00)возвращал string(1) “0”, однако number_format(-0.01) возвращал string(2) “-0”. Сейчас же будет возвращен 0 без знака.


    Добавлена возможность конвертировать нумерованные ключи при приведении типов object/array (RFC)


    Предыстория:


    В PHP есть два типа данных, которые содержат ключ/значение. Первый — это массивы, которые могут содержать ключи в виде строк или чисел. При этом если строка удовлетворяет правилу /^(0|(-?[1-9][0-9]*))$/ и она достаточно маленькая PHP_INT_MIN ≤ n ≤ PHP_INT_MAX, то она конвертируется в числовой ключ.


    Второй тип — это объекты, в которых недопустимы числовые ключи, и ключи конвертируются в строки.


    При этом в Zend Engine они представлены в виде одной структуры HashTable.


    Теперь это исправлено.


    Давайте посмотрим на пару примеров:


    $obj = new stdClass;
    
    $obj->{'0'} = 1;
    $obj->{'1'} = 2;
    $obj->{'2'} = 3;
    $arr = (array) $obj;
    
    var_dump($arr); // Видим, что массив содержит ключи/значения
    var_dump($arr[1]); // Не можем обратиться по ключу. В PHP 7.2 это исправлено.

    $arr = [0 => 1, 1 => 2, 2 => 3];
    $obj = (object)$arr;
    
    var_dump($obj); // Видим, что объект содержит ключи/значения
    var_dump($obj->{'0'}); // Не можем обратиться по ключу. В PHP 7.2 это исправлено.

    Запрещено передавать null в качестве параметра для get_class() (RFC)


    Когда null передается как параметр get_class() внутри контекста класса, поведение функции может быть весьма неожиданным:


    class Foo
    {
        function bar($repository)
        {
            $result = $repository->find(100);
            return get_class($result);
        }
    }

    Если $result содержит действительный объект, возвращенный из репозитория, результатом функции будет имя класса этого объекта.


    Если $result содержит null, выход будет иметь контекст класса, из которого вызывается get_class(), в этом случае Foo.


    Эта особенность нарушает принцип наименьшего удивления: «если необходимая функция имеет высокий коэффициент удивления, может потребоваться перепроектирование этой функции».
    Теперь будет выдаваться предупреждение:
    Warning: get_class() expects parameter 1 to be object, null given in %s on line %d
    Если вы хотите сохранить старое поведение, придётся переписать код:


    // Было:
    $x = get_class($some_value_that_may_be_null);
    
    // Стало:
    if ($some_value_that_may_be_null === null) {
        $x = get_class();
    } else {
        $x = get_class($some_value_that_may_be_null);
    }

    Вызов Count с параметром, который нельзя посчитать (RFC)


    Теперь вызов count() с параметром, который является скалярным, null или объектом, который не реализовал интерфейс Countable, будет выдавать Warning.


    Возможность расширения типа параметра (RFC)


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


    class ArrayClass {
      public function foo(array $foo) { /* ... */ }
    }
    
     class EverythingClass extends ArrayClass {
      public function foo($foo) { /* ... */ }
    }

    До PHP 7.2 возвращалась ошибка:


    Warning: Declaration of EverythingClass::foo($foo) should be compatible with ArrayClass::foo(array $foo) in %s on line 18

    В пулл реквесте мнения разделились.
    Одни говорили:


    "Конечно, давайте отправим SOLID в ад. Кто такая Барбара Лисков??? Какая-то безумная женщина? Конечно! Давайте разрешим ломать принципы и идеи".

    Другие считают, что:


    "Ограничения вроде принципа единой ответственности (single responsibility) должны быть реализованы не на уровне языка, а в коде приложения. И теперь и буква L в SOLID будет на усмотрение разработчика".

    Добавлена возможность указывать запятую в конце группированных неймспейсов (RFC)


    // Раньше это работало только для массивов
    $array = [1, 2, 3,];
    
    // Теперь и для группировки неймспейсов
    use Foo\Bar\{ Foo, Bar, Baz, };

    Планировалось добавить такую возможность и для других списков, но на стадии голосования они были отменены и будут по-прежнему возвращать Parse error:


    // Аргументы функций и методов
    fooCall($arg1, $arg2, $arg3,);
    
    // Перечисление реализуемых интерфейсов
    class Foo implements
        FooInterface,
        BarInterface,
        BazInterface,
    {
        // Перечисление трейтов
        use
            FooTrait,
            BarTrait,
            BazTrait,
        ;
    
        // Перечисление свойств и констант
        const
            A = 1010,
            B = 1021,
            C = 1032,
            D = 1043,
        ;
        protected
            $a = 'foo',
            $b = 'bar',
            $c = 'baz',
        ;
        private
            $blah,
        ;
    
        // Декларация функций и методов
        function something(FooBarBazInterface $in, FooBarBazInterface $out,) : bool
        {
        }
    }
    
    // Наследование переменных из родительской области в анонимных функциях
    $foo = function ($bar) use (
        $a,
        $b,
        $c,
    ) {
        // . . . 
    };

    Реализовано семейство функций socket_getaddrinfo (RFC)


    Теперь из PHP будет доступна информация из getaddrinfo(), реализованная на C. Это недостающая функция для текущей библиотеки сокетов. При работе с различными сетями было бы полезно разрешить libc рассказать нам, какие методы подключения/прослушивания будут наиболее подходящими с учетом набора подсказок.


    Были утверждены четыре функции:


    socket_addrinfo_lookup(string node[, mixed service, array hints]) : array
    socket_addrinfo_connect(resource $addrinfo) : resource
    socket_addrinfo_bind(resource $addrinfo) : resource
    socket_addrinfo_explain(resource $addrinfo) : array

    Улучшены TLS-константы (RFC)


    Теперь:


    • tls:// имеет дефолтное значение TLSv1.0 + TLSv1.1 + TLSv1.2
    • ssl:// это алиас к tls://
    • константа STREAM_CRYPTO_METHOD_TLS_* имеет дефолтное значение TLSv1.0 + TLSv1.1 + TLSv1.2 вместо TLSv1.0
    • константа STREAM_CRYPTO_METHOD_SSLv23_CLIENT считается устаревшей и позже будет удалена.

    Object typehint (RFC)


    Добавлен новый тип для хинта: object


    function acceptsObject(object $obj) {
        // ...
    }
    
    acceptsObject(json_decode('{}')); 
    acceptsObject(new \MyObject());
    acceptsObject("Будет ошибка");
    
    function correctFunction() : object {
        $obj = json_decode('{}');
        return $obj;
    }
    
    // Будет ошибка
    function errorFunction() : object {
        return [];
    }

    LDAP EXOP (RFC)


    Добавлены функции для использования расширенных операций LDAP в php-ldap.


    // Вызов EXOP whoami и сохранение результатов в $identity
    if (ldap_exop($link, LDAP_EXOP_WHO_AM_I, NULL, $identity)) {
      echo "Connected as $identity\n";
    } else {
      echo "Operation failed\n";
    }
    // Делаем то же самое, используя объект результата:
    $r = ldap_exop($link, LDAP_EXOP_WHO_AM_I);
    if (($r !== FALSE) && ldap_parse_exop($link, $r, $retdata)) {
      echo "Connected as $retdata\n";
    } else {
      echo "Operation failed\n";
    }
    // То же самое с хелпером:
    if (ldap_exop_whoami($link, $identity)) {
      echo "Connected as $identity\n";
    } else {
      echo "Operation failed\n";
    }
    // Изменение пароля с хелпером:
    if (ldap_exop_passwd($link, 'uid=johndoe,dc=example,dc=com', '', 'newpassword')) {
      echo "Password changed\n";
    } else {
      echo "Operation failed\n";
    }

    В ядро PHP добавлена Libsodium (RFC)


    Libsodium — современная криптографическая библиотека, которая предлагает аутентифицированное шифрование, высокоскоростную криптографию с эллиптическими кривыми и многое другое. В отличие от других криптографических стандартов (которые являются набором криптографических примитивов, например, WebCrypto), libsodium включает в себя тщательно подобранные алгоритмы, реализованные экспертами по безопасности. Это поможет избежать уязвимостей в сторонних каналах.


    Добавлен алгоритм Argon2 в хешировании пароля (RFC)


    Argon2 — это современный простой алгоритм, направленный на высокую скорость заполнения памяти и эффективное использование нескольких вычислительных блоков.


    HashContext as Object (RFC)


    Начиная с PHP5 предпочтительной структурой для хранения внутренних данных были объекты. По какой-то причине в расширении Hash для этого использовались ресурсы. Данный RFC пытается исправить недоразумение, переведя расширение Hash на хранение внутренних данных в виде объектов.


    Примеры использования ресурса в качестве внутреннего представления:


    resource hash_copy ( resource $context )
    resource hash_init ( string $algo [, int $options = 0 [, string $key = NULL ]] )

    Внутреннее представление преобразуется из ресурса в объект. Существующий код должен продолжить работать, если он не использует явных проверок is_resource(), эти проверки могут быть легко заменены на is_resource | is_object.


    Добавлен отладчик PDO Prepared statements (RFC)


    $db = new PDO(...);
    
    $stmt = $db->query('SELECT 1');
    var_dump($stmt->activeQueryString()); // => string(8) "SELECT 1"
    
    $stmt = $db->prepare('SELECT :string');
    $stmt->bindValue(':string', 'foo');
    
    // возвращает необработанную строку до выполнения
    var_dump($stmt->activeQueryString()); // => string(14) "SELECT :string"
    
    // возвращает обработанную строку после выполнения
    $stmt->execute();
    var_dump($stmt->activeQueryString()); // => string(11) "SELECT 'foo'"

    Добавлен отладчик PDO Prepared statements v2 (RFC)


    $calories = 150;
    $colour = 'red';
    
    $sth = $dbh->prepare('SELECT name, colour, calories
        FROM fruit
        WHERE calories < ? AND colour = ?');
    $sth->bindParam(1, $calories, PDO::PARAM_INT);
    $sth->bindValue(2, $colour, PDO::PARAM_STR);
    $sth->execute();
    
    $sth->debugDumpParams();
    
    /*
    Вывод:
    
    SQL: [82] SELECT name, colour, calories
        FROM fruit
        WHERE calories < ? AND colour = ?
    Sent SQL: [88] SELECT name, colour, calories
        FROM fruit
        WHERE calories < 150 AND colour = 'red'
    Params:  2
    Key: Position #0:
    paramno=0
    name=[0] ""
    is_param=1
    param_type=1
    Key: Position #1:
    paramno=1
    name=[0] ""
    is_param=1
    param_type=2
    */

    Расширенные типы строк для PDO (RFC)


    $db->quote('über', PDO::PARAM_STR | PDO::PARAM_STR_NATL); // N'über'
    $db->quote('A'); // 'A'
    
    $db->setAttribute(PDO::ATTR_DEFAULT_STR_PARAM, PDO::PARAM_STR_NATL);
    $db->quote('über'); // N'über'
    $db->quote('A', PDO::PARAM_STR | PDO::PARAM_STR_CHAR); // 'A'

    Добавлены опции JSON_INVALID_UTF8_IGNORE и JSON_INVALID_UTF8_SUBSTITUTE (Request)


    Для функций json_encode / json_decode добавлены новые опции JSON_INVALID_UTF8_IGNORE и JSON_INVALID_UTF8_SUBSTITUTE для игнорирования или замены некорректных последовательностей байтов UTF-8.


    Удалено из PHP 7.2


    Следующий функционал объявлен устаревшим и был удален.


    Удалены строки без кавычек (bare word) (RFC)


    Строки без кавычек теперь вызывают E_WARNING. В PHP2 такие строки вызывали Syntax error, но в PHP3 бета-поведение было изменено.
    К примеру:


    $foo = flase; // Опечатка, но раньше вызывалась ошибка E_NOTICE, которую часто отключали.  
    // ...
    if ( $foo ) {
       var_dump($foo); // string(5) "flase"
    }

    Перенос mcrypt в PECL


    Расширение mcrypt, объявленное устаревшим в PHP 7.1, было перемещено в PECL.


    Объявлено устаревшим в PHP 7.2 (RFC)


    Следующий функционал объявлен устаревшим и больше не рекомендуется к использованию.
    Этот функционал будет удален в версии 8.0.


    Устарел __autoload


    Функция __autoload была заменена на spl_autoload_register ещё в версии 5.1.
    Основным преимуществом spl_autoload_register является возможность использовать несколько автозагрузчиков. Теперь будет выбрасываться Deprecation notice на стадии компиляции.


    Устарели png2wbmp() и jpeg2wbmp()


    Png2wbmp() и jpeg2wbmp() — единственные функции, изменяющие формат изображений, которые можно вызвать напрямую, доступные в ext / gd, что делает их довольно обособленными, поскольку libgd не предлагает таких функций. Кроме того, WBMP был изобретен для поддержки WAP, который в настоящее время устарел. Теперь будет выбрасываться Deprecation notice.


    Устарела $php_errormsg


    Переменная $php_errormsg создается в локальной области при возникновении нефатальной ошибки, если параметр track_errors включен (отключен по умолчанию), и ошибка не перехватывалась никаким обработчиком ошибок.


    Помимо того, что поведение зависело от настроек ini-файла, оно также было магическим. Функция error_get_last обеспечивает более чистый способ получения последней ошибки. С PHP 7 доступна функция error_clear_last, таким образом, охватываются все возможные варианты использования $php_errormsg без манипуляции с областями видимости.


    Устарела create_function()


    create_function() — это тонкая оболочка вокруг конструкции языка eval(), позволяющая создавать функцию со сгенерированным именем, списком аргументов и телом в виде строковых аргументов. До введения замыканий в PHP 5.3 она обеспечивала способ создания чего-то похожего на лямбда-функции.


    Из-за характера работы create_function(), помимо потенциального источника проблем безопасности, имеет очень плохие характеристики производительности и использования памяти. Использование реальных замыканий во всех отношениях предпочтительнее.


    Устарел mbstring.func_overload


    Параметр mbstring.func_overload в ini-файле позволяет заменить определенное подмножество строковых функций на аналоги с расширением mbstring. Например, strlen() больше не будет возвращать длину строки в байтах, вместо этого она вернет длину в символах в соответствии с текущей выбранной внутренней кодировкой.


    Это означает, что код с использованием mbstring.func_overload не совместим кодом, написанным в предположении, что основные операции со строками работают нормально. Некоторые библиотеки прямо запрещают func_overload (например, Symfony), другие библиотеки перестают работать. Код, который хочет поддерживать func_overload, должен условно переключаться между обычными строковыми функциями и функциями mbstring с 8-битным кодированием (обычно только библиотеки для криптографии пытаются это сделать).
    Теперь будет выбрасываться Deprecation notice если mbstring.func_overload содержит ненулевое значение.


    Устарел (unset) cast


    Каст (unset) превращает значение в null. Это означает, что (unset) expr — просто выражение, которое всегда возвращает null и не имеет других побочных эффектов.
    Помимо бесполезности, это поведение только путает, так как многие люди разумно предполагают, что (unset) $a будет вести себя аналогично unset($a), а на самом деле этого не происходит.
    Теперь будет выбрасываться Deprecation notice на стадии компиляции.


    Устарела функция parse_str() без второго аргумента


    Функция parse_str() разбирает строку URL и присваивает значения переменным в текущем контексте (или заносит в массив, если задан параметр result).


    Использовать эту функцию без параметра result крайне не рекомендовалось, потому что динамическое создание переменных в области видимости функции ведет ровно к тем же проблемам, что и register_globals. Теперь выбрасывается Deprecation notice, если параметр result не передается.


    Устарела функция gmp_random()


    Функция gmp_random() генерирует случайное число. Число будет в диапазоне нуля до произведения числа limiter на количество бит в лимбе (limb). Если число limiter отрицательное, будет возвращен отрицательный результат.


    Лимб — внутренний GMP-механизм. Технически это часть числа, помещающаяся в одно машинное слово. Количество бит в нем может различаться в разных системах. В основном это либо 16, либо 32, но это не гарантируется. Так происходит, потому что реализация GMP/MPIR не доступна пользователю. Таким образом, использование этой функции требует угадывания размера Лимба и может зависеть от платформы.


    Чтобы исправить это, в PHP 5.6 добавили функции gmp_random_bits() и gmp_random_range(), которые позволяют точно контролировать используемый диапазон случайных чисел. Эти функции всегда должны быть предпочтительнее, чем gmp_random().
    Теперь при вызове gmp_random() выбрасывается Deprecation notice.


    Устарела функция each()


    Функция each() может использоваться для итерации по массиву, подобно foreach. В каждом вызове он возвращает массив с текущим ключом и значением и продвигает указатель внутреннего массива на следующую позицию. Типичное использование, представленное в руководстве, выглядит следующим образом:


    reset($array);
    while (list($key, $val) = each($array)) {
        echo "$key => $val\n";
    }

    Функция each уступает foreach практически во всём, среди прочего она в 10 раз медленнее.
    Поддержка этой функции создает проблему для некоторых изменений языка. Например, в предупреждении для невалидного контейнера массива (RFC) пришлось исключить list(), потому что типичное использование each полагается на факт, что вы можете получить доступ к смещениям массива на false без предупреждения.


    Теперь выбрасывается Deprecation warning при первом вызове each, потому что чаще всего он используется в цикле.


    Устарела функция assert() со строковым аргументом


    Функция assert() имеет два режима работы: если передано что-то, кроме строки, она будет проверять, что значение является истиной. Если была передана строка, она будет запущена через eval(), и assert будет проверять истинность результата eval().


    Причиной такого поведения является то, что до PHP 7 это было единственным способом предотвратить вычисление выражения. Начиная с PHP 7 опция zend.assertions в ini-файле может использоваться, чтобы избежать вычисления выражений. Таким образом, больше нет необходимости поддерживать неявное вычисление строковых аргументов.


    Использование assert($value) для проверки истинности значения открывает уязвимость удаленного выполнения кода, если существует вероятность того, что $value будет строкой.
    Теперь выбрасывается Deprecation notice, если assert() используется со строковым аргументом.


    Устарел $errcontext аргумент в error handler


    Обработчикам ошибок, заданных с помощью set_error_handler(), передается в качестве последнего аргумента $errcontext. Этот аргумент представляет собой массив, содержащий все локальные переменные в месте, где была сгенерирована ошибка.


    Эта функция трудна для оптимизации, поскольку $errcontext может использоваться для изменения всех ссылок и объектов в текущей области видимости. Эта функциональность практически не используется. Если вы хотите проверить переменные состояния в месте ошибки, вы должны использовать debugger.


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


    В этом случае невозможно выбрасывать Deprecation warning, поэтому этот функционал будет просто отмечен в документации как устаревший.


    Устарела константа INTL_IDNA_VARIANT_2003


    В PHP 7.2 константа INTL_IDNA_VARIANT_2003 объявлена устаревшей.
    В PHP 7.4 будут изменены idn_to_ascii() и idn_to_utf8(), в которых дефолтный $variant параметр станет INTL_IDNA_VARIANT_UTS46.
    В PHP 8.0 уберут поддержку INTL_IDNA_VARIANT_2003.


    Объявлены устаревшими приведение типов (binary) и b"" литералы (RFC)


    Приведение типа (binary) и поддержка префикса b были добавлены в PHP 5.2.1 для совместимости с PHP 6, однако эта версия так и не появилась, и неизвестно, будут ли когда-нибудь ещё попытки реализовать двоичные строки. Тем не менее, они все еще принимаются языковым сканером, хотя и игнорируются.
    Теперь выбрасывается Deprecation notice при использовании этих кастов.


    Специально к версии 7.2 я подготовил репозиторий — "Что нового в PHP", который описывает изменения в версиях PHP, начиная с 5.


    Список на английском языке вы можете найти в источниках:
    https://github.com/php/php-src/blob/PHP-7.2/UPGRADING
    https://wiki.php.net/rfc#php_next_72


    Попробовать новую версию онлайн:
    https://3v4l.org/


    Как мы видим, глобальных изменений достаточно мало.
    А как вы относитесь к изменениям в PHP? Какая фича понравилась больше всего?

    Метки:
    Avito 248,23
    Avito – сайт объявлений №1 в России
    Поделиться публикацией
    Похожие публикации
    Комментарии 68
    • +2
      Зачем вообще использовать типизацию, если теперь все можно переопределить? Откуда ушли, туда и вернулись.
      • 0
        Переложили обязанность на разработчиков. Раньше вообще было мало возможностей контролировать типы. А теперь хотят сделать «Хочешь — контролируй, Хочешь — чуть меньше контролируй, а хочешь — вообще забей»
        • 0
          Возможно, это и правильно, пока что сложно сказать.
          • 0
            Сначала тоже возмутил этот шаг назад, но по факту, в реальности не так часто приходится использовать принцип подстановки Лисков. Как правило, там где я явно ожидаю объект класса A — объект класса B, расширяющий его, мне скорее всего не нужен. И даже более того — теоретически наследник может, сохранив реализацию контракта, переопределить внутреннюю реализацию настолько, что вызов наследника станет нежелательным.
            • +2
              Принцип подстановки Лисков как раз не столько о контракте, сколько о наследовании.
              Этот принцип нарушается, когда вы неправильно наследуете.

              И даже более того — теоретически наследник может, сохранив реализацию контракта, переопределить внутреннюю реализацию настолько, что вызов наследника станет нежелательным.


              Наследование должно расширять, а не замещать. Если в наследнике вы замещаете реализацию, то вам не наследник нужен. Вам нужна композиция, с вынесением поведения в стратегии к примеру.
              • 0
                когда расширяешь классы фреймворка или сторонней библиотеки от тебя уже не зависит выбор паттерна. а такое приходится делать чаще.
                • +1
                  Так не расширяйте их. Делайте враперы/адаптеры. Ваш код не должен зависеть от сторонних либ
        • 0
          Я надеюсь RFC, где предлагается добавить mixed typehint отклонят.

          Draft — 7.2 if RMs agree, otherwise 7.3
          • 0

            А можно узнать как вы реализуете паттерн реестра без mixed?

            • +1
              Просто не указывать возвращаемый тип. Псевдотип `mixed` в пыхе сам по себе является рудиментарным и вообще ничем не отличается от отсутствия декларации оного.
              • +1
                От отсутсвия декларации возвращаемого типа объявление mixed означает что разработчик точно знает что в данном месте возможен множественный возврат. Сейчас мне приходится в реестре возвращать без указания типа, но с пометкой в комментариях про bool|string|array, что само по себе является хаком.

                Если мы уж стремимся перейти на строгую типизацию — нам нужно либо ее начать использовать везде, либо нигде.
                • +3
                  Для этого в пыхе должны быть реализованы хотя бы составные типы (или хотя бы тайпалиасы), вида:
                  type some = bool | string | array;
                  
                  function example(): some { ... }
                  


                  В этом случае пропадёт надобность как самого mixed, так и iterable, и callable (хотя там есть внутренняя логика: Контекст должен быть действительным классом, а метод — существовать, но не суть).
                  • 0
                    Интересное решение. Спасибо. Не думал о таком.
                    • 0

                      я так и не понял почему это дело завернули(

                      • 0
                        А там и не было rfc с тайпалиасами, только с группировками «на месте»:
                        function getIterable(): array | \Traversable { ... }
                        //
                        function getArrayable(): array | \Traversable & \ArrayAccess { ... }
                        


                        А это, как видно из простого примера — дичь. По-этому и завернули. Я бы тоже не хотел подобного функционала без возможности указывать алиасы.

                        Так что из этих всех обсуждений в релизе 7.1 остался только «костыль» для исключений:
                        try {
                            // ...
                        } catch (\Throwable | \Exception $e) {
                            // ...
                        }

                        • 0

                          может тогда тайпэлиасы запилить?)


                          type email = string;
                          
                          function filterEmail(string $email): ?email
                          {
                               // ...
                          }

                          а уже потом форсить union types.

                          • 0
                            Выглядит так же как mixed тип. Вроде нужно, а вот нахрена — не понятно =)

                            Есть вот такой, более профитный вариант:
                            type email (string $input): string { 
                                if ((bool)preg_match('/^.+?@.+?\..+?$/isu', $input)) {
                                    return $input;
                                }
                            
                                throw new \InvalidArgumentException(...);
                            }
                            
                            function filterEmail(string $email): ?email { ... }
                            


                            Такой способ:
                            1) Решит проблему рантайм-типов (вроде callable в виде массива).
                            2) Имеет довольно понятный синтаксис (я просто заменил кейворд `function` на кейворд `type`)
                            + В качестве бонусов:
                            3) Предоставит базовый механизм декораторов
                            4) Предоставит базовый механизм аннотаций
                            5) Кусок DbC

                            Единственное НО — берёт на себя слишком много возможностей.
                            • 0

                              В этом всем есть один минус: Вот у меня кусок кода с вызовом:


                              function filterEmail(string $email): ?email { ... }

                              и к сожалению мне надо смотреть что погромист подразумевал под своим type email. А какой-нибудь г*кодер будет писать


                              function filterEmail(string $email): ?stringed { ... } 

                              и из лаконичного названия я буду думать про строку, а создатель про array или object.

                              • 0
                                В этом всем есть один минус: Вот у меня кусок кода с вызовом:

                                И чем это отличается, допустим, от интерфейса `Stringable`? Кажется, что в именовании переменных и заключается первая из извечных проблем (вторая — это инвалидация кеша). Так что от этого никуда не уйти.
                                • 0
                                  В интерфейс Stringable если придет тип stringed — это одна беда. Если в интерфейс Stringable будет приходить string или mixed — я хотя-б пойму что от меня ожидают.
                                • 0

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

                                • 0
                                  Вроде нужно, а вот нахрена — не понятно =)

                                  дает информацию анализатору типов. Пример надуманный но мне иногда надо. Скажем есть метод который принимает не просто всякую строку, а строку которую может родить только определенный метод/функция. И на данном этапе делать для этого VO на пустом месте я не хочу.

                                  • 0
                                    Есть подозрение, что твой пример довольно непродуманный.

                                    Пример:
                                    // class EmailSenderExample
                                    public function send(email $receiver, message $body): bool { ... }
                                    
                                    // usage
                                    $sender->send(?, ?); // И что сюда передавать можно? Строки? тогда зачем эти "тайпалиасы"?
                                    
                              • 0
                                А это, как видно из простого примера — дичь.

                                Это не дичь, в ts вполне удобно, но type там тоже есть.


                                Выглядит так же как mixed тип.

                                Учитывая что он эквивалентен отсутствию типа вообще непонятно зачем он нужен...


                                Кстати я бы еще хотел видеть overload-инг методов, который с учетом типизации вполне возможен. Надеюсь когда-нибудь оно появится.

                        • +1
                          Не указывать возвращаемый тип = void | mixed. Void тип добавили, не вижу причин не добавить противоположный ему mixed.
                    • 0

                      эдакий кастыль для языка не умеющий в ковариантность типов. Позволяет вам в наследниках "ослабить" пред-условия.


                      Может быть когда-нибудь PHP научится разруливать это более красивым способом.

                    • +4
                      Устарел mbstring.func_overload

                      Интересно, и как теперь битрикс выкрутится? Они же требуют mbstring.func_overload = 2 в конфиге php прописывать?

                      P.S. задал вопрос в техподдержку — вдруг ответят?
                      • +3
                        [sarcasm]не обновляйте php в этом году, а мы пока грязный хак выкатим[/sarcasm]
                        • 0
                          Так ведь пока просто deprecated ;). А к 8-ке перепишут.
                          • +1
                            А разработчикам с ворнингами жить?
                            • 0
                              Так как обновления безопасности для 7.1 до 1 декабря 2019 года и нет ускорения в 2 раза, то просто не будут поддерживать 7.2. А кто хочет — будет жить с ворнингами.
                              • +5

                                А ворнинги – самая большая проблема битрикс-разработчиков?

                                • 0
                                  Включил на ~последней версии Битрикс24 коробочного режим отладки:
                                  400 Notice
                                  26 Strict Standart

                                  1 Warning погоды не сделает, а учитывая то, что они поддержку 7.1 сделают не раньше середины 2018 года, то я бы не стал из-за этого переживать.
                              • +3
                                Как, как… будут рекомендовать использовать 5.3. Я уже сталкивался со этими специалистами. Натрещат в уши какому-нибудь доверчивому руководителю про то, что «да там семерка еще багованая, ваще не работает», делов-то. Как будто Битрикс — это не Битрикс, а что-то хорошее.
                                • 0
                                  Прошу прощения…
                                  • +1
                                    Ох как я ждал этого. Но битриксу пофигу, они так и останутся на 5,3 версии, потому что они не хотят ломать обратную совместимость (именно поэтому они не могут уже лет 5 как внедрить свое новое ядро). А не хотят ломать, потому что кормятся с маркетплейса, соответственно, если сломают то потеряют текущие расширения (а большинство разработок там откровенно заборшены) и потеряют деньги. Короче если битрикс не переосмыслит хотя-бы эту ерунду, то крах неизбежен
                                    • 0
                                      У них с 1 января 2018 года в технических требованиях минимальная версия PHP 5.6
                                      • 0
                                        А легче от этого не стало, потому что в битриксе не образумятся
                                    • 0
                                      Если ответят — процитируйте плиз, было бы интересно.
                                    • 0

                                      Никакой особой непреодолимой сложности возникнуть не должно. Делается буквально следующее:


                                      1. Заменяются все вызовы функции тип strlen, substr, и т.д. на mb_strlen, mb_substr и т.д.
                                      2. Вызовы функций mb_orig_strlen, mb_orig_substr и т.д. остаются в коде «как есть»
                                      3. Добавляются куски вида if (!function_exists('mb_orig_strlen')) { function mb_orig_strlen(...) {...}}
                                      4. В git hook добавляется проверка, что функции без префиксов не используются
                                      5. Плавно обновляемся на новую версию PHP
                                      6. Через полгода, когда все уже привыкли к новым правилам, наоборот запрещаем писать с префиксом mborig… (контролируя это с помощью git hook) и автоматически удаляем префикс mborig там, где он используется
                                      7. После последней замерженной ветки с этими новыми правилами, делаем финальное удаление mborig из кода и в git hook запрещаем использовать этот префикс в новом коде
                                      8. Выпиливаем if (!function_exists('mb_orig_...')) { } из кода
                                      9. Мы успешно итеративно перешли с mb.func_overload != 0 на mb.func_overload = 0
                                      • 0
                                        repeat this after each Bitrix update?
                                        • 0

                                          Почему? Это однократная процедура, как битриксу обновиться со старой версии на новую.

                                          • –2
                                            у них css фал из трех строк написан пятью людьми. О чем вы))) Они это не могут сделать уже лет этак много
                                        • 0

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


                                          Недавно возникла проблема с очередной библиотекой, патчить вручную было лениво, в итоге родился скрипт https://gist.github.com/oWeRQ/6d2514409e84f863122d07ddb8a2878d см. function mbo_patch и совсем экспериментальный вариант с рекурсивной обработкой при подключении (через include mbo_virtual('...php');)

                                      • 0

                                        Не холивара ради, но движение есть https://dev.1c-bitrix.ru/community/blogs/orm/bitrix-minimal-php-version-to-56.php

                                        • 0
                                          <sarcasm>Здорово, PHP 5.6 вышла всего то в 28.08.2014, так классно, что за ~4 года они дошли до этой версии</sarcasm>
                                          P.S. На этом графике даже нет PHP 7.2, хотя 08.08.2017(когда была опубликована статья) уже был PHP 7.2.0 Alpha 3 от 06.08.17. То есть они уже знали что он есть, но планировать не стали.
                                          • +2
                                            Это минимальная поддерживаемая версия. А так на 7-ке уже давно работает.
                                        • +2
                                          Добавлен отладчик PDO Prepared statements

                                          Ура! Как их мне не хватало в своё время!
                                          Ещё бы нативную поддержку тредов впилили бы…
                                          • +7
                                            В ядро PHP добавлена Libsodium

                                            Таким образом PHP станет первым языком программирования с полноценным современным набором криптографических функций в базовой поставке. Для сравнения, язык Go 1.8 поддерживает X25519 и ChaCha20-Poly1305 в основном стеке TLS, но не предоставляет в стандартной библиотеке средств для обособленного использования современных криптографических алгоритмов на уровне приложения, для использования которых требуется установка дополнений. Другие проекты, такие как Ruby, Erlang и Node.js до сих пор основываются на OpenSSL, предлагая классические RSA и AES в режиме ECB без аутентификации шифротекста.
                                            • 0
                                              Оптимизирована работа встроенной функции in_array() с помощью поиска хеша в перевернутом массиве.

                                              Подскажите, что это значит? Теперь нет смысла самостоятельно переворачивать массив для быстрого поиска? Неужели теперь у каждого массива есть хеш-таблица значений?

                                            • 0
                                              В PHP 7.4 будут изменены ...

                                              А где-то еще упоминается PHP 7.4?
                                            • 0
                                              Кто-либо использовал assert() на практике?
                                            • +1

                                              "Добавлена возможность перегружать абстрактные функции (RFC)".


                                              Может всё-таки переопределять?

                                              • –1
                                                Кажется, грань между этими терминами очень тонкая.
                                                • +3

                                                  Почему?
                                                  Грань очно толстая, в PHP, как в языке с динамической типизацией не может быть перегруженных функций.
                                                  Переопределение — это, по сути, исчезание родительской функции у класса и возможность ее вызвать только через приведение типа.
                                                  Перегрузка — это добавление функции и разрешение в зависимости от аргументов.
                                                  В общем, разница очень большая.

                                              • 0
                                                PHP7 это конечно хорошо, но зачем мы пишем так, как будто PHP мертвый, практически все сайты используют этот серверный и далеко сложный язык, я бы не сказал что PHP простой, он далеко не простой, может база простая, но не сам язык. Поэтому я считаю что нельзя PHP ставить во второй ряд рядом с PHYTON и GO.
                                                PHP существует и будет существовать, потому что это скорее самая центральная ядро в серверной разработке, а как мы все знаем, сервер — это центр всего нашего сайта, нету сервера, нету ничего!
                                                • 0
                                                  это центр всего нашего сайта, нету сервера, нету ничего!

                                                  в последние годы наблюдаются тренды децентрализации (блокчейны) и serverless архитектуры. Так что… поглядим посмотрим.

                                                • 0
                                                  Новая функция preg_replace_callback_array() позволяет писать более чистый код, когда требуется использовать функцию preg_replace_callback(). До PHP 7 при необходимости обработать разные регулярные выражения разными функциями, приходилось для каждой такой обработки писать отдельный вызов функции.
                                                  Не приходилось. Была возможность определить группу шаблонов с опцией «e» («eval»). Потом эту опцию выпилили и какое-то время такого способа действительно не было. У меня была переписка с кем-то из команды разработки ПХП в это время.
                                                  • 0

                                                    eval выпилили не просто так. Количество минусов использования этого варианта намного превосходит плюсы. А уж что говорить про "чистоту"… тут массив ссылок на анонимные функции, это более чем чисто.

                                                    • 0
                                                      Я и не говорю, что просто так. Я указываю на неточность в тексте.
                                                  • 0
                                                    "Конечно, давайте отправим SOLID в ад. Кто такая Барбара Лисков??? Какая-то безумная женщина? Конечно! Давайте разрешим ломать принципы и идеи".

                                                    Специально пошел перечитал solid, так и не понял как это он вдруг нарушается? Лисков, вообще не писала ничего про ослабление интерфейса. Зато согласно методологии контрактного программирования:


                                                    1. Предусловия не могут быть усилены в подклассе.
                                                    2. Постусловия не могут быть ослаблены в подклассе.

                                                    Собственно, первый пункт соблюдался раньше, и теперь соблюдается. Лишь дали возможность ослабить предусловия. Что касается второго пункта, то я думаю, что было бы неплохо дать еще и возможность усиливать постусловия. А пока — страдаем.

                                                    • +1

                                                      Ослабление предусловий/усиление постусловий это нормально, но предложенное изменение уж сильно ослабляет это самое предусловие. То есть например у нас может быть метод который принимает на вход Money и внезапно в наследнике мы можем туда совершенно спокойно передать int. Конечно же это было бы глупо, но когда сам язык ограничивает от этого, то как-то проще.


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

                                                      • 0

                                                        Строго говоря, отсутствие типа — это "самый общий тип из всех возможных". Это тот самый пресловутый mixed.
                                                        А вообще да, правильнее всего было бы добавить возможность именно ослабить тип.

                                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                    Самое читаемое