Предлагаем вашему вниманию очередную подборку со ссылками на новости и материалы.
Приятного чтения!
Новости и релизы
- Уязвимости выполнения произвольного кода в PHPMailer и SwiftMailer
- PSR-16: Simple Cache — Принят стандарт интерфейса простого кэша.
- Composer 1.3 — Прислал im_special_one.
- Twig 2.0
- Инициирован форк PrestaShop
- Стандарт цикла событий (event loop) для PHP — Спецификация разработана в рамках инициативы группы PHP Asynchronous Interoperability Group и достигла стабильной версии.
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.
Материалы для обучения
Symfony
- LexikFormFilterBundle, создаем фильтрующие формы еще быстрее
- Symfony 2016 — итоги года
- Статистика контрибьюторов Symfony
- Неделя Symfony #522 (26 декабря 2016 — 1 января 2017)
- Неделя Symfony #523 (2-8 января 2017)
- Неделя Symfony #524 (9-15 января 2017)
Yii
- Разработка на Yii2: использование отладочной панели
- Разработка на Yii2: хелперы
- Плагин Yii 2 для IntelliJ IDEA (PhpStorm)
- 2amigos/yii2-usuario — Гибкое расширение Yii 2 для управления пользователями.
Laravel
- Laravel Dusk уже близко
- garveen/laravoole — Инструмент для запуска Laravel на асинхронных фреймворках Swoole или Workerman.
- phpstorm.tips — Трюки и подсказки по PhpStorm в гифках.
- Как PHP исполняет код
- Самодельные уведомления для Twitter и Gmail с помощью PHP и Arduino
- Избавляемся от статических вызовов
- Мультиязычное приложение на PHP и Gettext
- Закончилась поддержка PHP 5. Что дальше?
- Флаги фич (Feature Flags) в PHP
- Хороший пример использования RabbitMQ в PHP
- Бенчмарк популярных DI-контейнеров
- Полное руководство по загрузке изображений на PHP — Прислал Александр Денисюк.
- Drupal и WordPress — сравнение, аналогии, сходства, различия
- Пакет-географ: готов к работе
- Обнаружение в коде дефекта «разыменование нулевого указателя»
- Хранение php-сессий в Redis с блокировками
- PHPixie Cache: PSR-6, PSR-16 и несколько интересных фич
- Платформа для быстрого создания RESTful API
- Горизонтальное масштабирование. Что, зачем, когда и как?
- Основы безопасности веб-приложений
Аудио и видеоматериалы
- Xdebug в Docker контейнерах
- PHPCon Poland 2016 — Видеозаписи докладов.
- PHP Town Hall Podcast #50: Low down on PSR-15 — O middleware в PHP.
- Подкаст PHP Roundtable 058: HTTPlug, Guzzle & API's
- PHP подкаст #14
Занимательное
- Сравнение метрик кода популярных фреймворков: Laravel, Zend, Symfony, Cake, Slim
- Простой бенчмарк Laravel, Symfony, Zend
- Что сообщество думает о PHP в 2017
- The Zend Blog: Статус PHP в 2017
- PHP код, который выводит буквенно-цифровые символы не используя ни один из них:
<?=($__='`@`@'^'*/).')(($_='->.<:'^'__@[_')('>'^@_,'%'^@_)),$__($_('|'^'=','|'^'&')),$__($_(':'^"\n",';'^']'^@_));
Спасибо за внимание!
Если вы заметили ошибку или неточность — сообщите, пожалуйста, в личку.
Вопросы и предложения пишите на почту или в твиттер.
Прислать ссылку
Быстрый поиск по всем дайджестам
< Предыдущий выпуск: PHP-Дайджест № 99
Комментарии (34)
b1rdex
16.01.2017 08:25+5PHP код, который выводит буквенно-цифровые символы не используя ни один из них
$__='`@`@'^'*/).'; // $__ = 'JoIn' $_='->.<:'^'__@[_'; // $_ = 'range' $__($_('>'^@_,'%'^@_)) // join(range('a', 'z'))
Dumkaaa
16.01.2017 12:50+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
banderos120
16.01.2017 12:50-3Мое лицо, когда Тейлор говорит о справедливых бенчмарках.
SerafimArts
16.01.2017 20:52Справедливости говоря, на крупных проектах Ларка действительно даст фору Симфони (могу лишь сравнивать с ней, опыта с Zend маловато, чтобы утверждать что-то наверняка). Вся фишка в схеме работы и архитектуре:
Внутри Симфони
1) Сбилженный контейнер со всеми сервисами (frozen)
2) Каждый запрос обрабатывается тучей эвентов из разных мест
3) Внутрь контроллеров всовываются в конструктор сервисы через DI
4) Каждый запрос обрабатывают тучи гвардов
Внутри Ларки
1) Контейнер создаётся лениво, в зависимости от поведения приложения
2) Вместо кернел эвентов миддлвари, которые вешаются на определённый запрос, а не на все
3) Сервисы в контроллеры попадают через двойную диспатчеризацию (т.е. как объект Request в контроллеры в симфони)
4) Гвардов в ларке вообще нет, их ответсвенность берут на себя миддлвари, которые см. п.2 — на каждый запрос (или группу запросов) свои.
Подытоживая — из подобной схемы работы ларка более тяжеловесна в сыром виде, симфони же после билда контейнера (в продакшн режиме, например) — летает, но при увеличении количества бандлов в проекте на симфони — жручесть его увеличивается по экспоненте, а ребилд всего в дев режиме может достигать десятков секунд. Доходило до такого, что обычная страничка в сонате (правда с xdebug) отжирала до 100+ мегабайт. В случае же ларки потребление оперативы почти не растёт, т.к. добавление провайдера лишь добавляет дефинишн (зачастую интерфейс, а не алиас сервис-локации, как в симфони) для DI, а он уже загружается когда потребуется в том месте, где он используется и только в нём. Т.е. чистый старт ларки содержит почти что пустой контейнер, в тоже время в симфони он полностью заполненный из всех бандлов.
P.S. Я люблю оба фреймворка, они оба замечательные по-своему =)
pbatanov
16.01.2017 21:201) Симфони создает сервисы лениво. Более того, с ocramius/proxy-manager оно может даже создавать супер-ленивые сервисы (не инициализируются до использования, а не до инстанциирования зависимых). Приведенный бенч (опустим вопрос его предвзятости) показывает, что сбилженный конейтнер имеет свои бонусы по производительности.
2) Можете объяснить принципиальную разницу между мидлварью и листнером на пару событий kernel.request + kernel.response? Я думаю можно однозначно отобразить одно на другое, только вместо замыканий мидлвари отрабатывает EventDispatcher
3) Вот это выглядит странно в Ларе, если честно. Трендовая парадигма Симфони «Controller as a Service» выглядить более логично тут. У Лары это больше похоже на ФП.
4) Можно про тучу гвадров подробней? Если вы про секьюрити гварды, то их не туча, а в зависимости от сматченного фаервола. Если про другие гварды — то нужна конкретика. И, отдельно, чем «туча гвадров» лучше тучи миддлварей?SerafimArts
17.01.2017 01:57В целом, да, каюсь, немного приукрасил конечно, если разбираться, то в симфони после билда контейнера каджый сервис представляет из себя ссылку на метод, который возвращает сам сервис. Так же и по остальным пунктам, за исключением разве что п.2:
Листенер вешается на событие, например kernel.request, миддлваря вешается на роут\группу роутов, отсюда в симфони на каждый реквест реагирует туча классов, скипаются они или нет, но суть в том, что чем больше бандлов, тем больше подписчиков. В ларке же очень редко кто вешается на глобальный перехват, разве что какие-нибудь дебаггеры, почти всегда пакеты предоставляют их набор, а вешать уже предоставляется разработчику.
По остальным пунктам никаких возражений, каюсь =)
pbatanov
17.01.2017 07:58В симфони тоже можно реализовать подобное. Технически, роутинг в симфони — это просто некоторая дыра, которая возвращает вам \callable по данным запроса (по pathinfo в самом простом случае). В пайплайне обработки запроса есть момент, когда этот \callable уже известен, и есть специальное событие, которое позволяет его обработать или подменить. Например, навешать те же миддлвари.
Технически, завязыватсья на роутинг в этот момент сложновато, т.к. в симфони нет «этих ваших» Route::get, роута как такового вообще может не существовать, как сущности (вспоминаем про дыру).
Но если сделать некоторые стандартные допущения (что мы работаем исключительно со стандартным роутингом), то можно получить текущий роут и в зависимости от него (индивидуально, по группе — это уже детали реализации) навешивать миддлвари.
Т.е. если жестко приколотить себя к некоторым ограничениям, то можно сделать абсолютно идентичный механизм
А теперь встречный вопрос — насколько просто в Ларе будет установить те же мидлвари, скажем, считав аннотации у контроллера?
SerafimArts
17.01.2017 10:33То что можно реализовать не значит, что все бандлы реализуют. А проблема как раз в том, что каждый бандл добавляет глобальное поведение из-за чего фрейм работает всё медленнее и медленнее. Именно это печалит.
P.S. Я против роутинга на аннотациях, т.к. в этом случае невозможно указать приоритет, но если надо, то проще воспользоваться готовым: https://laravelcollective.com/docs/5.3/annotations#routes
pbatanov
17.01.2017 11:30Опять же, вы в очередной раз говорите о проблемах сторонних бандлов. Я уверен, что в Ларе тоже можно понабрать таких библиотек, которые зафлудят что угодно.
То, что не все реализуют — это 100%, именно потому, что как я уже сказал, такая реализация (в ядре) привнесет очень много привязок к конкретным решениям. А симфони — оно про заменяемость компонент.
Про аннтоации — вопрос был не конфигурации роутов, а о расширяемости текущией схемы добавления мидлварей в Ларе. Переформулирую. У меня есть группа контроллеров, произвольным образом промаркированных (аннотации, тэги у сервисов, что угодно). Как будет выглядеть конфигурация мидл-варей для них?SerafimArts
17.01.2017 12:43Так проблем в дефолтной поставке симфони никаких нет, всё летает. Но когда последний раз вы видели require у composer.json в симфони из пары-тройки строк? Я не хочу доказать, что N медленнее M де-факто, цель донести мысль о том, что архитектурные решения ларки чуть более эффективны для расширения благодаря ленивости загрузки и "точечности". Даже конфиги в пакетах под ларку почти всегда инициализируются и читаются только после того, как создаётся сервис, который их требует.
А по поводу второго, признаться, я не знаю как ответить на вопрос про миддлвари, т.к. не понимаю самого вопроса. Миддлвари и отвечают за запсук аннотаций, добавление тегов для сервисов и вообще что угодно, хоть за добавление интерфейса пользователя как аутентифицированного внутрь контейнера. А выглядеть это будет примерно как секция defaults в роутах симфони, за исключением того, что эти defaults можно вешать сразу на группу роутов не ссылаясь на внешний ресурс.
pbatanov
17.01.2017 13:23Я примерно о том же. Ларка позволяет делать «более просто» за счет того, что некоторые решения фиксированы (ну по крайней мере, оно так выглядит, я могу ошибаться).
Я правильно понимаю, судя по вашему ответу, что запуск мидлвари, конфигурирующей другие милдвари (т.е читающая аннотации, каждый раз или проверяющая весь контейнер на предмет тегов), будет производиться на каждый запрос? В чем отличие от листнера, который будет проверять, нужно ли запускать другие миддлвари|листнеры|%tool% на каждый запрос?
Как эта мидлваря получит аннотацию конечного контроллера, если поверх него могут быть натянуты еще мидлвари?
Дефолты, если что, тоже можно повесить на группу роутов, если быть точным, то на импортируемый ресурс (yml, аннотации, что угодно). Еще есть options, которые можно устанавливаются и на импортыSerafimArts
17.01.2017 14:401) Не совсем, скорее за счёт того, что никакой фиксации и нет, а провайдер регистрирует лишь сервис в контенере, в отличие от бандлов, требующих довольно жёсткое соблюдение правил именования в т.ч. Указние конфигов и ресурсов в ларке лишь декларация, мол тут у нас A, а тут Б, никаких разборов дерева конфигов.
2) Нет, в ларке нет аннотаций. Как следствие — всё зависит от реализации и в частности о того ридера, что используется. Отличие листенера в от миддлварей в том, что миддлваря жёстко фиксирует вход и выход и инициализируется только в момент аппрува роута. Листенер же подписывается (и создаётся объект с резолвом DI в том числе) на каждый запрос.
3) Как реализуете — так и будет. Но по логике это не задача миддлварь читать аннотации роутинга. Это скорее задача некого сервиса, который добавит их в список готовых при старте приложения. Например внутри Http Kernel, обязанность которого как раз и является загрузка роутов.
4) Я и написал (в самом конце), что дефолтсы можно вешать на группу лишь ссылаясь на внешний ресурс, что вполне годно, но не всегда удобно.
pbatanov
17.01.2017 15:011) Нет никаких жестких правил ). Жесткие правила нужны только в том случае, если вы хотите делать все автомагически (ну, типа quick-start). В остальных случаях вам достаточно имплементировать BundleInterface и зарегистрировать его в ядре. Аналогично с конфигами, расширениями и прочими конфигурациями.
В целом шляпа с резолвом конфигурации нужна затем, что одни бандлы умеют модифицировать конфиги других бандлов + производные параметры. Однако эта операция происходит всего один раз при сборке контейнера и после этого конфиг — это статичный массив, который есть не просит.
2) В симфони тоже нет аннотаций, это формально внешняя библиотека (doctrine/annotations), хоть и рекомендуемая к использованию.
Ну в целом все ваши ответы сводятся к «как реализуете» (и это нормальная позиция), поэтому я считаю дальнейшие распросы бессмысленым, спасибо за информацию. Обычно действительно большая часть зависит от рук разработчика и авторов библиотек.
в Symfony 3.3 сделали ленивые листнеры, в том числе, посмотрите. Я думаю это решит многие из озвученных вами проблем (по флуду листнерами)
Еще раз спасибо за разъясненияSerafimArts
17.01.2017 15:111) Ну это конечно верно, с другой стороны фреймворк всё же ограничивает. Например невозможно указать несколько директорий для сущностей одновременно, работая по DDD модели. Или подключить 10 бандлов внутрь другого, аггрегирующего. и т.д.
2) О, с за ссыль огромное спасибо. Жаль только что у меня в работе пока текущий 2.8 LTS, не скоро насложусь новыми фичами =(
pbatanov
17.01.2017 15:261а) Можно. Потому что, внезапно, доктрина — это не симфони. Поэтому можно долить конфигурацию так, чтобы грузило несколько папок
1б) https://github.com/symfony/symfony/pull/15011#issuecomment-183884227 этого периодически действительно не хватает, но решение вроде как принципиальное на данный момент. Но есть сторонние имплементации https://github.com/mmoreram/symfony-bundle-dependenciesSerafimArts
17.01.2017 15:541а) И всё же doctrine bundle, в отличии от doctrine orm — это часть симфони в некотором роде. И именно она не позволяет указывать в конфигах массивчик папочек для сущностей. Но, верно подмечено, можно переписать этот бандл, чтобы работало. Другой вопрос: а не проще ли забить и "не выпендриваться"? =)
1б) Ещё чего не хватает в симфони ещё двойной диспатчеризации как в ларке. И регистрации сервисов под интерфейсами, а не под алиасами.pbatanov
17.01.2017 16:331а. Ну можно. Вы можете докинуть в метадата-фактори любой альяс + любую папку. Просто это не происходит автоматически.
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% будут конфликты у всяких логгеров и других сервисов, которые генерятся фабрикамиSerafimArts
17.01.2017 21:15Ладно, убедили в том, что я отстал от этой жизни с этим симфони 2.8… =( Буду ждать конца года, там новый LTS должен подъехать, вот тогда и заживём!
Огромное спасибо за эти подробности, невероятно полезная информация (ну лично для меня).
banderos120
16.01.2017 21:21Я не к Laravel в частности, а касательно Lumen-а и бенчмарков, которые Тейлор приложил к нему.
pbatanov
16.01.2017 22:34+1А так, сейчас специально замерил два своих приложения — одно классика веб, второе апи, оба локально, dev режим, xdebug, sf 3.2, в каждом по 2-3 десятка бандлов, БД тоже локально в виртуалке (обычный рабочий комп)
Веб:
Апи:
Не вижу ваших сотен метров. То, что простая страничка сонаты отжирает сотню — это вопрос к самой сонате, которую лично я не долюбливаю. Симфони тут не причем.
zhigalin
17.01.2017 12:30Избавляемся от статических вызовов
Это очень сомнительно, как по мне…
З.Ы. С юбилеем!
Skit25
17.01.2017 17:41Есть еще новость: Yii2 Application Development Cookbook, Дмитрий Елисеев, вчера опубликовал в своем блоге. Он работал над завершением этой книги.
Статья про уязвимость майлера для тех кто не проверяет отправителя. Но вообще странно, почему эта уязвимость есть, майлеру -то сколько лет…zelenin
18.01.2017 04:00+1Есть еще новость: Yii2 Application Development Cookbook, Дмитрий Елисеев, вчера опубликовал в своем блоге
в декабре еще вышла, новость есть в прошлом, 99-м, выпускеSkit25
18.01.2017 19:46ваша правда. Дмитрий так рассказывал про неё, создалось впечатление, что это первая книга с печатного станка. Но теперь мы можем прикинуть, сколько по времени занимает доставка ))
ykushnir
20.01.2017 12:45RFC: 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, то я категорически против.
skiedr
> RFC: Parameter Type Widening
Какой кошмар. А как же принцил Лисков?
Andreyika
А что плохого с принципом случится, если foo все еще будет работать с (в том числе и) массивом?
pbatanov
Вы либо плохо читали RFC, либо подзабыли LSP. LSP разрешает расширение входных параметров и данный RFC как раз таки направлен на то, чтобы соответствовать LSP.
Т.е. если у вас есть класс-наследник с методом, расширяющим сигнатуру базового, то это не противоречит LSP, но в то же время позволяет оперировать терминами будущей совместимости (например вы можете расширить класс, чтобы они принимал не только array, но и \Traversable, и задеприкейтить старый для следующего мажороно релиза). В нынешней реализации это вызовет ошибку
xotey83
Оно как раз не нарушает LSP. Поскольку, применительно к ООП LSP говорит о том, что субтип (дочерний класс) должен расширять родительский класс (интерфейс).
Представим, что есть базовый класс:
Согласно «контракту» метод
foo
должен принимать на вход аргумент строкового или целочисленного типа.И есть использование:
Тут мы говорим о том, что на вход должен поступить объект, являющийся инстансом класса
Parent
, и в методfoo
этого объект мы передаём аргумент. Так как контракт методаfoo
говорит о том, что на вход должен поступить либо строковой либо целочисленный аргумент, то и переменная$arg
тоже должна быть либо строкового, либо целочисленного типа.Тут всё логично.
Теперь представим, что есть класс , перегружающий метод
foo
и сужающий его ОДЗ.В этой ситуации мы инстанс класса
Child
уже не можем передать в функциюbaz
поскольку метод в дочернем классе сужает ОДЗ, а значит мы не можем передать в методfoo
аргумент строкового типа. Таким образом мы имеем нарушение LSP.То, о чём говорит вышеозначенный RFC, так это о том, чтобы в дочерних классах можно было расширять типы аргументов переопределяемых методов. Если тип расширяется, то тогда контракт базового класса не нарушается: поскольку дочерние классы по-прежнему должны принимать на вход аргументы тех типов, которые задекларированы в родительском классе или интерфейсе.
Таким образом, LSP говорит о том, что субтипы не должны сужать супертип. В том числе, переопределение метода в субтипе может расширять ОДЗ метода, но не должно сужать его.
Извините, если ответ получился запутанным или сумбурным.