PHP-Дайджест № 151 (25 февраля – 11 марта 2019)


    Свежая подборка со ссылками на новости и материалы. В выпуске: обновления PHP, Laravel 5.8, Xdebug 2.7 и другие релизы, 3 свежих RFC, 2 принятых, и концепт из PHP Internals, порция полезных инструментов, и многое другое.

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



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



    PHP Internals


    • [RFC] Saner string to number comparisons — В своем свежем RFC Никита Попов предлагает изменить поведение == и сделать нестрогие сравнения менее подверженными ошибкам. В частности, сравнение чисел предлагается использовать, только если сравниваемая строка на самом деле является числовой. В противном случае число преобразуется в строку, и выполняется сравнение строк.

      Данное предложение влечет за собой изменение поведения операторов сравнения  <=>==!=>>=<, и <=, конструкции switch, функций типа in_array(), sort() и других.

      В ответ поступили идеи разной степени радикальности: от введения специального флага declare('strict_comparison=1');, который бы превращал все == в ===, до предложения отменить == вообще.

      Ну а пока, в 7.4, вероятно, будет бросаться Warning, если результат сравнения отличается от предполагаемого в PHP 8.
    • [RFC] Permit trailing whitespace in numeric strings — Еще одно предложение призванное улучшить консистентность, но путем ослабления. Предлагается разрешить пробельные символы в конце числовых строк, то есть чтоб "123 " == " 123" и все прочие операции работали, как и для строк с начальными пробелами.
    • [RFC] Consistent type errors for internal functions — Предложение принято и значит в PHP 8 встроенные функции будут бросать TypeError в случае, если переданы параметры неверного типа и соответственно не будут при этом возвращать null.
    • [RFC] Weak References — Предложение по реализации слабых ссылок принято.
    • [RFC] Locked Classes — Предлагается ввести новое ключевое слово locked для классов. Такие классы будут закрыты для динамического использования свойств, то есть нельзя обращаться к необъявленным свойствам:
      Скрытый текст
      locked class TestClass {
          public $definedProp;
      }
      
      $t = new testClass();
      $t->definedProp = "OK";
      echo $t->definedProp;
      unset($t->definedProp);
      
      echo $t->nonExistentProp; // Error
      $t->nonExistentProp = "Not OK"; // Error
      unset($t->definedProp); // Error
      
    • video PHP Internals News: Episode 1 — Новый подкаст от автора Xdebug Derick Rethans. В первом выпуске разговор с Никитой Поповым.
    • Allow throwing from __toString()PR от Никиты с фиксом одной из старых проблем PHP – невозможность бросать исключения в __toString.
    • List comprehension — Концепт от Сары Гоулман с реализацией спискового включения (list comprehension) для PHP. Синтаксис менее элегантный, чем в Python, но выглядит интересно:
      $a = [1, 2, 3];
      $mul = 3;
      $c = [ for $a as $v yield $mul * $v use ($mul) ];
      

    Инструменты



    Symfony



    Laravel



    Yii


    • Yii 2.0.16.1
    • Релизный цикл Yii — Мажорный релиз поддерживается 5 лет, из которых 2 активных фиксов и 3 – фиксы ошибок безопасности.
    • zhuravljov/yii2-queue-monitor — Веб-интерфейс для мониторинга и управления очередями Yii2.

    Async PHP



    Материалы для обучения



    Спасибо за внимание!

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

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

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

    Share post

    Comments 8

      –1
      Продолжая тему wiki.php.net/rfc/string_to_number_comparison и неудачных примеров приведения типов в пхп, я выражаю свое согласие с вышеизложенными предложениями, они соответствуют моему виденью и нашли применения в моих ф-циях toInt(), toFloat().

      Я хотел бы обсудить аналогичную проблему каста в Boolean и String. Я столкнулся со следующими примерами, которые считаю неудачными и планирую переопределить в своих функциях кастования типа. В них я разграничиваю входные данные на ожидаемые и не ожидаемые для каждого из приведений типа.
      1) Случаи приведения типа в Boolean и моей ф-ции toBool().
      1.1) Стандартный каст (bool)5, (bool)-1 производят true. Я не считаю, что это правильно. Да, мы можем ожидать «1», «0», «1.0», «0.0», " 1 ", " 0 ", как репрезентацию true/false значений. Но если приходит 5 или -1 — это скорее говорит об ошибке переданных данных, чем об удачной возможности воспользоваться «магическим» преобразованием из коробки пхп.
      В моем случае toBool(5), toBool(-1) вернет Null значение, которое я возвращаю, в случае неудачной конвертации типа.
      1.2) (bool)«1.0», (bool)«1», (bool), " 1.0 ", производят true, как и ожидается.
      (bool)«0», производит false, как и ожидается.
      Но «0.0», " 0 ", так же производят true, что мне кажется неверным, моя toBool(«0.0») вернет false.
      1.3) (bool)«string» производит true, когда «string» не выглядит, как ожидаемое значение для булевого типа. В моем случае toBool(«string») возвращает null.
      1.4) (bool)"" производит false, что тоже по-моему мнению не верно.
      Похожий кейс обсуждается в статье для чисел, когда идет речь о сравнении (bool)(0 == ""), которое производит true, а предлагают сделать false.
      Я считаю, что toBool("") должно возвращать null, но здесь у меня сомнения.
      1.5) (bool)null производит false, когда я считаю, что должно производиться null. Мы ведь часто хотим иметь возможность сбрасывать булево значение в состоянии объекта, и присваивание null, как раз сбрасывает его. После, мы ориентируясь на факт, что значение сброшено (а не false), можем например загрузить значение по-умолчанию.
      1.6) (bool)[1], (bool)[0] — производит true, а (bool)[] — производит false.
      Я считаю, что массив — это не ожидаемое значение и не может быть преобразовано, значит надо вернуть null.

      2) Случаи приведения типа в String и моя ф-ция toString().
      В случае приведения типа в String, я вижу следующие сомнительные стандартные касты из коробки пхп:
      2.1) Если (string)true производит «1», тогда почему (string)false производит "", а не «0»?
      Я считаю, что true/false — булево значение не является ожидаемым значением для каста в стринг и в обоих случаях toString() должен вернуть null. Здесь меня терзают сомнения.
      2.2) (string)[] — производит E_NOTICE ошибку: «Array to string conversion», в моем случае toString([]) вернет null.

      3.1) Чтобы быть полным, хочу сказать, что я так же не считаю булевы значения, как ожидаемые для каста в числа, и toInt(true), toFloat(false) в моей парадигме произведут null
      3.2) Аналогично с массивом, toInt([1]), toFloat([]) производят null.

      Очень жду комментариев и мнений. Что я не предусмотрел? Наверняка, эти вопросы уже покрыты в какой-то библиотеке, куда мне следовало бы заглянуть, прежде чем описывать эти правила.
        +1

        От to*() функций ожидаешь, что они любой треш преобразуют в соответствующий тип. Поэтому возвращение null мне кажется странным. Теряется смысл этих функций, потому что придется каждый раз дополнительно делать проверку на null. Тогда уж кидать TypeError, по аналогии с https://wiki.php.net/rfc/consistent_type_errors

          0
          В этих функциях есть второй параметр, который определяет применяемую фильтрацию, и всегда можно установить поведение по-умолчанию, как и усилить правила фильтрации, напр, вместо F_INT, использовать F_INT_POSITIVE, F_INT_POSITIVE_OR_ZERO.
          Эти функции не предназначены для валидации значений, а только для каста. Какие конкретно приведения в null вам кажутся странными? Почему toInt(null), toBool(null), toFloat(null), toString(null) производит null, я объяснил, мы хотим отличать неустановленное значение от 0, false, 0.0, "". Другие моменты, я тоже попытался обосновать.
          0
          «Работает — не трогай». Это ж какой лютый гемморой будет переходить на 8-ку, если это все сделают. Кучи явных и скрытых багов в логике повылезает просто ото всюду. А все изза того, что у когото перфекционизм головного мозга.
            –1
            Т.е. вы считаете, что (bool)«0.0» === true — это корректно, когда (bool)«0» === false?
            Причем здесь перфекционизм? Инструмент должен работать однозначно и быть интуитивно понятным. Могу парировать, что у вас пхп головного мозга, раз вы бескомпромистно полагаетесь на правила кастинга, изобретенные специально для пхп и не повторяющиеся в других ЯП.
            И я не понял, какие проблемы меня ждут после перехода на пхп8? Пожалуйста, разъясните.
              +1
              Проблемы вас ждут из-за того, что в любом более-менее живом проекте ваш код — не единственный. Даже если допустить, что вы везде используете strict_types=1 и пишете исключительно корректный с точки зрения типов код, то ручаться за авторов всех библиотек, которые вы испольузете — невозможно.

              Поскольку проблема будет возникать в рантайме и статически отследить такие регрессии будет практически невозможно, то велик шанс столкнуться с огромным количеством багов и неявного поведения ПО. Да, все можно исправить со-временем, но вопрос в том, кто за это время будет платить.
                –1
                Пожалуйста, приведите пример. Потому что мои варианты кастинга с фильтрацией, как раз нормализуют входящие значения, чтобы избежать проблем, описываемых вами. Я считаю, что они не способствуют появлению проблемы, а наоборот.
                Я не понимаю, почему эти методы должны как-то вредно взаимодействовать с вендорским кодом. Они будут использоваться только в рамках нашей кодовой базы.
                  +2
                  При чем здесь вы и ваша библиотека. Речь идет о предлагаемых для 8 версии изменениях, в которых прямо указано:

                  > This change to the semantics of non-strict comparisons is backwards incompatible. Worse, it constitutes a silent change in core language semantics. Code that worked one way in PHP 7.4 will work differently in PHP 8.0

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