PHP Дайджест № 199 (8 – 22 февраля 2021)


    В PHP 8.1 будет enum, и еще два принятых, два отклоненных и три новых RFC предложения для PHP 8.1. WordPress используется на 40% сайтов. Почему нужно убрать strict_types, почему не стоит использовать empty(), а также инструменты, видео, статьи, подкасты, и PHP Дайджест Live в 20:00 МСК.

    Приятного чтения!



    Новости и релизы



    PHP Internals


    • check [RFC] Enumerations
      С результатом 44 против 7 голосование завершено. В PHP 8.1 будет enum.

      enum RfcStatus {
          case Draft;
          case UnderDiscussion;
          case Accepted;
      }
      
      function setRfcStatus(RfcStatus $status) :void {
          // ...
      }
      
      setRFCStatus(RfcStatus::Accepted); // Ок
      setRFCStatus('Draft');                     // TypeError
      

      Подробнее про инамы можно прочитать в пересказах RFC в статье Брента и еще подробнее на php.watch.

      В Symfony уже открыли тикеты для добавления поддержки инамов.
    • check [RFC] Deprecate passing null to non-nullable arguments of internal functions
      В текущих версиях PHP стандартные функции без ошибок принимают null в качестве аргумента, когда параметр не nullable.

      А начиная с PHP 8.1 встроенные функции тоже будут бросать deprecation, а начиная с PHP 9 будет TypeError. Например, str_contains("", null). 3v4l.org/OVoa0A.

      Интересный факт: предложение принято единогласно, притом что это довольно крупная поломка обратной совместимости в PHP.
    • check [RFC] Array unpacking with string keys
      Предложение принято и в PHP 8.1 будет работать распаковка любых массивов, в том числе со строковыми ключами:

      $array1 = ['a' => 'apple', 'p' => 'pear'];
      $array2 = ['b' => 'banana', 'o' => 'orange'];
      $array = [...$array1, ...$array2];
      // Приблизительно то же самое что:
      $array = array_merge($array1, $array2);
      
    • [RFC] Fibers
      Из предложения по файберам был убран планировщик, потому что он сильно усложнял реализацию и вероятность принятия предложения.

      Теперь Fiber API предоставляет самый минимум и похож на аналогичные возможности в Ruby.

      Пример использования с ReactPHP trowski/react-fiber:

      Скрытый текст
      
      $loop = new FiberLoop(Factory::create());
      
      $browser = new Browser($loop);
      
      $request = function (string $method, string $url) use ($browser, $loop): void {
          /** @var Response $response */
          $response = $loop->await($browser->requestStreaming($method, $url));
      
          /** @var ReadableStreamInterface $stream */
          $stream = $response->getBody();
      
          $body = $loop->await(Stream\buffer($stream));
      
          var_dump(\sprintf(
              '%s %s; Status: %d; Body length: %d',
              $method,
              $url,
              $response->getStatusCode(),
              \strlen($body)
          ));
      };
      
      $requests = [];
      
      $requests[] = $loop->async($request, 'GET', 'https://reactphp.org');
      $requests[] = $loop->async($request, 'GET', 'https://google.com');
      $requests[] = $loop->async($request, 'GET', 'https://www.php.net');
      
      $loop->await(Promise\all($requests));
      
    • [RFC] CachedIterable (rewindable, allows any key&repeating keys)
      Tyson Andre предлагает добавить кеширующий итератор. Он сохраняет состояние любого итератора и внутри себя содержит иммутабельные копии его ключей и значений.
    • Proposal: namespace the SPL
      Обсуждается предложение создать неймспейс Spl и создать в нем алиасы для существующих классов: Spl\FixedArray -> SplFixedArray. А все новые классы, такие как CachedIterable и ReverseIterator уже вносить сразу в новый неймспейс.

      А пока в качестве альтернативы есть отличный инструмент azjezz/psl.
    • [RFC] mysqli bind in execute
      Kamil Tekiela продолжает инициативу по улучшению mysqli. В этом RFC предлагает добавить новый необязательный параметр в mysqli_stmt::execute(). Он будет принимать массив значений, которые автоматически биндятся, вместо отдельного вызова mysqli_stmt::bind_param(). К слову, сейчас bind_param принимает только переменные по ссылке.
    • cross [RFC] PHP\iterable\any() and all() on iterables — Предложение добавить функции any() и all() для итераторов не прошло голосование.
    • cross [RFC] var_representation(): readable alternative to var_export() — Идея добавить альтернативу для var_export не нашла поддержки, поэтому пока используем юзерленд альтернативу brick/varexporter.
    • [Draft] Unify PHP's typing modes — В PHP по сути есть два режима типизации. Один — слишком слабый, а другой, – strict_types=1 – слишком строгий. Этот документ описывает причины существования этих двух режимов, их недостатки и что нужно сделать, чтобы объединять оба режима.

      Документ написан George Peter Banyard, и пока он не планирует его выдвигать в качестве официального RFC.

      Разберем его положения на стриме.
    • Об Observer API в PHP 8 — Статья о внутреннем API для отслеживания входа и выхода из функции. Он существенно упростил разработку расширений типа Xdebug, профайлеров и APM-решений New Relic, Tideways, и т.п.

    Инструменты


    • renoki-co/php-k8s — Позволяет управлять ресурсами кубернетиса из PHP.
    • marcocesarato/php-conventional-changelog — Генерирует changelog из сообщений коммитов.
    • andrey-helldar/package-wizard — CLI-инструмент для создания начальной структуры пакетов.
    • rryqszq4/ngx_php7 — Встраиваемый в nginx интерпретатор PHP. Позволяет создавать обработчики запросов на PHP, модифицировать запрос/ответ, фильтровать тело ответа и заголовки, и прочее.

    Symfony



    Laravel



    Yii



    Async PHP


    • swow/swow — Расширение для PHP, которое предоставляет асинхронные возможности на базе libuv, включая асинхронный стрим, то есть из коробки работающие PDO, file_get_сontents() и т.п. (когда они обернуты в корутину). По сути, является минималистичным подмножеством Swoole.

    phpstorm PhpStorm



    Статьи



    Аудио/Видео



    Занимательное


    • mario-deluna/php-render — 3D рендерер на чистом PHP, даже без использования FFI. Шейдеры, парсер .obj файлов и прочее.

      Код примера:






    Уже традиционный стрим по мотивам PHP Дайджеста. Будет разбор новостей и ссылок из выпуска с подробностями и дополнительными деталями.
    Начало в 20:00 Москва, Минск / 19:00 Киев.



    Если вы заметили ошибку или неточность — сообщите, пожалуйста, в личку Хабра или телеграм.

    Больше новостей и комментариев в Telegram-канале PHP Digest.

    Прислать ссылку
    Поиск ссылок по всем дайджестам
    Предыдущий выпуск: PHP-Дайджест № 198

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 23

      +1
      В preview новости «WordPress используется на 40% сайтов», в расшифровке же «Доля WordPress перевалила за 40% среди топ 10 млн сайтов».

      Мы сканили в январе все доступные домены в интернете, порядка 250 млн штук доменов, из общего количества более менее работающих хостов в 295 млн (т.е. один и тот же сайт может работать на http, https, +www и т.п.) на вордпрессе работало 30.7 млн, что получается в районе 10%.
      Интересно, откуда по интернету ходит число в 40% всех сайтов.
        +3
        Мы сканили в январе все доступные домены в интернете, порядка 250 млн штук доменов

        а они использовали:


        For all our statistics we use the Alexa top 10 million websites, complemented by the Tranco top 1 million list.
          +3

          Планируете публиковать ваше исследование и методологию? Было бы интересно сравнить.

            +4
            конечно сделаем, еще перепроверяю данные, чтобы быть уверенными в них
            почти три года назад писал на эту же тему habr.com/ru/post/413739
            самому интересно узнать, что поменялось в сети
          –14
          Почему PHP развивается настолько хаотично? Новые фичи добавляются совершенно бездумно, обратная совместимость ломается. Не удивительно, что хорошие разработчики бегут с этого ЯП.
            +15
            Вы плохой разработчик или уже сбежали?
            +1
            А начиная с PHP 8.1 встроенные функции тоже будут бросать TypeError

            они будут бросать deprecation, а TypeError будет начиная с PHP 9:


            • in PHP < 8.1 the null value will be silently coerced to either false, 0, 0.0 or “”.
            • in PHP >= 8.1 a deprecation error is thrown, but the value is still coerced and the call still takes place.
            • in PHP >= 9.0 a TypeError is thrown, consistent with the behavior of user-defined functions.

              0

              Вы правы, поправил, спасибо.

              +1

              Спасибо за подборку. Вот это, правда, вызвало недоумение:


              Почему нужно убрать strict_types

              Приятного чтения.

              Прочитал. Но не нашел нет причин, почему его нужно убирать. Да есть какой-то драфт, который в ближайшее время даже на RFC. А если и будет RFC, то не факт, что примут.

                0

                А что именно недоумение вызвало? В посте так и написано:


                пока он не планирует его выдвигать в качестве официального RFC.
                  0

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

                    0

                    А что думаете по поводу пунктов https://github.com/Girgias/unify-typing-modes-rfc#advantages-of-a-unique-typing-mode ?


                    1. Smaller cognitive burden
                    2. Too strict may lead to too lax
                    3. Smooth integration with data sources
                    4. No need for "namespaced declares" is removed as it is only needed for strict_types
                      0

                      Например, я не согласен с этим:


                      Most notably float to integer and string to integer or float conversions, conversions the engine can perform safely in coercive type mode.

                      Все эти неявные конвертации могут быть результатом ошибки.


                      Также я не согласен с изменением дефолта, ибо апгрейд старых проектов на новый пхп превратится в кошмарный сон.

                        0

                        Цитата странная, согласен, но в предложении говориться как раз об обратном. Там речь о том, чтобы убрать strict_type, но запретить многие неявные преобразования по дефолту. Например вот такие:


                        false -> int           # No more conversion from bool
                        true -> string         # No more conversion from bool
                        7.5 -> int             # 7.5 cannot be converted to an integer without data loss
                        "8.2" -> int           # "8.2" cannot be converted to an integer without data loss
                        4.3 -> bool            # No more conversion from float to bool
                        "7 dogs" -> int        # Non-blank trailing characters no longer supported
                        "3.14 pizzas" -> float # Non-blank trailing characters no longer supported

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

                          –1

                          А я не хочу, чтобы убирали strict_types, потому что я не хочу иметь неявное преобразование "8" => 8 или "8.2" => 8.2. И даже 8.2 => 8 (int). Просто потому, что это РАЗНЫЕ типы. Скажем, если работать с elasticsearch, то внезапно окажется, что такой бардак может вести к неприятностям (да, я знаю, как их обходить, и всё же это хождение по граблям).

                          0

                          Есть у вас какой-то пример кода? Давайте его вместе рассмотрим. Хочется разобраться.

                            0

                            Примера кода нет, но представьте, что у вас на основе данных генерируется схема данных в том же Elasticsearch. Если вы пошлете в него сначала int (схема сгенерировалась), а потом float (в существующую схему), то всё, у вас неприятности.


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

                  +1
                  По поводу empty() тоже глупости какие-то как по мне. Нет, если весь код написан очень четко, возвращаемые/входные значения ограничены конкретными типами и в общем-то все везде на контроле, что в РНР в принципе сказки какие-то а не реальность, ну тогда нет смысла использовать empty(), потому как в том же примере с массивом тебе не нужно перекрывать всё что может быть пустым ([], "", false, 0, NULL) и твой метод на уровне контроля типов не пропустит что-то отличное от массива. Но когда в коде черт знает что, ты на вход можешь получить что угодно, то empty() сильно сокращает условия, просто если условия вроде !empty($myvar) то дальше обязательная проверка типа && is_array($myvar).
                  Короче, сколько себя помню — столько эту функцию хоронят и отговаривают от нее, но что-то вот уже и РНР8 и там она что-то даже не deprecated — наверное разрабы языка таки что-то понимают…
                    0
                    Про empty не согласен с резкостью заявления.
                    Использовать можно, главное понимать зачем и как это работает.

                    Empty помогает сократить написание, ибо сразу на существование и непустое значение проверить можно. Внимание, нужно помнить про false, 0, ибо empty(false), empty(0) вернёт true, особенно помнить про 0).

                    Например, если нужно и на false, и на null сразу проверить, чтобы дважды не писать, можно в empty обернуть, или с пустым и неопределённым массивом/объектом также. Одна проверка вместо двух.

                    Зачем писать isset($arr) && count($arr) > 0, если можно написать !empty($arr).
                    Аналогично вместо isset($bool) && $bool === true можно !empty($bool)

                    Вывод: используйте, если понимаете, как это работает
                      +1

                      Вот это самая большая проблема empty: var_dump(empty('0')); // => bool(true).
                      Я даже натыкался на случай, когда это вело реально к неожиданному для разработчика поведению, и — как следствие — к багу в продакшне.

                        0
                        Абсолютно согласен, к тому и веду, что использовать, если понимаешь как работает. Благодарю за хороший пример, empty('0') выглядит как недоработка языка, о которой не стоит забывать
                          –1
                          нет никаких проблем и «недоработок» с `empty()`. Читайте документацию, там указано, что empty($var) это по сути !isset($var) || $var == false;
                          а затем еще раз освежите в памяти нестрогое сравнение различных типов с булевым false, и тогда все станет прозрачно и понятно:
                          var_dump(
                              (bool) null, // false
                              (bool) '0', // false
                              (bool) '1', // true
                              (bool) '', // false
                              (bool) 0, // false
                              (bool) 1, // true
                              (bool) [] // false
                          );
                          
                            +1

                            Это неочевидное поведение, вне зависимости от того, что написано в документации.


                            P.S. Пожалуйста, воздержитесь в следующий раз от указаний, что и кто должен делать. Я прекрасно знаю причины того, почему так работает empty, и это никоим образом не меняет сути моего предыдущего комментария.

                      Only users with full accounts can post comments. Log in, please.