TGViewer
Channel Public Channel
Пых

Пых

@phpyh

Блог Валентина Удальцова о разработке на PHP.

Хобот @phpyhobot
https://youtube.com/@phpyh
https://vkvideo.ru/@phpyh
https://t.me/isPHPdying

Статистика: https://t.me/INOTAROBOT?start=st1219340804

Для связи используйте личные сообщения канала.
Subscribers
7.82K
Photos
287
Videos
20
Links
629

Showing posts older than #130 · Back to latest

Older Posts 20 shown
Post #129 2.66K
Если вы достаточно хорошо знаете английский, советую вот это выступление Дяди Боба.
Отличный стендап для буднего вечера 😅

https://www.youtube.com/watch?v=QHnLmvDxGTY
YouTube "Uncle" Bob Martin Software luminary “Uncle Bob” Martin spoke to members of the Yale and New Haven communities at Yale School of Management. Martin had been a professional programmer since 1970; since then he has become a prolific author and leader in the industry. Dan Bernier…
Post #128 2.39K
Эффективно игнорим исключения в 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.
Post #127 2.61K
Понравилась статья 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.
Medium Null is your friend, not a mistake NullPointerException is dreaded in Java. All sorts of workarounds exist to avoid nulls. Fear not. They are not needed with Kotlin.
Post #125 2.74K
Post #124 2.84K
Открытое собеседование #1 🎊
Cтрим в четверг, 16 июля, в 17:00 по Москве/Киеву/Минску


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

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

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

https://www.youtube.com/watch?v=FQNd9W3nb3A
YouTube Открытое собеседование PHP Point #1 / Валентин Удальцов vs Патрик Фельдеш О Патрике: https://career.habr.com/sspat Код для ревью: https://gist.github.com/vudaltsov/e6f7dd83a88b349cd5ee0e0d1795e5aa Задача на SQL: https://gist.github.com/vudaltsov/e3d06ef2158a248337aa262a9fb60b5f Большое спасибо Антону Мореву за помощь с трансляцией.…
Post #123 2.47K
В обсуждении @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.
3v4l.org Online PHP editor | output for 6QU82 Run your php code online; get statistics, vld output and compare output from all versions.
Post #122 2.38K
Если вам вдруг когда-нибудь потребуется найти/заменить символы перевода строки (\r, \n, \r\n), например для нормализации, можно воспользоваться малоизвестным классом \R.

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


https://3v4l.org/5cBcW
3v4l.org Online PHP editor | output for 5cBcW Run your php code online; get statistics, vld output and compare output from all versions.
Post #121 2.35K
И ещё одно важное уточнение, спасибо @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));
}


Так приятно, что комьюнити помогает 😊
GitHub Add error when unpacking an array of arguments with string keys · Issue #2481 · vimeo/psalm Could psalm detect such cases? https://psalm.dev/r/5a1bf51bb9 https://3v4l.org/NNsi8 Note that arrays with integer keys (not lists) can be unpacked https://3v4l.org/ddAYG.
Post #119 2.13K
Когда надо объединить n массивов, причём n >= 0.

array_merge([], ...$arrays)
Post #118 3.23K
Обработка 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
Gist DeadlockRetryMiddleware.php GitHub Gist: instantly share code, notes, and snippets.
Post #117 2.63K
В PhpStorm наконец-то добавят поддержку Psalm и PHPStan 🎊

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

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

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

Как отчаянный псалмовец 😜 очень рад быть к этому причастным.
Во время карантина по просьбе
@pronskiy записал для команды обзорный скринкаст по фичам Psalm.
Post #115 2.29K
Как справедливо заметил в обсуждении @dimmount, есть еще четвёртый подход — Closure Table. Мы, кстати, тоже его используем, но я не знал, что это так называется 🙈

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

https://habr.com/ru/post/193166/
Хабр Хранение деревьев в базе данных. Часть первая, теоретическая Полгода назад написал бандл ClosureTable для фреймворка Laravel 3. Поводом для написания стала вот эта замечательная презентация Билла Карвина о способах хранени...
Post #114 2.35K
Иерархические структуры в реляционных СУБД

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

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

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

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

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

Забавно. В первой статье есть примеры на Doctrine 1, и они безбожно устарели. Но основной материал будет актуален ещё долго...
Хабр Иерархические структуры данных и Doctrine Введение Хранение иерархических данных (или попросту — деревьев) в реляционных структурах задача довольно нетривиальная и вызывает некоторые проблемы, когда разработчики сталкиваются с подобной...
Post #113 2.44K
Эффективное проектирование агрегатов

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

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

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

https://dddcommunity.org/library/vernon_2011/
Post #112 2.84K
Открытое собеседование — ищем участников

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

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

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

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

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

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

Вопросы в личку: @vudaltsov, @pronskiy.
Post #111 3.55K
Однажды я услышал, что геттеры — это плохо.

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

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, но про это как-нибудь в другой раз 😉
martinfowler.com bliki: Command Query Separation a bliki entry for Command Query Separation
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →