Приглашаю всех на стрим о рефакторинге!
В четверг вечером я с Леонидом Корсаковым буду в прямом эфире "наперегонки" комментировать и рефакторить одну известную open source библиотеку. Посмотрим, что из этого выйдет 😅
1 октября / четверг / 19:00
Организаторы из Skyeng обещают призы 🎁:
🐘 фирменного PHP слона за лучшую зрительскую историю о рефакторинге,
🔑 несколько лицензий на PhpStorm за вопросы в эфире голосом!
https://www.youtube.com/watch?v=liMyAuxIoyM
В четверг вечером я с Леонидом Корсаковым буду в прямом эфире "наперегонки" комментировать и рефакторить одну известную open source библиотеку. Посмотрим, что из этого выйдет 😅
1 октября / четверг / 19:00
Организаторы из Skyeng обещают призы 🎁:
🐘 фирменного PHP слона за лучшую зрительскую историю о рефакторинге,
🔑 несколько лицензий на PhpStorm за вопросы в эфире голосом!
https://www.youtube.com/watch?v=liMyAuxIoyM
YouTube
Рефакторим c Александром Макаровым, Валентином Удальцовым, Валентином Назаровым, Леонидом Корсаковым
В четверг Александр Макаров (Yii) и Валентин Назаров (Skyeng) проведут стрим, на котором Валентин Удальцов (Пых) и Леонид Корсаков (PHP Kazan):
• посмотрят на код популярного гитхаб-проекта,
• найдут, что там порефакторить (и порефакторят),
• поделятся своими…
• посмотрят на код популярного гитхаб-проекта,
• найдут, что там порефакторить (и порефакторят),
• поделятся своими…
Подкаст { Между скобок } про статический анализ
На прошлой неделе Сергей Жук предложил мне обсудить статанализ, и я был бы не я, если бы упустил возможность ввернуть пару монологов про Psalm 😆
И вот о чём мы поговорили:
• почему PHP пошел в сторону строгой типизации,
• для чего нужны статические анализаторы и как они работают,
• будущее статических анализаторов.
https://soundcloud.com/between-braces/11-valentin-udaltsov-staticheskiy-analiz
На прошлой неделе Сергей Жук предложил мне обсудить статанализ, и я был бы не я, если бы упустил возможность ввернуть пару монологов про Psalm 😆
И вот о чём мы поговорили:
• почему PHP пошел в сторону строгой типизации,
• для чего нужны статические анализаторы и как они работают,
• будущее статических анализаторов.
https://soundcloud.com/between-braces/11-valentin-udaltsov-staticheskiy-analiz
Четверо в YouTube, не считая кота 🐈
Вчера у нас получился любопытный стрим про рефакторинг. Приятная компания, интересное задание и достойная организация. Спасибо всем, кто слушал, комментировал и потом писал в личку ✊
Вкратце для тех, кто ещё не посмотрел. Я поленился по-честному отрефакторить yiisoft/validator, вместо этого воспользовался лазейкой "мажорный релиз" и предложил альтернативную архитектуру для библиотеки 😅
Что у меня получилось: https://github.com/phpyh/validator.
Мои пояснения на вчерашнем стриме: https://youtu.be/liMyAuxIoyM?t=4308.
Вчера у нас получился любопытный стрим про рефакторинг. Приятная компания, интересное задание и достойная организация. Спасибо всем, кто слушал, комментировал и потом писал в личку ✊
Вкратце для тех, кто ещё не посмотрел. Я поленился по-честному отрефакторить yiisoft/validator, вместо этого воспользовался лазейкой "мажорный релиз" и предложил альтернативную архитектуру для библиотеки 😅
Что у меня получилось: https://github.com/phpyh/validator.
Мои пояснения на вчерашнем стриме: https://youtu.be/liMyAuxIoyM?t=4308.
⚠️ Команда Symfony снова шалит в патч-апдейте 4.4.15 / 5.1.7 😏
Если вы вносили правки, описанные мной в посте от 28 сентября, то придётся их откатить: удалить
После этого нужно добавить в репозиторий (без игнора) один из вариантов файла
Если у вас ядро располагается в нестандартном месте, то файл
Если вы вносили правки, описанные мной в посте от 28 сентября, то придётся их откатить: удалить
src/.preload.php и убрать соответствующие правила из .gitignore и конфигов инструментов.После этого нужно добавить в репозиторий (без игнора) один из вариантов файла
config/preload.php из обновленного рецепта. В папку с конфигами у меня статанализ не ходит, поэтому на этот раз исключение добавлять не пришлось.Если у вас ядро располагается в нестандартном месте, то файл
var/cache/prod/App_KernelProdContainer.preload.php будет называться иначе. Вот как получить верный путь:bin/console c:c --env=prod
find var/cache/prod -name '*.preload.php'
Symfony
Symfony 4.4.15 released (Symfony Blog)
Symfony 4.4.15 has just been released.
Ванлайнер для получения данных объекта без рефлексии
https://3v4l.org/adhBn
Что почитать на эту тему:
• документацию по Closure::call(),
• статью Accessing private PHP class members without reflection от @Ocramius.
https://3v4l.org/adhBn
Что почитать на эту тему:
• документацию по Closure::call(),
• статью Accessing private PHP class members without reflection от @Ocramius.
В преддверии новой самоизоляции хочу поделиться с вами роликом, который мы сделали в апреле, чтобы улыбнуть и улыбнуться 😊
Всем отличного настроения, несмотря ни на что!
🎶🥁💃🥭
https://www.youtube.com/watch?v=cyZ2bJ0rQQM
Всем отличного настроения, несмотря ни на что!
🎶🥁💃🥭
https://www.youtube.com/watch?v=cyZ2bJ0rQQM
YouTube
Zapekanka — Under Quarantine Funk
Функция для получения всех типов класса
Такая функция потребовалась мне для поиска обработчика объекта по типу. Генератор здесь позволяет не рефлексировать раньше времени.
https://3v4l.org/EOPjm
Такая функция потребовалась мне для поиска обработчика объекта по типу. Генератор здесь позволяет не рефлексировать раньше времени.
https://3v4l.org/EOPjm
Пых
Ванлайнер для получения данных объекта без рефлексии https://3v4l.org/adhBn Что почитать на эту тему: • документацию по Closure::call(), • статью Accessing private PHP class members without reflection от @Ocramius.
Выяснилось, что в предложенном мной виде функция objectToArray неуниверсальна ☹️
Для объекта встроенного класса (например,
"Встроенность" можно проверить через ReflectionClass::isInternal, а можно просто подавить ошибку и обработатьрелигии ситуации 😉
В чистом виде get_object_vars применима к любым объектам и всегда возвращает массив публичных нестатических свойств. У объектов встроенных классов кроме
Обновлённый вариант функции с рефлексией https://3v4l.org/2mtXC и без https://3v4l.org/RqDHu.
Для объекта встроенного класса (например,
DateTimeImmutable или stdClass) вызов Closure::call бросит ошибку уровня E_WARNING и вернёт null, так как замыкание нельзя привязать к области видимости встроенного класса."Встроенность" можно проверить через ReflectionClass::isInternal, а можно просто подавить ошибку и обработать
null, выбирайте по В чистом виде get_object_vars применима к любым объектам и всегда возвращает массив публичных нестатических свойств. У объектов встроенных классов кроме
stdClass он, как правило, пустой.Обновлённый вариант функции с рефлексией https://3v4l.org/2mtXC и без https://3v4l.org/RqDHu.
Не игнорьте .idea в проекте
До сих пор встречаю проекты, где в
Представим, что каждый разработчик решил использовать свою IDE с уникальными временными файлами и предложил PR на изменение
Это элементарно достигается настройкой глобального
Всего лишь две команды в чек-лист вашего онбоардинга...
До сих пор встречаю проекты, где в
.gitignore есть правила типа .idea/, .vscode/ или *.swp, поэтому решил написать этот пост.Представим, что каждый разработчик решил использовать свою IDE с уникальными временными файлами и предложил PR на изменение
.gitignore. Думаю, проблема очевидна. Код должен быть IDE-агностик, то есть не зависеть от среды разработки.Это элементарно достигается настройкой глобального
.gitignore на машине разработчика. Каждый прописывает себе те исключения, которые необходимы для его ОС, IDE и прочих инструментов, а затем спокойно открывает любой проект, не боясь закоммитить лишнее.Всего лишь две команды в чек-лист вашего онбоардинга...
git config --global core.excludesfile ~/.gitignore
echo '.idea/' >> ~/.gitignore
Уже месяц используем Composer 2 RC в продакшне, рекомендую!
Главное улучшение — это, конечно, превосходная скорость без всяких плагинов вроде
Понравилась возможность выполнить
Также меня заинтересовало, почему задепрекейтили мою любимую опцию
Подробно об изменениях:
• на русском https://sergeymukhin.com/blog/composer-2-chto-novogo-i-izmenennogo,
• на английском https://php.watch/articles/composer-2.
Главное улучшение — это, конечно, превосходная скорость без всяких плагинов вроде
hirak/prestissimo или symfony/flex.Понравилась возможность выполнить
composer require/remove <name> --dry-run и безболезненно узнать, что изменится.Также меня заинтересовало, почему задепрекейтили мою любимую опцию
--no-suggest. Пояснение "из уст" автора нашёл только в issue #8615: в новой версии предложения необъёмные и ненадоедливые.Подробно об изменениях:
• на русском https://sergeymukhin.com/blog/composer-2-chto-novogo-i-izmenennogo,
• на английском https://php.watch/articles/composer-2.
composer selfupdate --preview
Параметры vs Аргументы
Параметр — это переменная в сигнатуре функции. В PHP параметры характеризуются именем, типом, позицией, значением по умолчанию, вариативностью (
Аргумент — это выражение/значение, используемое при вызове функции.
Именно поэтому
На мой взгляд простой, но важный нюанс 👌
Параметр — это переменная в сигнатуре функции. В PHP параметры характеризуются именем, типом, позицией, значением по умолчанию, вариативностью (
...) и возможностью передачи по ссылке (см. ReflectionParameter).Аргумент — это выражение/значение, используемое при вызове функции.
Именно поэтому
$reflectionMethod->getParameters(), но func_get_args и InvalidArgumentException.На мой взгляд простой, но важный нюанс 👌
Завтра выступаю на PHPFest 🚀 с докладом про утечки памяти 💧
Буду говорить и лайвкодить на следующие темы:
• как следить за памятью в консольных командах;
• эффективная декомпозиция кода;
• copy-on-write;
• $real_usage в memory_get_usage();
• циклические ссылки наглядно;
• WeakReference, WeakMap;
• как следить за памятью в воркерах.
https://2020.phpfest.ru/lecture/3
Буду ждать вас на странице трансляции в 10:00 по Москве (в 14:00 по Новосибирску)!
Буду говорить и лайвкодить на следующие темы:
• как следить за памятью в консольных командах;
• эффективная декомпозиция кода;
• copy-on-write;
• $real_usage в memory_get_usage();
• циклические ссылки наглядно;
• WeakReference, WeakMap;
• как следить за памятью в воркерах.
https://2020.phpfest.ru/lecture/3
Буду ждать вас на странице трансляции в 10:00 по Москве (в 14:00 по Новосибирску)!
Разыгрываю билет на PHPFest 2020!
Задача
https://gist.github.com/vudaltsov/4c1fe1c2c2ad0f2a3850f5ef228e00db
Перед вами код фабрики тяжёлых отчётов. Отчёт генерируется на лету по запросу. В процессе фабрика может быть вызвана несколько раз для одного и того же экземпляра данных, поэтому предусмотрен in-memory кэш. В качестве сервера используется RoadRunner.
Как отрефакторить код, чтобы память не текла в PHP 7? В PHP 8?
Условия участия
• Нужно прислать правильные ответы на оба вопроса через бота (не через личные сообщения).
• Ответ для PHP 8 должен отличаться от ответа для PHP 7.
• Ответы принимаются сегодня до полуночи по Москве.
• Чтобы повысить шансы, нужно прислать простое и лаконичное решение как можно раньше.
Приз
Победителя определю я и опубликую его имя и решение утром. Герой получит доступ в личный кабинет и возможность посмотреть все доклады в записи в удобное время.
Удачи! 😊
Задача
https://gist.github.com/vudaltsov/4c1fe1c2c2ad0f2a3850f5ef228e00db
Перед вами код фабрики тяжёлых отчётов. Отчёт генерируется на лету по запросу. В процессе фабрика может быть вызвана несколько раз для одного и того же экземпляра данных, поэтому предусмотрен in-memory кэш. В качестве сервера используется RoadRunner.
Как отрефакторить код, чтобы память не текла в PHP 7? В PHP 8?
Условия участия
• Нужно прислать правильные ответы на оба вопроса через бота (не через личные сообщения).
• Ответ для PHP 8 должен отличаться от ответа для PHP 7.
• Ответы принимаются сегодня до полуночи по Москве.
• Чтобы повысить шансы, нужно прислать простое и лаконичное решение как можно раньше.
Приз
Победителя определю я и опубликую его имя и решение утром. Герой получит доступ в личный кабинет и возможность посмотреть все доклады в записи в удобное время.
Удачи! 😊
PHPFest 23-24 октября 2021
PHPFest в Новосибирске. Офлайн и Онлайн
Итоги конкурса!
Как я проверял ваши решения 🤓
Если ответ был текстовый, то я оценивал правильность идеи. Если ответ был кодом, то я тестировал его при помощи InMemoryCachingReportFactoryTest.php, предварительно адаптировав тест, если были изменены названия классов или добавлены зависимости. Если тест крашился из-за банальной ошибки (например, неинициализированного типизированного свойства), я такой ответ не засчитывал. Если в коде визуально были неточности, но мой несложный тест он проходил, я засчитывал. Думаю, это справедливо, всё-таки совсем непротестированный код на прод заливать не стоит 😉
Победитель 🏆
Первый правильный ответ пришёл от Andrew (@Groonya):
• https://gist.github.com/aivchen/39a956afc47634c7f8bb2de4688aa7c1 (PHP 7),
• https://gist.github.com/aivchen/5c8d51bed4188910ed34660c3b92fea0 (PHP 8).
Интересно, что в первом сниппете Андрея тоже есть неинициализированное свойство
Пояснение от меня 💡
Эту задачу я рассмотрю сегодня в рамках своего доклада. Решение выложил отдельным видео на PHP Point. Присоединяйтесь к PHPFest через 2 часа по ссылке https://2020.phpfest.ru/showtime/, всех жду!
Как я проверял ваши решения 🤓
Если ответ был текстовый, то я оценивал правильность идеи. Если ответ был кодом, то я тестировал его при помощи InMemoryCachingReportFactoryTest.php, предварительно адаптировав тест, если были изменены названия классов или добавлены зависимости. Если тест крашился из-за банальной ошибки (например, неинициализированного типизированного свойства), я такой ответ не засчитывал. Если в коде визуально были неточности, но мой несложный тест он проходил, я засчитывал. Думаю, это справедливо, всё-таки совсем непротестированный код на прод заливать не стоит 😉
Победитель 🏆
Первый правильный ответ пришёл от Andrew (@Groonya):
• https://gist.github.com/aivchen/39a956afc47634c7f8bb2de4688aa7c1 (PHP 7),
• https://gist.github.com/aivchen/5c8d51bed4188910ed34660c3b92fea0 (PHP 8).
Интересно, что в первом сниппете Андрея тоже есть неинициализированное свойство
$reports, однако оператор ??= на это по понятным причинам не ругается, поэтому формально код корректный.Пояснение от меня 💡
Gist
InMemoryCachingReportFactoryTest.php
GitHub Gist: instantly share code, notes, and snippets.
Сегодня в начале выступления была заминка из-за того, что у меня не работала команда
По скрину поймёте, почему 😂
Как известно, Symfony пробегает все файлы, зарегистрированные в DI как ресурсы, при прогреве кэша в dev. Соответственно, при автозагрузке демонстрационного класса
Неудивительно, что перезагрузка мака меня не спасла. В итоге я успешно показал всё на рабочем проекте, пока фоновый процесс в моей голове пытался понять, почему тут работает, а там нет.
🤦🤦♂️🤦♀️🙈
bin/console demo в специально подготовленном для лайвкодинга проекте.По скрину поймёте, почему 😂
Как известно, Symfony пробегает все файлы, зарегистрированные в DI как ресурсы, при прогреве кэша в dev. Соответственно, при автозагрузке демонстрационного класса
App\Worker в конце файла запускался этот самый воркер и начинал свой бесконечный цикл. Добавил эти строки я на последнем прогоне доклада и конечно же забыл удалить, поэтому сегодня утром "подвисание" команды для меня было полной неожиданностью...Неудивительно, что перезагрузка мака меня не спасла. В итоге я успешно показал всё на рабочем проекте, пока фоновый процесс в моей голове пытался понять, почему тут работает, а там нет.
🤦🤦♂️🤦♀️🙈
😅 Я не смог вас сегодня отпустить без подробного разбора вчерашней задачи, поэтому записал по горячим следам небольшой ролик на PHP Point.
Помимо комплексного решения для PHP 7 и PHP 8 я рассказал про маленькую неочевидную особенность
https://www.youtube.com/watch?v=r1HDMu7nJh0
Помимо комплексного решения для PHP 7 и PHP 8 я рассказал про маленькую неочевидную особенность
\WeakReference и продемонстрировал, как можно тестировать утечки в PHPUnit в стиле тяп-ляп.https://www.youtube.com/watch?v=r1HDMu7nJh0
YouTube
Нюансы WeakReference & WeakMap на конкретном примере / Валентин Удальцов
Разбираем решение задачи про утечки, опубликованной на канале Пых в рамках конкурса совместно с PHPFest.
Полезные ссылки:
• мой доклад на PHPFest 2020 https://2020.phpfest.ru/lecture/3,
• условие задачи со ссылкой на код https://news.1rj.ru/str/phpyh/182,
• победитель…
Полезные ссылки:
• мой доклад на PHPFest 2020 https://2020.phpfest.ru/lecture/3,
• условие задачи со ссылкой на код https://news.1rj.ru/str/phpyh/182,
• победитель…
На сегодняшний день я участвовал пока только в трёх конференциях по PHP в качестве докладчика, и из них PHPFest отличился самым высоким уровнем организации.
Посудите сами, в результате созвона с командой PHPFest я купил нормальный микрофон, Ethernet-адаптер для стабильного соединения в офисе, и вместе мы добились качественного стриминга задолго до самой конференции.
Большое спасибо @seregazhuk за настойчивость и пунктуальность. После стольких прогонов никакая техническая проблема в моём сетапе не могла меня смутить, потому что я был на 110% уверен в своём докладе.
Уже через день после мероприятия на сайте появились записи докладов, а сегодня мне прислали подробный фидбэк по моему выступлению, после чего я всё бросил и пошёл писать этот пост.
@phpfest, вы огонь, спасибо за такой высокий уровень, пожалуйста, не расслабляйтесь, а остальные — подтягивайтесь!
Посудите сами, в результате созвона с командой PHPFest я купил нормальный микрофон, Ethernet-адаптер для стабильного соединения в офисе, и вместе мы добились качественного стриминга задолго до самой конференции.
Большое спасибо @seregazhuk за настойчивость и пунктуальность. После стольких прогонов никакая техническая проблема в моём сетапе не могла меня смутить, потому что я был на 110% уверен в своём докладе.
Уже через день после мероприятия на сайте появились записи докладов, а сегодня мне прислали подробный фидбэк по моему выступлению, после чего я всё бросил и пошёл писать этот пост.
@phpfest, вы огонь, спасибо за такой высокий уровень, пожалуйста, не расслабляйтесь, а остальные — подтягивайтесь!
При помощи
После вызова
Сравните: https://3v4l.org/LL8E9 и https://3v4l.org/jni5Y.
Generator::valid() можно проверить генератор на пустоту, не обходя его целиком.После вызова
$generator->valid() функция генератора начинает выполнение и доходит либо до первого yield (тогда valid возвращает true), либо до конца (valid возвращает false). Интересно, что в первом случае на генераторе можно вызвать rewind без каких-либо последствий, так как обход ещё не начался. Во втором случае генератор закрывается и обойти его уже нельзя.Сравните: https://3v4l.org/LL8E9 и https://3v4l.org/jni5Y.