Друзья, приглашаю к себе в команду Middle/Senior разработчиков!
Москва, Южная/Чертановская, полный рабочий день, 140-220к.
Предметная область — анализ вовлеченности и лояльности сотрудников.
У нас PHP 7.4, Symfony 5, PostgreSQL, CQRS, DDD, event-driven архитектура и unit-тесты.
От кандидата ждем уверенного владения PHP 7.x, ООП, SQL и понимания вышеупомянутых концепций.
Подробнее на странице вакансии https://happy-job.ru/vacancy-super-php-2020-02.
Можете писать мне в ЛС.
На фото наш техотдел 🤗
Москва, Южная/Чертановская, полный рабочий день, 140-220к.
Предметная область — анализ вовлеченности и лояльности сотрудников.
У нас PHP 7.4, Symfony 5, PostgreSQL, CQRS, DDD, event-driven архитектура и unit-тесты.
От кандидата ждем уверенного владения PHP 7.x, ООП, SQL и понимания вышеупомянутых концепций.
Подробнее на странице вакансии https://happy-job.ru/vacancy-super-php-2020-02.
Можете писать мне в ЛС.
На фото наш техотдел 🤗
Вышел первый пакет Yii3
Принцип именования: исключение должно само иметь "Human understandable name", а не имплементировать лишний метод
Принцип разделения интерфейсов. Метод
Помимо этого интерфейс почему-то не наследует
В целом пакет выглядит бесполезным без обработчика этого самого
yiisoft/friendly-exception
. Он состоит из одного интерфейса https://github.com/yiisoft/friendly-exception/blob/master/src/FriendlyExceptionInterface.php, который нарушает как минимум два принципа.Принцип именования: исключение должно само иметь "Human understandable name", а не имплементировать лишний метод
getName()
. Имя класса — это и есть главное название, а для дополнительной информации предусмотрен стандартный метод getMessage()
.Принцип разделения интерфейсов. Метод
public function getSolution(): ?string
обуза, потому что при имплементации интерфейса без предполагаемого решения придется добавлять плейсхолдер return null
. Вместо этого правильнее было сделать отдельный интерфейс с сигнатурой без null
, например:interface SolutionAwareExceptionInterface extends Throwable
{
public function getSolution(): string;
}
Помимо этого интерфейс почему-то не наследует
Throwable
,
что позволяет использовать его вне контекста исключений. Хорошая практика — максимально ограничивать контекст использования для предотвращения выстрелов в ногу.В целом пакет выглядит бесполезным без обработчика этого самого
FriendlyException
. Это интерфейс ради интерфейса. Задача, которую он якобы решает, настолько тривиальна, что при необходимости проще решить её в приложении самому, чем тащить еще одну библиотеку.GitHub
friendly-exception/src/FriendlyExceptionInterface.php at master · yiisoft/friendly-exception
An interface for an exception to be friendly. Contribute to yiisoft/friendly-exception development by creating an account on GitHub.
В Symfony тоже спорную фичу добавили: https://symfony.com/blog/new-in-symfony-5-1-autowire-public-typed-properties.
Публичные свойства хороши в DTO, но в сервисах они — зло! Сервисы должны быть инкапсулированы, зависимости в них не должны меняться после инициализации. Не стоит пользоваться этой новой фичей, она очевидный антипаттерн.
Прокидывайте сервисы по классике через конструктор в приватные поля и следите за тем, чтобы инъекций было не больше трех, а в идеале ноль или одна.
Публичные свойства хороши в DTO, но в сервисах они — зло! Сервисы должны быть инкапсулированы, зависимости в них не должны меняться после инициализации. Не стоит пользоваться этой новой фичей, она очевидный антипаттерн.
Прокидывайте сервисы по классике через конструктор в приватные поля и следите за тем, чтобы инъекций было не больше трех, а в идеале ноль или одна.
Symfony
New in Symfony 5.1: Autowire public typed properties (Symfony Blog)
In Symfony 5.1, public properties typed with classes related to services are autowired automatically, which is equivalent to the traditional setter injection.
В PHP 8 появится функция get_debug_type.
Вместо
Но необязательно ждать релиза PHP 8 — можно установить полифил от Symfony и пользоваться функцией в PHP 7.x!
Вместо
is_object($value) ? get_class($value) : gettype($value)
можно будет писать get_debug_type($value)
. Полезно, например, для исключений:throw new InvalidArgumentException(sprintf('Expected string, got %s', get_debug_type($arg)));
Но необязательно ждать релиза PHP 8 — можно установить полифил от Symfony и пользоваться функцией в PHP 7.x!
composer req symfony/polyfill-php80
GitHub
GitHub - symfony/polyfill-php80: Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions
Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions - symfony/polyfill-php80
Пых — блог Валентина Удальцова о разработке на PHP.
На канале не размещается реклама и вакансии.
Полезные ссылки:
• основной чат канала Пыхтелка,
• чат Пыхтелка Symfony,
• канал на YouTube PHPPoint,
• канал с мемами PHP умирает?!,
• пост про мои консультации,
• статистика канала на Telegram Analytics,
• Patreon.
На канале не размещается реклама и вакансии.
Полезные ссылки:
• основной чат канала Пыхтелка,
• чат Пыхтелка Symfony,
• канал на YouTube PHPPoint,
• канал с мемами PHP умирает?!,
• пост про мои консультации,
• статистика канала на Telegram Analytics,
• Patreon.
Telegram
Валентин Удальцов
Я обязательно исправлюсь в следующей жизни.
🔥1
В Psalm скоро появятся условные типы как в TypeScript.
Поиграться можно тут: https://psalm.dev/r/5fb0ea4228 .
Источник: https://twitter.com/psalmphp/status/1241744682494971904 .
Подробнее в issue: https://github.com/vimeo/psalm/issues/3005 .
/**
* @template T as string|list<string>
* @psalm-param T $name
* @psalm-return (T is string ? Connection : array<string, Connection>)
*/
public function getConnection($name) {
// ...
}
Поиграться можно тут: https://psalm.dev/r/5fb0ea4228 .
Источник: https://twitter.com/psalmphp/status/1241744682494971904 .
Подробнее в issue: https://github.com/vimeo/psalm/issues/3005 .
Twitter
Psalm
Quarantine update: was bored, so decided to implement TypeScript's conditional types in Psalm. You can play with the prototype here: https://t.co/Roc7rm90Ao
Вышла новая мажорная версия популярной библиотеки ramsey/uuid. Из описания следует, что серьезных нарушений обратной совместимости в ней нет, а вот новых интерфейсов и исключений там целый список.
Изучаем изменения в документации и обновляемся
На мой взгляд, самое интересное — это поддержка пока нестандартизированного UUID v6. Новая версия UUID предложена специально для использования в качестве первичного ключа БД и обладает следующими свойствами:
- Сортировка по необработанным байтам приводит к последовательности, эквивалентной сортировке по встроенной временной метке.
- Встроенное время может быть извлечено для использования в качестве времени создания.
- Глобальная уникальность, которая является основным требованием для всех типов UUID.
Про отличия версии 6 от версии 1 и другие подробности можно прочитать в IETF черновике.
Изучаем изменения в документации и обновляемся
composer req ramsey/uuid:^4.0
.На мой взгляд, самое интересное — это поддержка пока нестандартизированного UUID v6. Новая версия UUID предложена специально для использования в качестве первичного ключа БД и обладает следующими свойствами:
- Сортировка по необработанным байтам приводит к последовательности, эквивалентной сортировке по встроенной временной метке.
- Встроенное время может быть извлечено для использования в качестве времени создания.
- Глобальная уникальность, которая является основным требованием для всех типов UUID.
Про отличия версии 6 от версии 1 и другие подробности можно прочитать в IETF черновике.
GitHub
Release 4.0.0 · ramsey/uuid
Read the upgrade guide for details on how these changes may impact your code and what you can do to ease the upgrade process.
Added
Add support for version 6 UUIDs, as defined by http://gh.peabod...
Added
Add support for version 6 UUIDs, as defined by http://gh.peabod...
Чтобы узнать, какие пакеты пора обновить, используем команду
Желтым будут выделены зависимости, которые обновились в мажорной версии. В соответствии с правилами семантического версионирования мажорный релиз допускает нарушение обратной совместимости. Это означает, что обновление такого пакета потребует времени — нужно будет почитать заметки к релизу, проверить все сценарии и места использования и скорее всего покодить. Не стоит сразу накидываться на новые мажорные версии — пусть настоятся, получат свои хотфиксы.
Красным будут выделены зависимости, которые обновились в минорной или патч версиях. Такие релизы не должны нарушать обратной совместимости, при условии, конечно, что авторы библиотек знают про принципы версионирования. Патчи рекомендую накатывать сразу — скорее всего они содержат багфиксы или закрывают уязвимости. Минорные апдейты, как правило, содержат новые фичи и депрекации старых. Тут обновляемся по вкусу, но тоже лучше не затягивать, иначе потом все за один присест придется осваивать.
Чтобы скрыть мажорные апдейты (наличие которых форсирует желтый цвет даже если пакет в текущем мажоре получил патч), используем флаг
Про остальные флаги и другие полезные команды читаем в официальной документации Composer.
composer outdated
или просто composer out
.Желтым будут выделены зависимости, которые обновились в мажорной версии. В соответствии с правилами семантического версионирования мажорный релиз допускает нарушение обратной совместимости. Это означает, что обновление такого пакета потребует времени — нужно будет почитать заметки к релизу, проверить все сценарии и места использования и скорее всего покодить. Не стоит сразу накидываться на новые мажорные версии — пусть настоятся, получат свои хотфиксы.
Красным будут выделены зависимости, которые обновились в минорной или патч версиях. Такие релизы не должны нарушать обратной совместимости, при условии, конечно, что авторы библиотек знают про принципы версионирования. Патчи рекомендую накатывать сразу — скорее всего они содержат багфиксы или закрывают уязвимости. Минорные апдейты, как правило, содержат новые фичи и депрекации старых. Тут обновляемся по вкусу, но тоже лучше не затягивать, иначе потом все за один присест придется осваивать.
Чтобы скрыть мажорные апдейты (наличие которых форсирует желтый цвет даже если пакет в текущем мажоре получил патч), используем флаг
--minor-only (-m)
.Про остальные флаги и другие полезные команды читаем в официальной документации Composer.
Semantic Versioning
Semantic Versioning 2.0.0
Semantic Versioning spec and website
Теперь у Symfony тоже есть библиотека для работы с UUID:
ramsey/uuid
- процесс генерации реализован прямо в библиотеке и разложен по ООП полочкам, легко расширяется;
- поддержка GUID;
- поддержка экспериментального UUID v6;
- интеграции: ramsey/uuid-doctrine , ramsey/uuid-console .
symfony/uid
- элементарная обёртка над полифилом symfony/polyfill-uuid, который имитирует функционал PHP-расширения UUID и при этом работает быстрее;
- поддержка UUID v6;
- поддержка ULID;
- обсуждаются планы по интеграции с другими компонентами и библиотеками.
Как только допилят интеграцию, можно будет в новых проектах ставить
____
Есть недовольные, мол, Symfony продолжает добавлять компоненты, которые заменяют существующие неплохие проекты. Возможно, имеется в виду
Мое мнение, что если пакет лицензирован MIT, то по определению ни у кого не должно быть никаких претензий к тем, кто создает похожие библиотеки.
Во-вторых, Symfony не всегда делает хорошо, например, к тому же Messenger и другим компонентам немало вопросов по архитектуре. Разработки Symfony никак не блокируют стремление к прекрасному, скорее стимулируют. Да и в целом конкуренция — это почти всегда хорошо, она препятствует застою, предоставляет выбор. Может быть Ben Ramsey не релизнул бы 4.0 еще полгода, если бы Symfony не анонсировала свой UID 😉
composer req symfony/uid
. Сравним.ramsey/uuid
- процесс генерации реализован прямо в библиотеке и разложен по ООП полочкам, легко расширяется;
- поддержка GUID;
- поддержка экспериментального UUID v6;
- интеграции: ramsey/uuid-doctrine , ramsey/uuid-console .
symfony/uid
- элементарная обёртка над полифилом symfony/polyfill-uuid, который имитирует функционал PHP-расширения UUID и при этом работает быстрее;
- поддержка UUID v6;
- поддержка ULID;
- обсуждаются планы по интеграции с другими компонентами и библиотеками.
Как только допилят интеграцию, можно будет в новых проектах ставить
symfony/uid
просто из-за скорости работы.____
Есть недовольные, мол, Symfony продолжает добавлять компоненты, которые заменяют существующие неплохие проекты. Возможно, имеется в виду
symfony/messenger
, который оставил в тени simple-bus/simple-bus
.Мое мнение, что если пакет лицензирован MIT, то по определению ни у кого не должно быть никаких претензий к тем, кто создает похожие библиотеки.
Во-вторых, Symfony не всегда делает хорошо, например, к тому же Messenger и другим компонентам немало вопросов по архитектуре. Разработки Symfony никак не блокируют стремление к прекрасному, скорее стимулируют. Да и в целом конкуренция — это почти всегда хорошо, она препятствует застою, предоставляет выбор. Может быть Ben Ramsey не релизнул бы 4.0 еще полгода, если бы Symfony не анонсировала свой UID 😉
Изучаем свежезакрытые уязвимости в Symfony и обновляем
https://symfony.com/blog/cve-2020-5274-fix-exception-message-escaping-rendered-by-errorhandler
https://symfony.com/blog/cve-2020-5255-prevent-cache-poisoning-via-a-response-content-type-header
https://symfony.com/blog/cve-2020-5275-all-access-control-rules-are-required-when-a-firewall-uses-the-unanimous-strategy
Советую просматривать CVE и разбираться, в чем была проблема и как её решили. Это отличная возможность поучиться на чужих ошибках и начать писать более безопасный код.
Но никогда не обольщайтесь на эту тему. Если ваша система не проходит регулярный профессиональный аудит силами внутреннего отдела безопасности или внешней службы на аутсорсе — я могу с уверенностью сказать, что она уязвима.
4.4.x
до 4.4.7
и 5.0.x
до 5.0.7
.https://symfony.com/blog/cve-2020-5274-fix-exception-message-escaping-rendered-by-errorhandler
https://symfony.com/blog/cve-2020-5255-prevent-cache-poisoning-via-a-response-content-type-header
https://symfony.com/blog/cve-2020-5275-all-access-control-rules-are-required-when-a-firewall-uses-the-unanimous-strategy
Советую просматривать CVE и разбираться, в чем была проблема и как её решили. Это отличная возможность поучиться на чужих ошибках и начать писать более безопасный код.
Но никогда не обольщайтесь на эту тему. Если ваша система не проходит регулярный профессиональный аудит силами внутреннего отдела безопасности или внешней службы на аутсорсе — я могу с уверенностью сказать, что она уязвима.
Symfony
CVE-2020-5274: Fix Exception message escaping rendered by ErrorHandler (Symfony Blog)
CVE-2020-5274 fixes Exception message escaping rendered by ErrorHandler.
Недавно обновил
Первое, что приходит в голову, захардкодить в
Другой вариант — переписать ограничение в
Я предпочитаю добавлять проблемные версии в секцию conflict. Так я могу свободно менять глобальный констрейнт в
vendor/package
до 3.18.1
, а там баг. Понятное дело, сразу создал тикет, но как быть в проекте, пока он не закрыт?Первое, что приходит в голову, захардкодить в
require
версию 3.18.0
. Это самый плохой вариант, потому что через какое-то время выйдет новая версия, там все пофиксят, добавят фич, а я так и буду сидеть на 3.18.0
даже после composer update
. Это ещё и небезопасно, ведь так можно пропустить security patch. Это как нарушить open/closed — стандартное обновление не работает, а чтобы обновить нужно руками править composer.json.Другой вариант — переписать ограничение в
require
на ^3.18, !=3.18.1
, но, на мой взгляд, такую запись будет труднее воспринимать визуально. Кроме того, правило исключения в этой секции второстепенно.Я предпочитаю добавлять проблемные версии в секцию conflict. Так я могу свободно менять глобальный констрейнт в
require
/ require-dev
и при необходимости точечно подправлять его в conflict
.{
"name": "vudaltsov/phpyh",
"require": {
"vendor/package": "^3.18"
},
"conflict": {
"vendor/package": "3.18.1"
}
}
getcomposer.org
The composer.json schema - Composer
A Dependency Manager for PHP
📖 Правильная регистрация консольных команд Symfony в DI
Год назад на одном большом проекте исследовал мучительный баг. Команда
И вот наконец-то на выходных нашел время оформить подробный разбор проблемы.
Добро пожаловать на обновленный профиль на медиуме, где вы, возможно, читали мою статью Не игнорьте composer.lock.
http://bit.ly/3hnPoIs
Год назад на одном большом проекте исследовал мучительный баг. Команда
bin/console cache:clear
при локальном развертывании и прогонах в CI требовала подключения к БД и Redis. Какого черта, я же просто компилирую контейнер?!И вот наконец-то на выходных нашел время оформить подробный разбор проблемы.
Добро пожаловать на обновленный профиль на медиуме, где вы, возможно, читали мою статью Не игнорьте composer.lock.
http://bit.ly/3hnPoIs
Medium
Правильная регистрация консольных команд Symfony в DI
Если ваше приложение требует БД при чистке кэша, эта статья для вас
В продолжение разговора о консольном приложении, предлагаю вот такой базовый класс команды для вашего проекта.
https://gist.github.com/vudaltsov/22c9498e891669d36bbbd366cc3705ef
Некоторые пояснения:
- благодаря пустому конструктору при создании подкласса PhpStorm не дублирует необязательные и ненужные аргументы оригинального конструктора
-
- в
- методы
- зафиксированы все корректные типы, в частности, execute(): int.
Опробовано в продакшне 😂, пользуйтесь.
https://gist.github.com/vudaltsov/22c9498e891669d36bbbd366cc3705ef
Некоторые пояснения:
- благодаря пустому конструктору при создании подкласса PhpStorm не дублирует необязательные и ненужные аргументы оригинального конструктора
Symfony\Component\Console\Command\Command
;-
abstract public static function name()
форсирует статическое имя, речь о котором шла в статье постом выше;- в
getDefaultName
добавлен префикс, чтобы исключить коллизии с вендорными командами;- методы
doExecute
и doInteract
сразу получают удобный хэлпер SymfonyStyle
, о котором я когда-то тут рассказывал;- зафиксированы все корректные типы, в частности, execute(): int.
Опробовано в продакшне 😂, пользуйтесь.
Gist
ConsoleCommand.php
GitHub Gist: instantly share code, notes, and snippets.
Как пропустить первый элемент итератора в цикле? А пройти пять начиная с третьего?
💩
💩
Все гораздо проще и лаконичнее с LimitIterator.
Обратите внимание, что первый аргумент
Итак, проход по первым трём элементам любого обходимого объекта будет выглядеть так:
Неплохие базовые вопросы для собеседования 😉
💩
if (!isset($firstSkipped))
💩
if ($i++ < 2)
Все гораздо проще и лаконичнее с LimitIterator.
foreach (new LimitIterator($iterator, $offset = 2, $limit = 5) as $item) {
// ...
}
Обратите внимание, что первый аргумент
LimitIterator
имеет тип Iterator
. То есть можно передать, например, Generator
или ArrayIterator
. Однако часто простые обходимые объекты реализуют IteratorAggregate
, который не является подтипом Iterator
. Как тут быть? Сначала на ум приходит забрать из него итератор вызовом $object->getIterator()
. Она неверная, потому что IteratorAggregate::getIterator
возвращает супертип Traversable, то есть это опять-таки может быть IteratorAggregate
. Правильное решение — обернуть наш объект в IteratorIterator, который превращает любой Traversable
в Iterator
.Итак, проход по первым трём элементам любого обходимого объекта будет выглядеть так:
foreach (new LimitIterator(new IteratorIterator($traversable), 0, 3) as $item) {
// ...
}
Неплохие базовые вопросы для собеседования 😉
В текущем проекте мы активно юзаем
• Ставим пакет с полезными автокомплитами для zsh.
• Открываем новое окно терминала и игнорируем появившееся предупреждение, нажав
• Затем фиксим права командой
• В новом терминале заходим в проект, набираем
Кстати, линуксоидам тоже рекомендую посмотреть в сторону zsh: https://habr.com/ru/post/326580/.
Makefile
, как-нибудь напишу про это подробнее. В macOS Catalina по умолчанию используется оболочка Z shell, и из коробки автокомплит для make
не настроен. Вот как это исправить:• Ставим пакет с полезными автокомплитами для zsh.
brew install zsh-completions
echo 'if type brew &>/dev/null; then
FPATH=$(brew --prefix)/share/zsh-completions:$FPATH
autoload -Uz compinit
compinit
fi' >> ~/.zshrc
• Открываем новое окно терминала и игнорируем появившееся предупреждение, нажав
y
.• Затем фиксим права командой
compaudit | xargs chmod g-w
.• В новом терминале заходим в проект, набираем
make <tab>
и, вуаля, получаем список команд!Кстати, линуксоидам тоже рекомендую посмотреть в сторону zsh: https://habr.com/ru/post/326580/.
Wikipedia
Zsh
командная оболочка операционной системы Unix