Telegram Web Link
Если кто-то вдруг пропустил, вчера команда JetBrains запустила информативный и красивый таймлайн развития PHP в честь 25-летия языка.

Советую просмотреть сверху вниз и обратно, обязательно найдёте что-то любопытное. Например, я узнал, что в PHP некогда была функция leak(), что в 2014-ом Википедия перешла на HHVM.

Интересно пронаблюдать, как соотносятся во времени различные события. Например, Дмитрий Стогов присоединился к Zend незадолго до запуска Facebook, а Composer появился гораздо позже, чем большая часть фреймворков.

Ну и конечно не забывайте про скидку 50% на PhpStorm, она действует ещё целый день 😉

https://www.jetbrains.com/lp/php-25/
Задачка от меня на канале PHP задачи с собеседований с пояснением к решению.

https://www.tg-me.com/phpquiz/222
Однажды я услышал, что геттеры — это плохо.

И прошел все этапы реакции по Кюблер-Росс: отрицание, злость, торг, депрессию, принятие 😂
Надеюсь, этот пост поможет пропустить несколько стадий.

DTO. Если тело геттера return $this->privateProperty, заменяем его публичным свойством с аннотацией @psalm-readonly-allow-private-mutation или @psalm-readonly или объявляем весь класс @psalm-immutable. Так мы обеспечиваем инкапсуляцию да ещё и нанооптимизируем код (-N вызовов геттеров). Метод без каких-либо манипуляций не имеет смысла — это 4 строки визуального долга и 1 строка для покрытия тестами.

Кстати, я тут заметил, что геттер — это трюк. К существительному добавили глагол, чтобы удовлетворить фомуле subject.actionVerb(?object). Вот только get — это не предоставить, а получить. То есть мы не просим объект поделиться состоянием, мы его отбираем.

Value Object. Если метод представляет собой query по CQS и возвращает некоторое представление (проекцию) объекта, то его название не должно быть шаблонным, оно должно отражать семантику. Например, Birthday::format(string $format): string, Color::toHex(): string.

Entity. Стараемся применять принцип Tell-Don't-Ask. Попробую сформулировать по-своему. Объект — это состояние + поведение. Если мы программируем объектно-ориентированно, мы должны просить объект совершить действие над принадлежащим ему состоянием, а не отбирать у него состояние и выполнять действие за пределами этого объекта. Если программируем не объектно-ориентированно (что тоже ок), то объекты по определению не используем и геттеры, соответственно, тоже.

---

Итак, в DTO вместо геттеров используем публичные свойства. В Value Object — семантические query методы, и то, если не добавлять "на всякий случай", их будет немного. В Aggregate Root оставляем только command методы.

Как тогда вывести состояние модели? Рассудим логически. Для вывода состояния поведение не нужно, нужно только состояние. Значит и сама модель для этой задачи не нужна. В простом случае состояние можно запросить напрямую из хранилища и выдать сразу без всяких ORM: echo json_encode($pdo->query('select x1, x2 from y where z = ?')->fetch()). В более сложном случае можно посмотреть в сторону Event Sourcing, но про это как-нибудь в другой раз 😉
Media is too big
VIEW IN TELEGRAM
Открытое собеседование — ищем участников

Бывало, засидишься на одном месте и не знаешь, актуален ли ты еще на рынке... Хотя бы какие там тренды? Что спрашивают-то сейчас вообще на собеседованиях?

Вот и решили с Романом Пронским провести публичное онлайн-собеседование с вопросами на актуальные темы мира PHP.

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

Собеседование будет проходить в режиме стрима в теплой обстановке, примерно как на видео, только я буду без усов 😂

Требования для участия:
• уровень middle/senior;
• PHP 7.x, Composer, PSR;
• ООП, SOLID, coupling/cohesion, вот это все;
• тестирование, PHPUnit;
• желателен опыт с Symfony 4/5;
• SQL, желательно PostgreSQL;
• представление о современных трендах в архитектуре приложений.

Заявки на участие можно отправить до 8 июля через форму: https://forms.gle/ES3nXiwf4ycosGEy9.

Вопросы в личку: @vudaltsov, @pronskiy.
Эффективное проектирование агрегатов

Эссе Вона Вернона в трёх коротких частях, которое поможет с пониманием паттерна агрегат.

Прочитав его, вы получите ответы на следующие вопросы:
• как и зачем проектировать маленькие агрегаты;
• что такое истинные инварианты и как их искать;
• почему Value Object предпочтительнее, чем Entity;
• когда нужна мгновенная (immediate), а когда конечная (eventual) согласованность;
• когда позволительно изменять несколько агрегатов в одной транзакции.

По сути, это квинтэссенция нескольких важных глав из синей и красной книги по DDD.

https://dddcommunity.org/library/vernon_2011/
Иерархические структуры в реляционных СУБД

На этой неделе разгребаю в проекте разные тудушки, поэтому больше читаю и обдумываю, чем пишу код 😂

Вот вам цикл из двух статей, в которых автор сравнивает три подхода к хранению иерархических структур в реляционках:
• список смежных вершин (adjacency list),
• материализованный путь (materialized path),
• вложенное множество (nested set).

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

В конце первой статьи есть раздел про комбинирование подходов. Особенно удобно комбинировать на проектах с CQRS: списки смежных вершин на запись и списки + материализованные пути на чтение.

https://habr.com/ru/post/46659/
https://habr.com/ru/post/47280/

Забавно. В первой статье есть примеры на Doctrine 1, и они безбожно устарели. Но основной материал будет актуален ещё долго...
Как справедливо заметил в обсуждении @dimmount, есть еще четвёртый подход — Closure Table. Мы, кстати, тоже его используем, но я не знал, что это так называется 🙈

По сути, это денормализация материализованного пути в отдельную таблицу ancestor/descendant с заменой like на джойны и подзапросы, подробнее в статье другого автора.

https://habr.com/ru/post/193166/
Теперь канал можно поддержать 💵 на Patreon

Для фона долго искал что-то с глубинным смыслом 😂
На всякий случай оставлю тут исходное изображение.

https://www.patreon.com/phpyh
В PhpStorm наконец-то добавят поддержку Psalm и PHPStan 🎊

Предположительно, плагины войдут в релиз 2020.3, так что ждём сентябрьский EAP.

Впервые плагины оформлены в виде опенсорс-проектов на GitHub, так что мы можем наблюдать как на языке со статическим анализом реализуется поддержка внешнего статического анализа для языка без статического анализа 🤣 Если серьезно, то проекты можно использовать как эталоны для собственных плагинов.

Подробнее в блоге JetBrains: https://blog.jetbrains.com/phpstorm/2020/07/phpstan-and-psalm-support-coming-to-phpstorm/.

Как отчаянный псалмовец 😜 очень рад быть к этому причастным.
Во время карантина по просьбе
@pronskiy записал для команды обзорный скринкаст по фичам Psalm.
Обработка deadlock в Doctrine

Проблему взаимных блокировок в первую очередь надо решать исходя из контекста, где они возникают. Однако если дедлоки стреляют изредка, можно предусмотреть простой retry. Удобнее всего его реализовать как middleware для command bus и там поймать Doctrine\DBAL\Exception\RetryableException.

Помните, что после ошибки EntityManager закрывается. В Symfony его можно оживить вызовом метода resetManager() на сервисе @doctrine (автовайрится по интерфейсу Doctrine\Persistence\ManagerRegistry). После этого менеджер даже в извлеченном из контейнера сервисе не кинет The EntityManager is closed благодаря замене инициализатора в прокси.

Пример такого middleware для Symfony Messenger: https://gist.github.com/vudaltsov/945291b4e8a8800f669d478c8d66e8b8
Когда надо объединить n массивов, причём n >= 0.

array_merge([], ...$arrays)
Спасибо @andrewDemb за ценное замечание: начиная с PHP 7.4 array_merge может принимать 0 аргументов.

array_merge(...$arrays)

https://3v4l.org/nUEs7
И ещё одно важное уточнение, спасибо @shmaltorhbooks.

Распаковать в аргументы можно только список (индексированный массив). На текущий момент даже Psalm это не проверяет. Соответственно, в общем случае массив массивов нужно привести списку массивов при помощи array_values.

Финальный вариант для PHP >= 7.4: array_merge(...array_values($arrays)).

Для удобства эту конструкцию можно оформить в виде функции в проектном functions.php.

/**
* @template T of array
* @psalm-param array<T> $arrays
* @psalm-return T
*/
function merge_arrays(array $arrays): array
{
return array_merge(...array_values($arrays));
}


Так приятно, что комьюнити помогает 😊
Если вам вдруг когда-нибудь потребуется найти/заменить символы перевода строки (\r, \n, \r\n), например для нормализации, можно воспользоваться малоизвестным классом \R.

preg_replace('/\R/', PHP_EOL, "text\rwith\nvarious\r\nline endings\n\n")


https://3v4l.org/5cBcW
В обсуждении @ivan_tsirulev обратил внимание, что \R матчит более широкий спектр символов:

• новую строку \n,
• возврат каретки \r,
• подачу страницы \f,
• вертикальную табуляцию \v.

Пример: https://3v4l.org/6QU82.

Список всех управляющих последовательностей в документации PHP: https://www.php.net/manual/ru/language.types.string.php#language.types.string.syntax.double.

Подробнее о поиске символов новой строки через регулярные выражения в статье Никиты Попова: https://nikic.github.io/2011/12/10/PCRE-and-newlines.html.
Открытое собеседование #1 🎊
Cтрим в четверг, 16 июля, в 17:00 по Москве/Киеву/Минску


Роман @phpdigest и я @phpyh совместно проведём открытое собеседование с Патриком Фельдешем.

Начнём со знакомства, перейдём к PHP, пробежимся по SOLID и закончим где-то в архитектуре и вопросами из чата. В конце расскажем, что было хорошо, а что не очень, и прошел ли бы кандидат реальное собеседование.

Трансляция будет на новом YouTube канале PHP Point — подписывайтесь, чтобы не пропустить следующие проекты 😉

https://www.youtube.com/watch?v=FQNd9W3nb3A
Кеш или кэш?
Anonymous Poll
26%
кЕш
74%
кЭш
Понравилась статья Null is your friend, not a mistake.

Главный тезис: сама по себе концепция null не является ошибкой (в миллиард долларов), ошибочна система типов Java, которая считает null частью любого типа.

Для понимания. В PHP у нас с этим всё хорошо 😳: мы явно помечаем тип X как nullable при помощи символа вопроса ?X. В Java такого нет, переменная типа X может иметь значение X или null. Поэтому у новичков (которые не выбрали Kotlin) часто проблемы с NullPointerException, а в коде на Java присутствуют костыли @Nullable и @NotNull и/или "избыточные" проверки null != $obj.

https://medium.com/@elizarov/null-is-your-friend-not-a-mistake-b63ff1751dd5

За статью спасибо @Enleur.
Эффективно игнорим исключения в Psalm

Вчера счастью моему не было предела, когда в https://github.com/vimeo/psalm/issues/3286 через 3 месяца мне ответили, что в psalm.xml в разделе <ignoreExceptions> есть незадокументированный тег <classAndDescendants>. При помощи него уже давным давно можно игнорить исключение и все его подклассы. На скрине до и после 🤣

Игнорить следует unchecked исключения (подклассы RuntimeException, LogicException и Error). Ну и иногда можно позволить себе игнорить некоторые checked, чтобы не захламлять проект бесконечными @throws, которые едва ли можно как-то обработать.

Кстати, в PhpStorm в разделе Preferences > Languages & Frameworks > PHP тоже можно указывать, какие исключения считать unchecked.
2025/07/10 11:18:29
Back to Top
HTML Embed Code: