Предлагаем вашему вниманию очередную подборку со ссылками на новости и материалы.
Приятного чтения!

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



PHP


  • RFC: Parameter Type Widening — Предлагается сделать возможным изменение (отмену) типа аргумента в методах наследников:

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

Инструменты


  • edamov/pushok — Библиотека для отправки push-уведомлений на iOS с поддержкой новых фич (collapse IDs, subtitles, JWT auth, HTTP\2). Прислал edamov.
  • ReflectPHP — Инструмент позволяет запускать исходный код PHP более старших версий на интерпретаторе более младших версий. Прислал serafimarts.
  • FluentDOM/FluentDOM — Обертка над DOMDocument, реализующая текучий интерфейс а-ля jQuery. Пост в поддержку.
  • paragonie/sodium_compat — Экспериментальный полифил для Libsodium на чистом PHP. Пост в поддержку.
  • aidantwoods/SecureHeaders — Класс для упрощения работы с HTTP-заголовками связанными с безопасностью. Подробный пост по теме от автора.
    Альтернативное решение BePsvPT/secure-headers.
  • thephpleague/uri-parser — Парсер URI для PHP 7. Исправляет недостатки parse_url и совместим со стандартом RFC 3986. Пост в поддержку.
  • geekish/crap — Позволяет устанавливать псевдонимы для часто используемых composer пакетов.
  • fruux/sabre-cache — Библиотека для кэширования, реализован стандарт PSR-16.
  • symfony/dotenv — Symfony-компонент для чтения .env файлов.
  • zelenin/http-client — PSR-7-совместимый http-клиент с поддержкой middleware. Прислал zelenin.
  • wapmorgan/Mp3Info — Библиотека для чтения тегов и метаинформации из mp3.
  • wapmorgan/UnifiedArchive — Библиотека для унифицированного доступа к архивам различных форматов. Также в виде утилиты командной строки — wapmorgan/CAM.

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



Аудио и видеоматериалы



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



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

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

Прислать ссылку
Быстрый поиск по всем дайджестам
< Предыдущий выпуск: PHP-Дайджест № 99
Поделиться с друзьями
-->

Комментарии (34)


  1. skiedr
    16.01.2017 00:34
    +6

    > RFC: Parameter Type Widening

    Какой кошмар. А как же принцил Лисков?


    1. Andreyika
      16.01.2017 12:50

      А что плохого с принципом случится, если foo все еще будет работать с (в том числе и) массивом?


    1. pbatanov
      16.01.2017 12:50

      А как же принцил Лисков?

      Вы либо плохо читали RFC, либо подзабыли LSP. LSP разрешает расширение входных параметров и данный RFC как раз таки направлен на то, чтобы соответствовать LSP.

      Т.е. если у вас есть класс-наследник с методом, расширяющим сигнатуру базового, то это не противоречит LSP, но в то же время позволяет оперировать терминами будущей совместимости (например вы можете расширить класс, чтобы они принимал не только array, но и \Traversable, и задеприкейтить старый для следующего мажороно релиза). В нынешней реализации это вызовет ошибку


    1. xotey83
      16.01.2017 12:56
      +1

      Оно как раз не нарушает LSP. Поскольку, применительно к ООП LSP говорит о том, что субтип (дочерний класс) должен расширять родительский класс (интерфейс).
      Представим, что есть базовый класс:

      class Parent
      {
          /** @param string|int $bar */
          public function foo($bar)
          {
              ...
          }
      }

      Согласно «контракту» метод foo должен принимать на вход аргумент строкового или целочисленного типа.

      И есть использование:
      /**
       * @param Parent     $qux
       * @param string|int $arg
       */
      function baz(Parent $qux, $arg)
      {
          $qux->foo($arg);
      }


      Тут мы говорим о том, что на вход должен поступить объект, являющийся инстансом класса Parent, и в метод foo этого объект мы передаём аргумент. Так как контракт метода foo говорит о том, что на вход должен поступить либо строковой либо целочисленный аргумент, то и переменная $arg тоже должна быть либо строкового, либо целочисленного типа.
      Тут всё логично.

      Теперь представим, что есть класс
      class Child extends Parent
      {
          public function foo(int $bar)
          {
              ...
          }
      }
      , перегружающий метод foo и сужающий его ОДЗ.
      В этой ситуации мы инстанс класса Child уже не можем передать в функцию baz поскольку метод в дочернем классе сужает ОДЗ, а значит мы не можем передать в метод foo аргумент строкового типа. Таким образом мы имеем нарушение LSP.

      То, о чём говорит вышеозначенный RFC, так это о том, чтобы в дочерних классах можно было расширять типы аргументов переопределяемых методов. Если тип расширяется, то тогда контракт базового класса не нарушается: поскольку дочерние классы по-прежнему должны принимать на вход аргументы тех типов, которые задекларированы в родительском классе или интерфейсе.

      Таким образом, LSP говорит о том, что субтипы не должны сужать супертип. В том числе, переопределение метода в субтипе может расширять ОДЗ метода, но не должно сужать его.

      Извините, если ответ получился запутанным или сумбурным.


  1. b1rdex
    16.01.2017 08:25
    +5

    PHP код, который выводит буквенно-цифровые символы не используя ни один из них
    $__='`@`@'^'*/).'; // $__ = 'JoIn'
    $_='->.<:'^'__@[_'; // $_ = 'range'
    
    $__($_('>'^@_,'%'^@_)) // join(range('a', 'z'))
    


    1. Dumkaaa
      16.01.2017 12:50
      +1

      Подскажите, как это преобразовывается?


      1. b1rdex
        16.01.2017 17:58

        Ужасно, но php позволяет применять бинарные операторы к строкам и результат будет строкой.

        If both operands for the &, | and ^ operators are strings, then the operation will be performed on the ASCII values of the characters that make up the strings and the result will be a string.
        http://php.net/manual/en/language.operators.bitwise.php


  1. mmjurov
    16.01.2017 12:04
    +4

    С юбилеем, однако! Спасибо вам за отличный источник информации, желаю не терять энтузиазма и продолжать в том же духе!


    1. pronskiy
      16.01.2017 12:51

      Спасибо!


  1. banderos120
    16.01.2017 12:50
    -3

    Мое лицо, когда Тейлор говорит о справедливых бенчмарках.


    1. SerafimArts
      16.01.2017 20:52

      Справедливости говоря, на крупных проектах Ларка действительно даст фору Симфони (могу лишь сравнивать с ней, опыта с Zend маловато, чтобы утверждать что-то наверняка). Вся фишка в схеме работы и архитектуре:


      Внутри Симфони
      1) Сбилженный контейнер со всеми сервисами (frozen)
      2) Каждый запрос обрабатывается тучей эвентов из разных мест
      3) Внутрь контроллеров всовываются в конструктор сервисы через DI
      4) Каждый запрос обрабатывают тучи гвардов


      Внутри Ларки
      1) Контейнер создаётся лениво, в зависимости от поведения приложения
      2) Вместо кернел эвентов миддлвари, которые вешаются на определённый запрос, а не на все
      3) Сервисы в контроллеры попадают через двойную диспатчеризацию (т.е. как объект Request в контроллеры в симфони)
      4) Гвардов в ларке вообще нет, их ответсвенность берут на себя миддлвари, которые см. п.2 — на каждый запрос (или группу запросов) свои.


      Подытоживая — из подобной схемы работы ларка более тяжеловесна в сыром виде, симфони же после билда контейнера (в продакшн режиме, например) — летает, но при увеличении количества бандлов в проекте на симфони — жручесть его увеличивается по экспоненте, а ребилд всего в дев режиме может достигать десятков секунд. Доходило до такого, что обычная страничка в сонате (правда с xdebug) отжирала до 100+ мегабайт. В случае же ларки потребление оперативы почти не растёт, т.к. добавление провайдера лишь добавляет дефинишн (зачастую интерфейс, а не алиас сервис-локации, как в симфони) для DI, а он уже загружается когда потребуется в том месте, где он используется и только в нём. Т.е. чистый старт ларки содержит почти что пустой контейнер, в тоже время в симфони он полностью заполненный из всех бандлов.


      P.S. Я люблю оба фреймворка, они оба замечательные по-своему =)


      1. pbatanov
        16.01.2017 21:20

        1) Симфони создает сервисы лениво. Более того, с ocramius/proxy-manager оно может даже создавать супер-ленивые сервисы (не инициализируются до использования, а не до инстанциирования зависимых). Приведенный бенч (опустим вопрос его предвзятости) показывает, что сбилженный конейтнер имеет свои бонусы по производительности.

        2) Можете объяснить принципиальную разницу между мидлварью и листнером на пару событий kernel.request + kernel.response? Я думаю можно однозначно отобразить одно на другое, только вместо замыканий мидлвари отрабатывает EventDispatcher

        3) Вот это выглядит странно в Ларе, если честно. Трендовая парадигма Симфони «Controller as a Service» выглядить более логично тут. У Лары это больше похоже на ФП.

        4) Можно про тучу гвадров подробней? Если вы про секьюрити гварды, то их не туча, а в зависимости от сматченного фаервола. Если про другие гварды — то нужна конкретика. И, отдельно, чем «туча гвадров» лучше тучи миддлварей?


        1. SerafimArts
          17.01.2017 01:57

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


          Листенер вешается на событие, например kernel.request, миддлваря вешается на роут\группу роутов, отсюда в симфони на каждый реквест реагирует туча классов, скипаются они или нет, но суть в том, что чем больше бандлов, тем больше подписчиков. В ларке же очень редко кто вешается на глобальный перехват, разве что какие-нибудь дебаггеры, почти всегда пакеты предоставляют их набор, а вешать уже предоставляется разработчику.


          По остальным пунктам никаких возражений, каюсь =)


          1. pbatanov
            17.01.2017 07:58

            В симфони тоже можно реализовать подобное. Технически, роутинг в симфони — это просто некоторая дыра, которая возвращает вам \callable по данным запроса (по pathinfo в самом простом случае). В пайплайне обработки запроса есть момент, когда этот \callable уже известен, и есть специальное событие, которое позволяет его обработать или подменить. Например, навешать те же миддлвари.

            Технически, завязыватсья на роутинг в этот момент сложновато, т.к. в симфони нет «этих ваших» Route::get, роута как такового вообще может не существовать, как сущности (вспоминаем про дыру).

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

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

            А теперь встречный вопрос — насколько просто в Ларе будет установить те же мидлвари, скажем, считав аннотации у контроллера?


            1. SerafimArts
              17.01.2017 10:33

              То что можно реализовать не значит, что все бандлы реализуют. А проблема как раз в том, что каждый бандл добавляет глобальное поведение из-за чего фрейм работает всё медленнее и медленнее. Именно это печалит.


              P.S. Я против роутинга на аннотациях, т.к. в этом случае невозможно указать приоритет, но если надо, то проще воспользоваться готовым: https://laravelcollective.com/docs/5.3/annotations#routes


              1. pbatanov
                17.01.2017 11:30

                Опять же, вы в очередной раз говорите о проблемах сторонних бандлов. Я уверен, что в Ларе тоже можно понабрать таких библиотек, которые зафлудят что угодно.

                То, что не все реализуют — это 100%, именно потому, что как я уже сказал, такая реализация (в ядре) привнесет очень много привязок к конкретным решениям. А симфони — оно про заменяемость компонент.

                Про аннтоации — вопрос был не конфигурации роутов, а о расширяемости текущией схемы добавления мидлварей в Ларе. Переформулирую. У меня есть группа контроллеров, произвольным образом промаркированных (аннотации, тэги у сервисов, что угодно). Как будет выглядеть конфигурация мидл-варей для них?


                1. SerafimArts
                  17.01.2017 12:43

                  Так проблем в дефолтной поставке симфони никаких нет, всё летает. Но когда последний раз вы видели require у composer.json в симфони из пары-тройки строк? Я не хочу доказать, что N медленнее M де-факто, цель донести мысль о том, что архитектурные решения ларки чуть более эффективны для расширения благодаря ленивости загрузки и "точечности". Даже конфиги в пакетах под ларку почти всегда инициализируются и читаются только после того, как создаётся сервис, который их требует.


                  А по поводу второго, признаться, я не знаю как ответить на вопрос про миддлвари, т.к. не понимаю самого вопроса. Миддлвари и отвечают за запсук аннотаций, добавление тегов для сервисов и вообще что угодно, хоть за добавление интерфейса пользователя как аутентифицированного внутрь контейнера. А выглядеть это будет примерно как секция defaults в роутах симфони, за исключением того, что эти defaults можно вешать сразу на группу роутов не ссылаясь на внешний ресурс.


                  1. pbatanov
                    17.01.2017 13:23

                    Я примерно о том же. Ларка позволяет делать «более просто» за счет того, что некоторые решения фиксированы (ну по крайней мере, оно так выглядит, я могу ошибаться).

                    Я правильно понимаю, судя по вашему ответу, что запуск мидлвари, конфигурирующей другие милдвари (т.е читающая аннотации, каждый раз или проверяющая весь контейнер на предмет тегов), будет производиться на каждый запрос? В чем отличие от листнера, который будет проверять, нужно ли запускать другие миддлвари|листнеры|%tool% на каждый запрос?

                    Как эта мидлваря получит аннотацию конечного контроллера, если поверх него могут быть натянуты еще мидлвари?

                    Дефолты, если что, тоже можно повесить на группу роутов, если быть точным, то на импортируемый ресурс (yml, аннотации, что угодно). Еще есть options, которые можно устанавливаются и на импорты


                    1. SerafimArts
                      17.01.2017 14:40

                      1) Не совсем, скорее за счёт того, что никакой фиксации и нет, а провайдер регистрирует лишь сервис в контенере, в отличие от бандлов, требующих довольно жёсткое соблюдение правил именования в т.ч. Указние конфигов и ресурсов в ларке лишь декларация, мол тут у нас A, а тут Б, никаких разборов дерева конфигов.


                      2) Нет, в ларке нет аннотаций. Как следствие — всё зависит от реализации и в частности о того ридера, что используется. Отличие листенера в от миддлварей в том, что миддлваря жёстко фиксирует вход и выход и инициализируется только в момент аппрува роута. Листенер же подписывается (и создаётся объект с резолвом DI в том числе) на каждый запрос.


                      3) Как реализуете — так и будет. Но по логике это не задача миддлварь читать аннотации роутинга. Это скорее задача некого сервиса, который добавит их в список готовых при старте приложения. Например внутри Http Kernel, обязанность которого как раз и является загрузка роутов.


                      4) Я и написал (в самом конце), что дефолтсы можно вешать на группу лишь ссылаясь на внешний ресурс, что вполне годно, но не всегда удобно.


                      1. pbatanov
                        17.01.2017 15:01

                        1) Нет никаких жестких правил ). Жесткие правила нужны только в том случае, если вы хотите делать все автомагически (ну, типа quick-start). В остальных случаях вам достаточно имплементировать BundleInterface и зарегистрировать его в ядре. Аналогично с конфигами, расширениями и прочими конфигурациями.

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

                        2) В симфони тоже нет аннотаций, это формально внешняя библиотека (doctrine/annotations), хоть и рекомендуемая к использованию.

                        Ну в целом все ваши ответы сводятся к «как реализуете» (и это нормальная позиция), поэтому я считаю дальнейшие распросы бессмысленым, спасибо за информацию. Обычно действительно большая часть зависит от рук разработчика и авторов библиотек.

                        в Symfony 3.3 сделали ленивые листнеры, в том числе, посмотрите. Я думаю это решит многие из озвученных вами проблем (по флуду листнерами)

                        Еще раз спасибо за разъяснения


                        1. SerafimArts
                          17.01.2017 15:11

                          1) Ну это конечно верно, с другой стороны фреймворк всё же ограничивает. Например невозможно указать несколько директорий для сущностей одновременно, работая по DDD модели. Или подключить 10 бандлов внутрь другого, аггрегирующего. и т.д.


                          2) О, с за ссыль огромное спасибо. Жаль только что у меня в работе пока текущий 2.8 LTS, не скоро насложусь новыми фичами =(


                          1. pbatanov
                            17.01.2017 15:26

                            1а) Можно. Потому что, внезапно, доктрина — это не симфони. Поэтому можно долить конфигурацию так, чтобы грузило несколько папок
                            1б) https://github.com/symfony/symfony/pull/15011#issuecomment-183884227 этого периодически действительно не хватает, но решение вроде как принципиальное на данный момент. Но есть сторонние имплементации https://github.com/mmoreram/symfony-bundle-dependencies


                            1. SerafimArts
                              17.01.2017 15:54

                              1а) И всё же doctrine bundle, в отличии от doctrine orm — это часть симфони в некотором роде. И именно она не позволяет указывать в конфигах массивчик папочек для сущностей. Но, верно подмечено, можно переписать этот бандл, чтобы работало. Другой вопрос: а не проще ли забить и "не выпендриваться"? =)
                              1б) Ещё чего не хватает в симфони ещё двойной диспатчеризации как в ларке. И регистрации сервисов под интерфейсами, а не под алиасами.


                              1. pbatanov
                                17.01.2017 16:33

                                1а. Ну можно. Вы можете докинуть в метадата-фактори любой альяс + любую папку. Просто это не происходит автоматически.

                                http://symfony.com/doc/master/bundles/DoctrineBundle/configuration.html#configuration-overview вот простыня конфига, там строчка 309. В ней вы можете указать дополнительные мэппинги сверх того, что регается само. В том числе другие папки.

                                Переписывать вообще ничего не требуется. Требуется конфиг написать

                                И нет, доктрина не является частью симфони, это независимый проект, как и твиг, например.

                                1б. Если вы про передачу в контроллер через аргументы, то это есть, в виде парам конвертеров, аргумент-резолверов. Да и вообще вы можете пробросить любой аргумент руками в action через аттрибуты запроса.

                                Посмотрите, например, как реализован проброс UserInterface с версии 3.2

                                https://github.com/symfony/symfony/pull/18510

                                Регистрация сервисов под интерфейсами есть как автовайринг (вы можете просто объявлять зависимость от интерфейса, в него подтянется сервис, если он единственный имплементирует его, если нет, можно уточнить один раз)

                                А с версии 3.3 идентификатор сервиса будет опциональным
                                http://symfony.com/blog/new-in-symfony-3-3-optional-class-for-named-services

                                Идея регистрировать сервис сразу под всеми имплементируемыми интерфейами интересна, но 100% будут конфликты у всяких логгеров и других сервисов, которые генерятся фабриками


                                1. SerafimArts
                                  17.01.2017 21:15

                                  Ладно, убедили в том, что я отстал от этой жизни с этим симфони 2.8… =( Буду ждать конца года, там новый LTS должен подъехать, вот тогда и заживём!


                                  Огромное спасибо за эти подробности, невероятно полезная информация (ну лично для меня).


      1. banderos120
        16.01.2017 21:21

        Я не к Laravel в частности, а касательно Lumen-а и бенчмарков, которые Тейлор приложил к нему.


      1. pbatanov
        16.01.2017 22:34
        +1

        А так, сейчас специально замерил два своих приложения — одно классика веб, второе апи, оба локально, dev режим, xdebug, sf 3.2, в каждом по 2-3 десятка бандлов, БД тоже локально в виртуалке (обычный рабочий комп)

        Веб:


        Апи:


        Не вижу ваших сотен метров. То, что простая страничка сонаты отжирает сотню — это вопрос к самой сонате, которую лично я не долюбливаю. Симфони тут не причем.


        1. terkin
          17.01.2017 11:37

          Это blackfire на скринах?


          1. pbatanov
            17.01.2017 11:46
            +1

            Нет, родной встроенный профилировщик symfony

            Блэкфайр в прод режиме выдает по веб приложению вот такую картинку

            blackfire.io


  1. zhigalin
    17.01.2017 12:30

    Избавляемся от статических вызовов

    Это очень сомнительно, как по мне…

    З.Ы. С юбилеем!


  1. Skit25
    17.01.2017 17:41

    Есть еще новость: Yii2 Application Development Cookbook, Дмитрий Елисеев, вчера опубликовал в своем блоге. Он работал над завершением этой книги.

    Статья про уязвимость майлера для тех кто не проверяет отправителя. Но вообще странно, почему эта уязвимость есть, майлеру -то сколько лет…


    1. zelenin
      18.01.2017 04:00
      +1

      Есть еще новость: Yii2 Application Development Cookbook, Дмитрий Елисеев, вчера опубликовал в своем блоге


      в декабре еще вышла, новость есть в прошлом, 99-м, выпуске


      1. Skit25
        18.01.2017 19:46

        ваша правда. Дмитрий так рассказывал про неё, создалось впечатление, что это первая книга с печатного станка. Но теперь мы можем прикинуть, сколько по времени занимает доставка ))


  1. ykushnir
    20.01.2017 12:45

    RFC: Parameter Type Widening
    Implementing this RFC would allow libraries to be upgraded to use type declarations in their method signatures. Currently adding types to a method of a class in a library would break any code that extends that class.

    Если это делается исключительно для того, чтобы обеспечить совместимость старых пакетов с PHP7 + strict types, то я категорически против.