В обсуждении ребята подняли вопрос об учёте часовых поясов в функции из поста выше.
time_diff_ms() корректно учитывает временные зоны, так как сравнивает абсолютные метки времени, а не время настенных часов (wall-clock time).
Попутно мы выяснили, что метод
Добавил в Gist тесты для всех сценариев создания объекта времени.
https://gist.github.com/vudaltsov/0bb623b9e2817d6ce359eb88cfbf229d#file-time_diff_ms_test-php
time_diff_ms() корректно учитывает временные зоны, так как сравнивает абсолютные метки времени, а не время настенных часов (wall-clock time).
Попутно мы выяснили, что метод
DateTime(Immutable)::setTimezone() не изменяет абсолютное время, просто адаптирует время настенных часов под часовой пояс. Метка времени до и после setTimezone() остаётся такой же. Смотрите также комментарий к документации метода.Добавил в Gist тесты для всех сценариев создания объекта времени.
https://gist.github.com/vudaltsov/0bb623b9e2817d6ce359eb88cfbf229d#file-time_diff_ms_test-php
Gist
time_diff_ms.php
GitHub Gist: instantly share code, notes, and snippets.
Как одним выражением прочитать и изменить свойство
Этот приём можно использовать, например, в базовом классе корня агрегата.
Некогда подглядел у @fes0r.
[$currentValue, $this->property] = [$this->property, $newValue];Этот приём можно использовать, например, в базовом классе корня агрегата.
abstract class AggregateRoot
{
/**
* @psalm-var list<object>
*/
private array $events = [];
/**
* @psalm-return list<object>
*/
final public function releaseEvents(): array
{
▶ [$events, $this->events] = [$this->events, []];
return $events;
}
final protected function raise(object $event, object ...$events): void
{
$this->events = [...$this->events, $event, ...$events];
}
}
Некогда подглядел у @fes0r.
Пыхарь, что ты используешь для времени?
Anonymous Poll
26%
int (timestamp)
4%
string
43%
DateTime
36%
DateTimeImmutable
28%
nesbot/carbon
1%
cakephp/chronos
1%
другую стороннюю либу (напиши в обсуждении, какую)
1%
свою либу (напиши, что тебе это даёт)
Недавно узнал, что есть подход, при котором юнит-тесты кладут рядом с тестируемыми классами 🤔
Примеры:
• https://github.com/thephpleague/flysystem/tree/2.x/src,
• https://github.com/EventSaucePHP/EventSauce/tree/master/src/Integration.
Выглядит заманчиво — не надо синхронизировать две файловые структуры и бегать туда-сюда. И на ревью сразу видно, написан тест для нового класса или нет. Также этот подход должен повысить мобильность модулей кода — модуль не надо собирать по папкам
В библиотеках такие тесты легко удалить из архива правилом
Что думаете? Приглашаю обсудить в Пыхтелку 🐯
Примеры:
• https://github.com/thephpleague/flysystem/tree/2.x/src,
• https://github.com/EventSaucePHP/EventSauce/tree/master/src/Integration.
Выглядит заманчиво — не надо синхронизировать две файловые структуры и бегать туда-сюда. И на ревью сразу видно, написан тест для нового класса или нет. Также этот подход должен повысить мобильность модулей кода — модуль не надо собирать по папкам
src и test, чтобы переименовать или вынести в Composer-пакет.В библиотеках такие тесты легко удалить из архива правилом
**/*Test.php export-ignore в .gitattributes. Проект можно аналогичным образом чистить перед деплойментом.Что думаете? Приглашаю обсудить в Пыхтелку 🐯
Отличная статья про именованные агрументы от автора Psalm Мэтта Брауна!
В ней рассказывается про нюансы использования именованных аргументов в PHP 8 и про то, как новая версия Psalm
https://psalm.dev/articles/getting-ready-for-named-arguments
В ней рассказывается про нюансы использования именованных аргументов в PHP 8 и про то, как новая версия Psalm
3.14.0 поможет их снивелировать.https://psalm.dev/articles/getting-ready-for-named-arguments
psalm.dev
Getting ready for Named Arguments
Named Arguments are coming to PHP with the release of PHP 8!
Named Arguments will make many developers very happy, but they come with a pretty…
Named Arguments will make many developers very happy, but they come with a pretty…
Оказывается, для Symfony уже давно есть Psalm-плагин 😮
На радостях сделал 5 пулл-реквестов на базе стабов, которые мы скопили на рабочем проекте. Все 5 были приняты и вошли в релиз 1.4.3 ☺️
Кто до сих пор не использует статический анализ, советую просмотреть мои PR. Приёмочные тесты дадут вам некоторое представление о том, как статический анализ может вывести типизацию привычных инструментов на новый уровень.
https://github.com/psalm/psalm-plugin-symfony
На радостях сделал 5 пулл-реквестов на базе стабов, которые мы скопили на рабочем проекте. Все 5 были приняты и вошли в релиз 1.4.3 ☺️
Кто до сих пор не использует статический анализ, советую просмотреть мои PR. Приёмочные тесты дадут вам некоторое представление о том, как статический анализ может вывести типизацию привычных инструментов на новый уровень.
https://github.com/psalm/psalm-plugin-symfony
GitHub
GitHub - psalm/psalm-plugin-symfony: Psalm Plugin for Symfony
Psalm Plugin for Symfony. Contribute to psalm/psalm-plugin-symfony development by creating an account on GitHub.
Forwarded from PHP Digest
Открытое собеседование по PHP | Эпизод #2 — Прием заявок
Пилотный выпуск открытого собеседования зашел отлично, и мы получили много ценных отзывов. Спасибо всем, кто был с нами на стриме и задавал вопросы!
Если вдруг вы не видели первый выпуск, то вот запись https://www.youtube.com/watch?v=FQNd9W3nb3A
Тем временем начинаем подготовку второго выпуска!
Требования для участия не поменялись:
• уровень middle/senior;
• PHP 7.x, PSR;
• ООП, SOLID, coupling/cohesion, вот это все;
• тестирование, PHPUnit;
• желателен опыт с Symfony 4/5;
• SQL, желательно PostgreSQL;
• представление о современных трендах в архитектуре приложений.
Темы будут ± те же, а вот вопросы подготовим новые, без Psalm 🙂
Заявку на участие можно отправить до 27 августа через форму: https://forms.gle/ES3nXiwf4ycosGEy9.
Вопросы в личку: @vudaltsov, @pronskiy.
Пилотный выпуск открытого собеседования зашел отлично, и мы получили много ценных отзывов. Спасибо всем, кто был с нами на стриме и задавал вопросы!
Если вдруг вы не видели первый выпуск, то вот запись https://www.youtube.com/watch?v=FQNd9W3nb3A
Тем временем начинаем подготовку второго выпуска!
Требования для участия не поменялись:
• уровень middle/senior;
• PHP 7.x, PSR;
• ООП, SOLID, coupling/cohesion, вот это все;
• тестирование, PHPUnit;
• желателен опыт с Symfony 4/5;
• SQL, желательно PostgreSQL;
• представление о современных трендах в архитектуре приложений.
Темы будут ± те же, а вот вопросы подготовим новые, без Psalm 🙂
Заявку на участие можно отправить до 27 августа через форму: https://forms.gle/ES3nXiwf4ycosGEy9.
Вопросы в личку: @vudaltsov, @pronskiy.
YouTube
Открытое собеседование PHP Point #1 / Валентин Удальцов vs Патрик Фельдеш
О Патрике: https://career.habr.com/sspat
Код для ревью: https://gist.github.com/vudaltsov/e6f7dd83a88b349cd5ee0e0d1795e5aa
Задача на SQL: https://gist.github.com/vudaltsov/e3d06ef2158a248337aa262a9fb60b5f
Большое спасибо Антону Мореву за помощь с трансляцией.…
Код для ревью: https://gist.github.com/vudaltsov/e6f7dd83a88b349cd5ee0e0d1795e5aa
Задача на SQL: https://gist.github.com/vudaltsov/e3d06ef2158a248337aa262a9fb60b5f
Большое спасибо Антону Мореву за помощь с трансляцией.…
Раньше, чтобы создать nullable ValueObject из nullable примитива, приходилось писать колбасу вроде
Сегодня условные типы Psalm позволяют перенести if в статический конструктор:
https://psalm.dev/r/ab0090be4c
null === $stringClientId ? null : ClientId::fromString($stringClientId).
Сегодня условные типы Psalm позволяют перенести if в статический конструктор:
/**
* @template T of ?string
* @psalm-param T $id
* @psalm-return (T is null ? null : self)
*/
public static function fromString(?string $id): ?self
{
if (null === $id) {
return null;
}
Assert::uuid($id);
return new self($id);
}
ClientId::fromString($stringClientId)
https://psalm.dev/r/ab0090be4c
psalm.dev
Conditional love
Before Psalm was open-sourced, I had to first get it working on Vimeo’s codebase. One of the early hurdles was picking a return type for the…
Рекомендую доклад Temporal Modeling.
Mathias Verraes демонстрирует, как моделировать поведение через события и процессы, а не структуры данных и состояние. Такой подход повышает эффективность взаимодействия с бизнесом и позволяет ещё на этапе обсуждения выявить больше нюансов предметной области.
https://youtu.be/hh5lskgATCk
Список всех докладов Матиаса на эту тему
Mathias Verraes демонстрирует, как моделировать поведение через события и процессы, а не структуры данных и состояние. Такой подход повышает эффективность взаимодействия с бизнесом и позволяет ещё на этапе обсуждения выявить больше нюансов предметной области.
https://youtu.be/hh5lskgATCk
Список всех докладов Матиаса на эту тему
YouTube
Mathias Verraes - Talk Session: Temporal Modeling
Explore DDD 2019 - Denver, Sept. 16-20
Event Storming, Event Sourcing, CQRS, messaging, distributed systems … In one way or another, they're all about time. Traditional modeling styles, focused on things and structures, are not the primary way anymore to…
Event Storming, Event Sourcing, CQRS, messaging, distributed systems … In one way or another, they're all about time. Traditional modeling styles, focused on things and structures, are not the primary way anymore to…
> Вам нужны условия Йоды только если ваши тесты 💩 и вы думаете, что перестановка аргументов сравнения имеет большее значение, чем корректная запись ваших бизнес-правил.
https://twitter.com/frankdejonge/status/1298602389281411072
Мы используем в проекте условия Йоды (и фиксер yoda_style), но этот твит заставил меня задуматься, зачем 🤣
Когда-то давно я бы ответил "потому что так в Symfony Coding Standards", позже "потому что так удобнее присваивать результат сравнения", сегодня "только потому что привык".
https://twitter.com/frankdejonge/status/1298602389281411072
Мы используем в проекте условия Йоды (и фиксер yoda_style), но этот твит заставил меня задуматься, зачем 🤣
Когда-то давно я бы ответил "потому что так в Symfony Coding Standards", позже "потому что так удобнее присваивать результат сравнения", сегодня "только потому что привык".
Twitter
Frank de Jonge
You only need yoda-conditions if your test suit is 💩 and you think switching your comparator values is better than proofing your business-rules are functioning as they should. Don't #[At] me.
Пояснение к моей задаче на канале PHP задачи с собеседований.
Метод
Интересно, что вызов магических методов для неинициализированных свойств изначально был предусмотрен в RFC: Typed Properties 2.0 и имплементирован в
Чтобы всё-таки стриггерить
Пара статей про ленивую инициализацию свойств:
• https://ocramius.github.io/blog/intercepting-public-property-access-in-php/,
• https://ocramius.github.io/blog/lazy-property-automatic-property-initialization/.
Метод
__get() выполняется при попытке чтения из недоступных (защищённых или приватных) или несуществующих свойств. Публичное неинициализированное типизированное свойство таковым не является.Интересно, что вызов магических методов для неинициализированных свойств изначально был предусмотрен в RFC: Typed Properties 2.0 и имплементирован в
7.4.0. Однако после обсуждения различных WTF кейсов этот функционал был удалён в 7.4.1.Чтобы всё-таки стриггерить
__get, __set, __isset или __unset для типизированного свойства, необходимо сначала "удалить" его через unset: https://3v4l.org/RbFFM.Пара статей про ленивую инициализацию свойств:
• https://ocramius.github.io/blog/intercepting-public-property-access-in-php/,
• https://ocramius.github.io/blog/lazy-property-automatic-property-initialization/.
Telegram
PHP задачи с собеседований
Что выведет код?
Наброски системы плагинов для Infection от @ocramius
https://github.com/infection/infection/issues/1323
Пример того, как надо оформлять RFC issue в проектах с открытым исходным кодом 👍
Кстати, интересно, что тикеты в Infection (фреймворк Максима Рафалко для мутационного тестирования) уже не в первый раз становятся источником знаний и вдохновения для PHP сообщества 🔥
Также смотрите треды в Twitter на эту тему:
• https://twitter.com/Ocramius/status/1302886222747119616,
• https://twitter.com/slamzoe/status/1302909388894724101.
https://github.com/infection/infection/issues/1323
Пример того, как надо оформлять RFC issue в проектах с открытым исходным кодом 👍
Кстати, интересно, что тикеты в Infection (фреймворк Максима Рафалко для мутационного тестирования) уже не в первый раз становятся источником знаний и вдохновения для PHP сообщества 🔥
Также смотрите треды в Twitter на эту тему:
• https://twitter.com/Ocramius/status/1302886222747119616,
• https://twitter.com/slamzoe/status/1302909388894724101.
GitHub
Plugin system to allow pre-/post- filtering and modification of mutations · Issue #1323 · infection/infection
Scope - third-party tools integration The idea is relatively simple: some mutations don't make sense, according to other tools that are completely third-party to infection. Such tools could say...
Полезная задачка про
https://news.1rj.ru/str/phpquiz/309
json_encode в PHP 7.4 от меня на канале PHP задачи с собеседований.https://news.1rj.ru/str/phpquiz/309
Telegram
PHP задачи с собеседований
Что выведет код?
Вспомнил, что ещё в декабре мы горячо обсуждали этот нюанс в чате @symfony_php.
В результате прений я сделал Pull Request, который привёл в соответствие поведение Symfony Serializer.
https://github.com/symfony/symfony/pull/34791
В результате прений я сделал Pull Request, который привёл в соответствие поведение Symfony Serializer.
https://github.com/symfony/symfony/pull/34791
GitHub
[Serializer] Skip uninitialized (PHP 7.4) properties in PropertyNormalizer and ObjectNormalizer by vudaltsov · Pull Request #34791…
Q
A
Branch?
3.4
Bug fix?
yes
New feature?
no
Deprecations?
no
Tickets
n/a
License
MIT
Doc PR
n/a
When trying to read from an uninitialized property in PHP 7.4, a TypeError is gen...
A
Branch?
3.4
Bug fix?
yes
New feature?
no
Deprecations?
no
Tickets
n/a
License
MIT
Doc PR
n/a
When trying to read from an uninitialized property in PHP 7.4, a TypeError is gen...
Какая у тебя ЗП в тысячах рублей?
Дудь, разлогинься 😂
Дудь, разлогинься 😂
Final Results
15%
<50
25%
50-100
21%
100-150
16%
150-200
9%
200-250
4%
250-300
2%
300-350
1%
350-400
1%
400-450
4%
>450
Ищу к себе в команду middle PHP-разработчика
В Happy Inc мы исследуем вовлечённость и лояльность персонала в крупных компаниях. По-простому — собираем данные и строим отчёты. Но всё это приправлено многогранной бизнес-логикой, сложной авторизацией и прочими ноу-хау.
PHP 7.4 / Symfony 5.1 / PostgreSQL 12 / OpenAPI / CQRS / ES / DDD / Psalm на максималках и всё, о чём я тут рассказываю 😜
Full-time, Москва, БЦ Варшавка Sky, ЗП по результатам собеса.
https://happy-job.ru/vacancy-super-php-2020-10
Резюме можно присылать сразу мне @vudaltsov.
В Happy Inc мы исследуем вовлечённость и лояльность персонала в крупных компаниях. По-простому — собираем данные и строим отчёты. Но всё это приправлено многогранной бизнес-логикой, сложной авторизацией и прочими ноу-хау.
PHP 7.4 / Symfony 5.1 / PostgreSQL 12 / OpenAPI / CQRS / ES / DDD / Psalm на максималках и всё, о чём я тут рассказываю 😜
Full-time, Москва, БЦ Варшавка Sky, ЗП по результатам собеса.
https://happy-job.ru/vacancy-super-php-2020-10
Резюме можно присылать сразу мне @vudaltsov.
Сегодня ребята в Пыхтелке активно обсуждают JWT vs Server Side Sessions, поддерживаю разговор мыслями и ссылками.
• Сессии — это абсолютно валидный, неустаревший подход. Не стоит переписывать аутентификацию из-за хайпа вокруг JWT.
• Сессии усложняют горизонтальное масштабирование, но так ли остро стоит этот вопрос в вашем проекте?
• Стандарт JWT действительно несовершенен, история помнит несколько серьёзных уязвимостей в его реализациях. Но в 2020 это не так актуально, просто проверьте, что вы обновили библиотеки.
• JWT не предусматривает простого механизма инвалидации токена. Либо придётся выставлять короткий Expiration Time, либо строить сложный statefull механизм для гибкого контроля выданных токенов.
• JWT удобен для организации временного ограниченного доступа к конкретным операциям/ресурсам: эндпойнтам API, файлам, действиям по ссылкам из персонализированных рассылок.
• Сессии — это абсолютно валидный, неустаревший подход. Не стоит переписывать аутентификацию из-за хайпа вокруг JWT.
• Сессии усложняют горизонтальное масштабирование, но так ли остро стоит этот вопрос в вашем проекте?
• Стандарт JWT действительно несовершенен, история помнит несколько серьёзных уязвимостей в его реализациях. Но в 2020 это не так актуально, просто проверьте, что вы обновили библиотеки.
• JWT не предусматривает простого механизма инвалидации токена. Либо придётся выставлять короткий Expiration Time, либо строить сложный statefull механизм для гибкого контроля выданных токенов.
• JWT удобен для организации временного ограниченного доступа к конкретным операциям/ресурсам: эндпойнтам API, файлам, действиям по ссылкам из персонализированных рассылок.
Несколько статей "за" и "против":
• https://medium.com/swlh/why-do-we-need-the-json-web-token-jwt-in-the-modern-web-8490a7284482,
• https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/,
• https://jolicode.com/blog/why-you-dont-need-jwt,
• https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid.
• https://medium.com/swlh/why-do-we-need-the-json-web-token-jwt-in-the-modern-web-8490a7284482,
• https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/,
• https://jolicode.com/blog/why-you-dont-need-jwt,
• https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid.
⚠️ Небольшое сообщение для тех, кто обновил Symfony до 4.4.14 / 5.1.6
Обратите внимание, что рядом с вашим
В соответствии с обновленным рецептом его нужно загитигнорить, а также добавить в исключения статических анализаторов во избежание ошибок, связанных с косвенным анализом классов
Спасибо @Taarim за наводку 😊
Обратите внимание, что рядом с вашим
src/Kernel.php появился автогенерируемый файл .preload.php (#38140, #38142, документация).В соответствии с обновленным рецептом его нужно загитигнорить, а также добавить в исключения статических анализаторов во избежание ошибок, связанных с косвенным анализом классов
vendor через этот файл.Спасибо @Taarim за наводку 😊
Symfony
Symfony 4.4.14 released (Symfony Blog)
Symfony 4.4.14 has just been released.