Свежая подборка со ссылками на новости и материалы. В выпуске: PHP 7.4.0 RC1, Laravel 6, Monolog 2 и другие релизы, Union Types и прочие новости из PHP Internals, порция полезных инструментов, пачка подкастов и многое другое.
Приятного чтения!
Новости и релизы
- PHP 7.4.0 RC1 — Стартовал цикл релиз-кандидатов ветки 7.4. Ожидается всего не менее 6 выпусков для стабилизации.
- PHP 7.1.32, PHP 7.2.22, PHP 7.3.9 — Релизы с исправлениями критичных ошибок безопасности, всем пользователям рекомендуется обновиться.
- Monolog 2.0.0 — После 4 лет разработки представлен Monolog 2.0. Требует PHP 7.2, используются тайпхинты где возможно и strict_types. Добавлены новые хэндлеры (SqsHandler, TelegramBotHandler) и другое. Monolog 1.x будет поддерживаться и дальше.
PHP Internals
- [RFC] Reclassifying engine warnings — Предлагается пересмотреть бросаемые нотисы и ворнинги в движке PHP и поправить классификацию там, где необходимо. Во многих случаях предлагается повысить уровень ошибки: Notice -> Warning, например, при попытке получить свойство у не-объекта, и Warning -> Error exception, например, при попытке использовать скаляр как массив. Ну и «Undefined variable» будет бросать Warning.
- [RFC] Union Types v2 — Предлагается ввести объединённые типы – это значит, что переменная может принимать один из перечисленных типов. Де-факто объединённые типы давно используются в PHPDoc, но теперь они действительно будут проверяться самим интерпретатором.
Предлагаемый синтаксисT1|T2|...
может быть использованы везде, где типы можно указывать сейчас:Скрытый текстclass Number { private int|float $number; public function setNumber(int|float $number): void { $this->number = $number; } public function getNumber(): int|float { return $this->number; } }
В качестве эксперимента RFC оформлен в виде пулл-реквеста и любой желающий может прокомментировать или выразить реакцию в виде emoji. Финальное голосование будет проходить так же, как и раньше на wiki.php.net. Судя по сообщению Никиты, первый эксперимент прошёл неплохо и было получено много ценных комментариев от сообщества. - error_reporting=E_ALL in PHP 8 — В PHP 8 по умолчанию уровень ошибок будет установлен в
E_ALL
вместо текущего:E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
.
Инструменты
- RubixML/RubixML — Активно развивающаяся библиотека для применения машинного обучения на PHP. Доступны примеры: классификация активности человека по данным акселерометра, распознавание объектов на изображениях, прогнозирование цен.
- tsufeki/tenkawa-php-language-server — Реализация LSP для PHP, с выводом типов на основе PHPStan.
- Nyholm/psr7 — Легковесная и строгая реализация PSR-7.
- PHPCompatibility/PHPCompatibility 9.3.0 — Набор правил для PHP_CodeSniffer для проверки кода на совместимость с различными версиями PHP. Добавлены проверки для PHP 7.4.
- dbalabka/php-enumeration — Ещё одна реализация перечислений в PHP, без использования магических методов и Reflection.
- nunomaduro/yorn — Концепт модулей в PHP с синтаксисом 'import' и 'export' а-ля JavaScript. Идея не новая, но занимательная.
Symfony
- Sylius 1.6 — Популярная e-commerce платформа на базе Symfony: обновлённая админка, headless-режим.
- Abstracting API calls with Symfony serializer
- blastcloud/hybrid — Пакет для тестирования запросов Symfony/HttpClient.
- Неделя Symfony #662 (2-8 сентября 2019)
Laravel
- Laravel 6 — На конференции LaraconEU представлено мажорное обновление фреймворка. Это LTS релиз и будет получать обновления безопасности в течение 3 лет. Также теперь релиз следует Semver, а значит версия 7 выйдет уже этой зимой. Более подробно об изменениях на русском, и в видео на Laracasts.
- facade/ignition — Кроме прочего, в Laravel 6 реализована новая страница ошибок. Она базируется на Whoops, но предоставляет больше информации и даже предлагает исправлять простые ошибки не покидая браузера.
- beyondcode/laravel-view-xray — Удобно подсветит и подпишет вьюшки на странице.
- stefanzweifel/laravel-stats 2.0 — Artisan-команда, которая выведет разнообразную статистику кода.
- PHP Townhall #68: Behind the Facade — Taylor Otwell в гостях у Matt Trask и Ben Edmunds обсуждают, что нового в Laravel, бизнес-сторону дел, и организацию LaraconUS.
Yii
Async PHP
- Пишем RESTful API с помощью ReactPHP: Управляем заказами
- clue/reactphp-stdio — Асинхронный инструмент для создания по-настоящему интерактивных CLI-утилит. Пост в поддержку релиза.
Материалы для обучения
- Как использовать провайдеры данных в PHPUnit
- Разгоняем Magento Rest API c помощью RoadRunner
- Определение кодировки текста в PHP вместо mb_detect_encoding
- FFI: пишем на Rust в PHP-программе
- Какое главное отличие Dependency Injection от Service Locator?
- Ищем баги в PHP коде без статических анализаторов c помощью quasilyte/phpgrep.
Аудио/Видео
- Александр Макаров про безопасность в вебе: От базовых принципов до особенностей PHP — Слайды.
- Видеозаписи с Blackfire meetup в Datadog NYC HQ — О профилировании с помощью Blackfire, флейм-графах PHP-приложений в продакшене, разработке кэшируемых PHP-приложений.
- PHP Internals News #26 — О подготовке Symfony к PHP 7.4 с Nicolas Grekas.
- PHP Internals News #25 — Со Стасом Малышевым о вопросах безопасности при разработке интерпретатора PHP.
- Девшахта-подкаст с Петром Мязиным (Пятиминутка PHP) — Версус: Node.js или PHP в 2019.
- Пятиминутка PHP #65 — Современный WordPress в 2019 году.
- Пятиминутка PHP #66 — Переменные окружения и PHP.
- Пятиминутка PHP #67 — DDD #4 – Entity
Сообщество
- Matthew Weier O'Phinney, лидер Zend Framework (Laminas) и один из основателей PHP-FIG, закончил работу в Zend и ищет новое место
- Автор Xdebug Derick Rethans рассматривает возможность сделать Xdebug 3 платным для коммерческого использования. На что Joe Watkins ответил, что экосистеме нужен бесплатный отладчик и в таком случае он будет вынужден реализовать альтернативное расширение.
Спасибо за внимание!
Если вы заметили ошибку или неточность — сообщите, пожалуйста, в личку.
Вопросы и предложения пишите на почту или в твиттер.
Больше новостей и комментариев в Telegram-канале PHP Digest.
Прислать ссылку
Поиск ссылок по всем дайджестам
< Предыдущий выпуск: PHP-Дайджест № 163
Комментарии (45)
bm13kk
09.09.2019 11:17> [RFC] Object Initializer
Реализация завязана на публичные методы. Первое (и единственное для меня) место где это нужно — в доктрине — не заработает.
Могло бы взлететь, если бы в пыхе были бы public final атрибуты — это когда один раз засетил и потом нельзя менять. Тогда можно все dependency полностью убрать из конструктора и сделать публичными. Что в свою очередь сократит очень много бойлерплейта.
michael_vostrikov
09.09.2019 20:27-2Union Types
Спрашивал об этом Расмуса на конференции, он сказал что решили не делать, лишние сложности и мало пользы. Оказывается, не все у них так считают. Как по мне, полезная штука. Только надо бы конструкцию для паттерн-матчинга на вызывающей стороне сделать.
michael_vostrikov
09.09.2019 23:29Кто-то не согласен, что раз на передающей стороне (выход функции) появились новые возможности, то надо и на принимающей (место вызова) сделать средства их обработки? Или просто с тем, что это полезно? Раз в других языках делают, то наверно есть какая-то польза от этого.
spasibo_kep
09.09.2019 22:51Привет, еще из, надеюсь, кому-то полезного: мы делаем PHP-митапы в Самаре 28-го сентября и Ульяновске 19-го октября — приходите или приезжайте, если где-то рядом)
OnYourLips
Думаю, что самым обсуждаемым будет Union Types v2.
Крайне не хотел бы его введения, будет помогать писать некачественный код.
levchick
<sarcasm_mode>Останется только добавить mixed, который позволит использовать любой тип</sarcasm_mode>
Hett
А потом и вовсе отказаться от статической типизации. И так по кругу.
psycho-coder
Согласен. Не вижу смысла его вводить после введения строгой типизации. А вы проголосовали в pull-request?
yaroslavche
Не согласен. Почему сразу некачественный код? Лично мне нравится предложение
Union Types
. Бывают ситуации, когда нужно вернуть/передать какой-то тип вместе с другим (например,?string
). Теперь же можно будет добавить и еще каких-то типов, если нужно. Что в этом плохого? Лично я бы не пропагандировал их использовать везде, но это хорошая возможность управление данными. Сходу так сложно придумать пример из жизни, но они точно есть. Еще, к примеру, много встроенных функций языка возвращают комбинированные типы. И с этим прекрасно справляется статический анализатор. Насколько будет проще, когда не нужно будет писать PHPDoc комменты с пояснением, что за тип будет у переменной. PHP уже давно движется к полной строгой типизации, и в этом нет ничего плохого. Некачественный код получается не тогда, когда в языке есть возможность, а тогда, когда эти возможности используют бездумно. И сейчас язык вполне себе помогает писать некачественный код, даже безUnion Types
.levchick
Соглашусь с Вами, что некачественный код можно написать тысяча и одним способом и сейчас. Но вот предложение тоже не поддерживаю. Когда язык обязывает указывать строго один тип (в крайнем случае nullable), вам так или иначе придется преобразование типов выносить либо наверх, либо в другой метод, тем самым упрощая этот конкретный метод, избавляя его от необходимости обрабатывать несколько типов. В других строго-типизированных языках такие проблемы решаются перегрузкой, когда для разного набора аргументов (в том числе других типов) определяется другой одноименный метод, реализующий требуемую логику именно для такого набора. Вычитать такой код будет куда проще, чем когда все в одной куче. И уж если PHP идет в сторону более строгой типизации, то было бы логичнее придерживаться более строгого подхода и в данном случае тоже, и вполне достаточно того, что можно типы не указывать вообще. ИМХО, естественно.
yaroslavche
levchick согласен по поводу декомпозиции. Но бывают ситуации, когда всё-таки нужно обработать несколько типов. Сейчас это только
mixed
. Помоему, сUnion Types
типизация станет намного строже в данных случаях. Я как раз-таки и смогу контролировать типы, а не использоватьmixed
и внутри метода проверять, а что же там пришло в аргументе.levchick
Так может декомпозировать и эти ситуации?:) Моя идея в том, что если язык движется в сторону строгости, то и разработчики должны писать более строгий код и стараться избегать ситуаций, где допустимы несколько типов одного аргумента или возвращаемых значений. Там где "капец как надо" или для легаси останется возможность тип не указывать вообще. А принятие этого предложения фактически легализует возможность юзать несколько типов везде где надо и не надо, что точно не приведет к росту качества php-кода.
yaroslavche
Как пример (сильно не пинайте, возможно я чёт не правильно понимаю =) ):
Что мы имеем: я не проверяю, вернёт ли json_encode false, просто говорю в сигнатуре, что может вернуть false, и это уже проблема пользователя функции, а не моя. Если захочет — проверит и выкинет исключение. Так же я явно указываю, что метод примет или массив, или объект какого-то интерфейса. Остальное будет
TypeError
, и не нужно писать проверок и создавать и выбрасывать свои исключения. Замечательно же, нет?levchick
В этом случае нужно в phpDoc описать в каких случаях у вас будет false. Кроме этого, чтобы получить информацию о том, почему же все таки false, пользователю метода нужно будет догадаться вызвать
json_last_error
, а если вы вдруг решите метод поменять и парсить json как-то по другому? Здесь как раз таки намного разумнее кинуть исключение, если string не может быть возвращен, с описанием собственно почему, а пользователю уже решать, что с этим делать.yaroslavche
Хмм… Хорошее замечание, я даже не подумал об этом. Но
json_decode
чисто для примера. Представьте, что это метод, который принимает или объект или массив для инициализации объекта и возвращает строку или false. Да, наверное, логичнее было бы вернуть ?string.levchick
Так проблема то собственно не в json, а в том, что вы должны
false
(то есть от phpdoc мы не избавимся)И это все решается как раз таки механизмом исключений.
Пример, когда возвращается либо результат, либо false, в принципе очень не удачен. Для того же
json_decode
в 7.3 ввели опциюJSON_THROW_ON_ERROR
, чтобы в случае ошибки неfalse
возвращать, а исключение кидать. И в целом этот подход считается одним из самых не удачных во встроенных функциях phpyaroslavche
Хорошо, я согласен что return-type не лучший вариант для использования в данном конкретном примере. И честно говоря, я бы на самом деле делал с исключениями, как Вы и говорите, я просто стараюсь отстоять мнение, что
Union Types
это скорее хорошо, чем плохо. Например, что скажете, если я хочу в метод аргументом передатьarray|MyClassInterface
и ничего более?jetexe
Я, например, скажу, что это плохой код. Если вам надо обрабатывать массив — делайте метод который принимает массив.
levchick
Давайте по-рассуждаем, что может быть внутри такого метода и как это можно было бы реализовать по другому
Очевидно что, для MyClassInterface и для array логика обработки разная либо нам нужно привести аргументы к одному типу, тогда ваш метод будет выглядеть примерно так
Я бы не назвал это хорошим кодом. В данном методе как минимум два блока кода с разной логикой, которая явно напрашивается быть разбитой на два метода. Кроме того, что если потребуется реализовать
decode
для какого-нибудь другого типа? Нам придется модифицировать метод и добавлять еще одно условие и т.д.В классических языках со строгой типизацией это бы решилось простой перегрузкой и код превратился бы в что-то типо того
И таким образом компилятор/интерпретатор бы сам решал, какой метод использовать в зависимости от аргумента. К сожалению, в php такой код работать не будет, но мы можем реализовать его немного по другому:
Таким образом, если нам необходимо будет реализовать decode для чего-то еще нам нужно всего лишь добавить еще один метод (а не модифицировать старый Open/Closed из SOLID) и мы гарантированно не сломаем то, что уже работает.
Либо, если
array
можно представить в видеMyClassInterface
, то реализоватьMyArrayClass
, который бы создавался из массива и имплементировалMyClassInterface
, и у нас бы осталсяdecode
с одним типом аргумента. Ну и конечно наоборот, когдаMyClassInterface
можно представить в виде массива…Вот по этому я считаю, что Union Types нужен в большинстве случаев для того, чтобы засахарить тот код, который стоило бы отрефакторить, и фактически легализует написание кода из примеров выше.
molchanoviv
Единственный валидный кейс который я вижу это в функции дергающей внешнее апи возвращать SuccessResponse или ErrorResponse в зависимости от того что вернуло апи, но как по мне этого явно недостаточно для введение такой сомнительной фичи.
levchick
Так пусть возвращаемым типом будет
ResponseInterface
, аSuccessResponse
иErrorResponse
будут его имплементировать. И фич никаких не нужно.molchanoviv
Именно так я и делаю. Я просто привёл более-менее валидный кейс. Сам я тоже против такой фичи.
yaroslavche
Не совсем согласен. Допустим, у меня массив с параметрами инициализации дефолтного объекта
MyClassInterface
. Что-то типа такого:Это нужно читать так: я предоставляю метод, который является оберткой к decode и может принимать разные типы аргумента. Но не любые. Это должен быть или массив для инициализации объекта, или сам объект. Да, я могу предоставить два метода для
decodeArray
и дляdecodeMyClass
. А могу один. Соблюдая строгую типизацию.Т.е. я просто привожу типы в одном методе, а реализация по факту одна —
MyClassInterface::decode
. Так же в Вашем примере всё также нужно проверить, какой тип пришел, что бы вызвать соответствующий метод и нужно так или иначе полагаться на mixed (где-то же Вы должны решить какой из методовdecodeArray
илиdecodeMyClass
вызвать) и выбрасывать исключение, если это неarray
илиMyClassInterface
. В случае с Union Type всё что неarray|MyClassInterface
будет автоматическиTypeError
, а в Вашем случае — не факт что разумно названное исключение (если не простоException
илиInvalidArgumentException
).По этому мне в коде достаточно проверить, массив ли это, если да — преобразовать, потом на всякий случай проверить преобразовало ли, если был массив (потому что иначе это в любом случае
MyClassInterface
), а потом вызватьMyClassInterface::decode
. Более того, не всякий массив подойдёт и может сфейлится конструктор, к примеру. То, о чем Вы говорите, и как есть сейчас — придется в любом случае проверить тип, и писать свитч? (утрирую, извините =) )А вообще, это можно, видимо, долго спорить =) Кто-то из нас не полностью прав в отношении к
Union Types
. Возможно я. Возможно Вы. Увидим после голосования =)P.S. решил почитать больше информации. Нашел уже отклоненный v1. Надо изучить подробней, чем они отличаются, а то судьба у первой версии незавидная.
psycho-coder
Понимаю, что это пример. Но, что можно делать методом decode() с массивом?
yaroslavche
тот метод можно назвать как угодно. Пускай это будет
doSomething
и принимать не массив, а что-то другое. Допустим — string. Не цепляйтесь за слова, пожалуйста.psycho-coder
Хорошо, не буду цепляться.
Данный пример мне очень сильно напоминает WordPress, с их WP_Post|Int|Null и пачкой проверок внутри. В связи с этим и хочется найти практическое применение UT, а не примеры в вакууме. Сам я пока не могу придумать, где и как такое применять.
yaroslavche
Думаю, Вы согласитесь, что это совсем не означает, что кейсов не существует. Как минимум — это отказ от типов в аннотациях (наконец-то). Еще фичи, что мне нравятся: type alias, псевдотипы, нормальный nullable (а не ?), В PR не сравнивают это с WordPress, и видимо, видят кейсы, судя по комментариям.
Не знаю. Мне нравятся UT. Если Вам нет — не пользуйтесь, никто же насильно не будет заставлять. Я устал дискутировать, честно говоря. За сим откланяюсь.
michael_vostrikov
С Union Types можно это исключение просто вернуть. Его и сейчас можно вернуть, только обрабатывать это неудобно, и контролировать сложнее, надо не использовать типизацию вообще.
arturpanteleev
Такой метод не должен возвращать false
Он должен или возвращать строку если все получилось, или кидать исключение, если что то пошло не так.
yaroslavche
Не должен, но
json_encode
возвращает. И не только эта функция. В данном конкретном примере я предоставляю метод который возвращает результат работы функции SPL. Допустим там еще много вычислений перед возвратом. Конечный пользователь может не использовать метод, посчитать сам и использоватьjson_encode
, если ему больше нравитсяreturn false
оттудаyaroslavche
К слову, нам и не нужно возвращать false, т.к. благодаря union types у нас гарантировано (я так думаю) будет строка. И исключений выбрасывать не нужно. В общем, это просто пример.
arturpanteleev
с версии 7.3 он уже может кидать исключение при указании JSON_THROW_ON_ERROR
Ну и в целом стандартная либа php явно не образец для подражания в плане качественого API
yaroslavche
Ну, как-бы, читать не надо, да. Главное — вцепиться в конкретный пример с json_encode =) Я на всё это выше уже отвечал. Не вижу смысла повторять еще раз для того, кто не читает =)
t_kanstantsin
Пример json_encode как раз показывает, что такой подход не многим нравится. Если бы такое поведением было приемлемым, то его бы не меняли.
psycho-coder
Поддерживаю. Хотя в некоторых ситуациях использую ?Type, чтобы вернуть null.
a_mazur
Возможно Вы имеете в виду «вернуть несколько аргументов из метода» — так для этого Union Types не нужен — с этим вполне справляется и массив (как минимум):
В C# для этого завезли кортежи, в Java можно часто встретить что-то типа:
Что к слову тоже не является примером отличного кода — ведь как так? Вы не знаете какой тип Вы должны вернуть и прибегаете к обобщенному коду?
Ну так это влияние других ЯП e.g., Java/C#, что к слову не самое топовое решение, почитайте про null pointer hell.
А вот это вообще отдельная песня. SPL уж точно не является примером для подражания. Нашумевшая, хоть уже и несколько устаревшая статья «PHP — fractal of bad design» является отличной иллюстрацией моих слов.
Я возможно скажу что-то новое для Вас, но PHPDoc комменты нужны скорее для того, чтобы понять зачем «интерфейсу» метода нужны те или иные параметры. Типы PHPDoc'a уже не так нужны, если Вы не работаете со старым legacy кодом конечно.
Согласен, вот только сама возможность использовать Union Types не будет помагать с решением этой проблемы ничем — только усугублять.
yaroslavche
Нет же. Я как раз о возвращаемом типе значения. Допустим — это или int, или string.
Полностью согласен, ведь я говорил не об возврате нескольких значений, а о типе.
Тем не менее, к сожалению, я вынужден ней пользоватся. А там есть функции возвращающие значение, которое может быть разным типом.
PHPDoc комменты нужны также для автокомплита в IDE, например где то в теле метода я получил обьект, но у метода не было return-type и IDE не знает что это, ну я и пишу:
так же указание типов в PHPDoc важно и для статических анализаторов.
a_mazur
К сожалению, мы все вынуждены ей пользоваться. Но Вы ведь понимаете, что union types не сделает SPL лучше?
Как говорили выше — куда лучше выбрасывать ошибку в непонятной ситуации, а не false.
Ну и как бы там ни было — ни того ни другого скорее всего в SPL не будет, твит на тему.
Опять таки, ну и чем Вам здесь поможет union types?
Как бы то ни было, я просто хочу подрезюмировать свое отношение к данному предложению — строго отрицательное. И вот почему: жизнь это не упростит аж никак (ну хочется прогеру поговнокодить, вернуть несколько различных типов — никто же не заставляет писать m():types), а вот потенциальных неприятных вещей добавит уж точно.
yaroslavche
Понимаю, и не утверждаю, что сделает
а тем, что вместо написания union types в PHPDoc я буду писать его в коде, там где мне нужно. И не нужно говорить о том, что это всё надо рефакторить, я это понимаю. Просто у меня уже привычка в PHPDoc писать тип для свойства класса. В 7.3 эта привычка не нужна (хотя я честно говоря еще особо не пользовался 7.3 =)). Так же мне иногда приходится писать union types в PHPDoc для статического анализатора (и не только потому, что мне так хочется). Честно говоря, я был бы не против иметь возможность писать эти типы "легально", а не с помощью аннотаций. По моему это просто самый обычный самодокументирующийся код. Но опять же, я прекрасно понимаю, что могу ошибаться. Ну хочется мне поговнокодить, что поделать. Вам от этого хуже не будет =) Я вообще считаю, что как минимум union types лучше, чем вообще не указывать ничего, если таки нужно вернуть/передать не единственный тип. А такие случаи реальны, их не нужно списывать со счетов, потому что это "говнокод".
i80586
Согласен. Тем более что вряд ли будет разрешено использовать мульти-объекты: getModel(): Post|Category
yaroslavche
i80586 думаю, скорее всего будет можно, но я могу ошибаться. В данном конкретном случае, если у Вас больше двух моделей, то лучше использовать какой-то
ModelInterface
в return-type, ИМХО. Но если именно хотите эти два класса — то ок, почему нет? Вот есть у меня их 3, а я хочу разрешить только 2 для метода.Union types
поможет разрешить передачу/возврат только определенных типов данных, и, по факту, отказаться отmixed
.i80586
Понимаю. Но тогда для IDE будет путаница какой класс использовать в данном случае в качестве подсказчика.