Telegram Web Link
Друзья, приглашаю к себе в команду 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.
Можете писать мне в ЛС.

На фото наш техотдел 🤗
Вышел первый пакет Yii3 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. Это интерфейс ради интерфейса. Задача, которую он якобы решает, настолько тривиальна, что при необходимости проще решить её в приложении самому, чем тащить еще одну библиотеку.
В Symfony тоже спорную фичу добавили: https://symfony.com/blog/new-in-symfony-5-1-autowire-public-typed-properties.

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

Прокидывайте сервисы по классике через конструктор в приватные поля и следите за тем, чтобы инъекций было не больше трех, а в идеале ноль или одна.
В PHP 8 появится функция get_debug_type.

Вместо 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
Channel photo updated
Channel name was changed to «Пых»
Пых — блог Валентина Удальцова о разработке на PHP.

На канале не размещается реклама и вакансии.

Полезные ссылки:
• основной чат канала Пыхтелка,
• чат Пыхтелка Symfony,
• канал на YouTube PHPPoint,
• канал с мемами PHP умирает?!,
пост про мои консультации,
статистика канала на Telegram Analytics,
Patreon.
🔥1
В Psalm скоро появятся условные типы как в TypeScript.
/**
* @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 .
Вышла новая мажорная версия популярной библиотеки ramsey/uuid. Из описания следует, что серьезных нарушений обратной совместимости в ней нет, а вот новых интерфейсов и исключений там целый список.

Изучаем изменения в документации и обновляемся composer req ramsey/uuid:^4.0.

На мой взгляд, самое интересное — это поддержка пока нестандартизированного UUID v6. Новая версия UUID предложена специально для использования в качестве первичного ключа БД и обладает следующими свойствами:

- Сортировка по необработанным байтам приводит к последовательности, эквивалентной сортировке по встроенной временной метке.
- Встроенное время может быть извлечено для использования в качестве времени создания.
- Глобальная уникальность, которая является основным требованием для всех типов UUID.

Про отличия версии 6 от версии 1 и другие подробности можно прочитать в IETF черновике.
Чтобы узнать, какие пакеты пора обновить, используем команду composer outdated или просто composer out.

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

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

Чтобы скрыть мажорные апдейты (наличие которых форсирует желтый цвет даже если пакет в текущем мажоре получил патч), используем флаг --minor-only (-m).

Про остальные флаги и другие полезные команды читаем в официальной документации Composer.
Теперь у Symfony тоже есть библиотека для работы с UUID: 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 😉
Предстоящая нерабочая неделя — отличная возможность для рефакторинга наболевшего кода и написания (недостающих) тестов.

Компромисс между бизнесом и IT — и поработаем, и гештальты закроем, и со скуки не умрём!
Изучаем свежезакрытые уязвимости в Symfony и обновляем 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 и разбираться, в чем была проблема и как её решили. Это отличная возможность поучиться на чужих ошибках и начать писать более безопасный код.

Но никогда не обольщайтесь на эту тему. Если ваша система не проходит регулярный профессиональный аудит силами внутреннего отдела безопасности или внешней службы на аутсорсе — я могу с уверенностью сказать, что она уязвима.
Недавно обновил 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"
}
}
📖 Правильная регистрация консольных команд Symfony в DI

Год назад на одном большом проекте исследовал мучительный баг. Команда bin/console cache:clear при локальном развертывании и прогонах в CI требовала подключения к БД и Redis. Какого черта, я же просто компилирую контейнер?!

И вот наконец-то на выходных нашел время оформить подробный разбор проблемы.

Добро пожаловать на обновленный профиль на медиуме, где вы, возможно, читали мою статью Не игнорьте composer.lock.

http://bit.ly/3hnPoIs
В продолжение разговора о консольном приложении, предлагаю вот такой базовый класс команды для вашего проекта.

https://gist.github.com/vudaltsov/22c9498e891669d36bbbd366cc3705ef

Некоторые пояснения:
- благодаря пустому конструктору при создании подкласса PhpStorm не дублирует необязательные и ненужные аргументы оригинального конструктора Symfony\Component\Console\Command\Command;
- abstract public static function name() форсирует статическое имя, речь о котором шла в статье постом выше;
- в getDefaultName добавлен префикс, чтобы исключить коллизии с вендорными командами;
- методы doExecute и doInteract сразу получают удобный хэлпер SymfonyStyle, о котором я когда-то тут рассказывал;
- зафиксированы все корректные типы, в частности, execute(): int.

Опробовано в продакшне 😂, пользуйтесь.
Как пропустить первый элемент итератора в цикле? А пройти пять начиная с третьего?

💩 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) {
// ...
}


Неплохие базовые вопросы для собеседования 😉
В текущем проекте мы активно юзаем 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/.
2025/07/11 23:50:02
Back to Top
HTML Embed Code: