Пых
YouTube
#1.1 Стримкаст. Типы и типизирование. ООП. Часть I.
Обсудим типизацию, что это такое, какая бывает, зачем нужна. Типы данных в PHP, встроенные типы. Поговорим о том, для чего нужны кастомные типы. Как всё это мешает или помогает при разработке. Конечно, затронем Typhoon. Ответим на вопросы зрителей.
Пых
BeerPHP сменил локацию! Митап пройдёт в лофте "Событие" на Таганке. Организаторы говорят, что эта площадка значительно лучше. Дата и время те же самые: 6 июня (завтра) в 19:00. Также мне разрешили поделиться с вами записью доклада после мероприятия! ht…
Наконец-то мы смонтировали ролик! Помимо доклада в нём есть признание в любви к вам, матерные слова и подробная история моего RFC.
Получилось очень задорно! Спасибо организаторам и участникам BeerPHP за такую крутую атмосферу.
https://youtu.be/56I5C0NYjv8
https://vudaltsov.github.io/memory-leaks-slides/
Please open Telegram to view this post
VIEW IN TELEGRAM
YouTube
Пишем на PHP и не теряем память • Валентин Удальцов • BeerPHP • 6 июня 2024
0:00 Крутой монтаж BeerPHP
0:20 Приветствие под Катюшу
1:15 RFC: new without parentheses
2:00 Ставь RoadRunner сегодня вечером!
3:08 Что такое утечка памяти?
4:04 Почему сложно искать и предотвращать утечки?
5:19 Не мешай PHP убираться!
7:15 Декомпозируй…
0:20 Приветствие под Катюшу
1:15 RFC: new without parentheses
2:00 Ставь RoadRunner сегодня вечером!
3:08 Что такое утечка памяти?
4:04 Почему сложно искать и предотвращать утечки?
5:19 Не мешай PHP убираться!
7:15 Декомпозируй…
Хотите музыкальный стрим сегодня с 17 до 18 МСК? Позже, к сожалению, не получится из-за договорённостей с соседями. Сыграю несколько песен на барабанах (можно будет даже заказать), отвечу на ваши вопросы. Посмотрим, что из этого выйдет.
Ставь
Please open Telegram to view this post
VIEW IN TELEGRAM
Пых
Please open Telegram to view this post
VIEW IN TELEGRAM
28 и 29 ноября в Москве пройдёт конференция Highload, в рамках которой 16 докладов будут выделены под PHP Russia.
Наилучший способ туда попасть — выступить! Плюшки спикера: куратор из программного комитета для подготовки крутого доклада (например, я), транспорт до Москвы и комфортное проживание, бейдж с полным доступом ко всем залам и зонам Highload. А ещё спикер навсегда вписывает себя и свои идеи в историю PHP. Короче, грех не податься!
Дай угадаю. Если ты раньше не выступал, то сейчас думаешь: "Ой, ну мне не о чем рассказывать, у нас всё стандартно." Поверь, так не бывает! У каждой компании есть ноу-хау, иначе она была бы неприбыльной и ты работал бы в другой. А раз "every company is a software company", то ноу-хау должно быть и в софте. Твоя задача — найти его и заполнить форму. Ещё можно предложить доклад про это самое "стандартно" и как его правильно готовить. Дальше мы уже решим, что впишется в программу, а что нет.
Итак, темы этого года:
• FFI, практическое применение
• AI/ML + PHP
• Производительность
• Devops под PHP
• Лучшие практики
• Новые крутые либы
• Альтернативные рантаймы
• Новые фреймворки
• Опыт больших сложных проектов на PHP
Ждём твой доклад по адресу https://cfp.phprussia.ru/ до 2-ого сентября.
Please open Telegram to view this post
VIEW IN TELEGRAM
cfp.phprussia.ru
PHP Russia 2024
Подайте доклад на конференцию PHP Russia
Александр Кирсанов, руководитель команды KPHP, ушёл из ВК
https://vk.com/@kphp-all
Буду ждать от Саши новых проектов для PHP!
Ребят, я тут затайфунился жёстко. Скоро снова выйду в свет. Куча идей постов, стримов и, конечно, новый поток курса. Просто нужно ещё немного времени. Всех люблю!
https://vk.com/@kphp-all
Буду ждать от Саши новых проектов для PHP!
Ребят, я тут затайфунился жёстко. Скоро снова выйду в свет. Куча идей постов, стримов и, конечно, новый поток курса. Просто нужно ещё немного времени. Всех люблю!
VK
Посвящается никому
24 июля 2017 года был мой первый рабочий день ВКонтакте.
https://github.com/typhoon-php/typhoon/releases/tag/0.4.0
Вчера ночью, ровно через 5 месяцев после 0.3.0, поставил следующий минорный тег. По сути, он, конечно, мажорный, так как 0.y релизы могут ломать обратную совместимость, чем мы не преминули многократно воспользоваться.
Это был долгий, но полный важных осознаний путь. В цикле постов расскажу про каждое.
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
Release 0.4.0 New API & components, support for enums, functions and PHPDoc properties and methods · typhoon-php/typhoon
I am extremely happy to announce the new Typhoon version. We've been discussing, deciding, refactoring and rewriting Typhoon for 5 months since 0.3.0. This was a massive effort with many discov...
Пых
Как вы наверняка знаете, в Psalm и PHPStan есть типы
non-empty-string
, non-empty-list<TValue>
и non-empty-array<TKey, TValue>
. В далёкой 0.2 версии тайфуна они обрабатывались индивидуально — у каждого был свой метод в TypeVisitor. Затем в 0.3 мы попытались сократить избыточность, внедрив конструктор non-empty<T>, но не покидало ощущение, что это костыль. И, наконец, месяц назад пришло осознание, что нужен конструктор не для непустоты, а для отрицания.В самом деле, выведем статически типы внутри вот такой функции:
/**
* @template T
* @param T $bar
*/
function foo(mixed $bar): void
{
if (is_string($bar)) {
// тут у $bar тип T & string
return;
}
// а тут у $bar тип T & !string
trim($bar); // ошибка: ожидается string
}
Очевидно, что для статического анализатора отрицание может быть очень полезно. В TypeScript был такой PR, но почему-то заглох. Psalm и PHPStan частично поддерживают
!
в аннотациях @assert:
/**
* @psalm-assert !null $value
* @phpstan-assert !null $value
*/
function assertNotNull($value): void
{
if ($value === null) {
throw new InvalidArgumentException();
}
}
Ну а в typhoon/type 0.4
not
теперь first-class тип. Семейство non-empty-*
, а заодно и non-falsy-string выражаются так:
non-empty-string = string & !''
non-falsy-string = truthy-string = non-empty-string & !'0'
non-empty-list<TValue> = list<TValue> & !array{}
non-empty-array<TKey, TValue> = array<TKey, TValue> & !array{}
Здесь array{} — это запечатанный array-shape без элементов, то есть []. Его ещё часто пишут как array<never, never>.
Чтобы обойти
types::nonEmptyString
через TypeVisitor
, достаточно смаршрутизировать его как пересечение с соответствующими аргументами:
enum types implements Type
{
// ...
case nonEmptyString;
public function accept(TypeVisitor $visitor): mixed
{
return match ($this) {
// ...
self::nonEmptyString => $visitor->intersection($this, [
self::string,
self::not(self::string('')),
]),
}
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
Пых
В документации PHP
self
, parent
и static
называются относительными типами классов (relative class types). С этой троицей мы боремся с самого начала. Каждый релиз — новый раунд.Раунд 1
Возьмём пару классов:
class A extends stdClass
{
public function self(): self { return $this; }
public function parent(): parent { return $this; }
public function static(): static { return $this; }
}
final class B extends A {}
С
self
и parent
здесь всё просто и однозначно: в классе A
self = A
, parent = stdClass
, в класс B
копируем эти 2 метода с уже разрешёнными типами A
и stdClass
. Значит, self
и parent
можно не оформлять как самостоятельные типы, а сразу заменять на конкретные классы из скоупа.Можем ли мы так же разрешить
static
? Нет, так как это имя не текущего, а вызываемого класса (см. позднее статическое связывание): в A
static
резолвится как A
, а в B
— как B
. При построении рефлексии мы должны в каждом унаследованном методе обновить static
с учётом текущего скоупа. Для этого замоделируем static
как first-class тип, который знает, где он сейчас находится, и получим typhoon/type 0.2:
A,B::self() возвращают types::object(A::class)
A,B::parent() возвращают types::object(stdClass::class)
A::static() возвращает types::static(A::class)
B::static() возвращает types::static(B::class)
Please open Telegram to view this post
VIEW IN TELEGRAM
Пых
В Typhoon 0.3 я начал добавлять поддержку трейтов. И всё, естественно, поломалось.
Раунд 2
trait T
{
public function self(): self { return $this; }
public function parent(): parent { return $this; }
public function static(): static { return $this; }
}
Валидный ли это код? Да. Вот только ни один из трёх типов невозможно отрезолвить так же, как мы это делали выше.
self
и parent
не на что заменить, так как трейт сам по себе не является типом и не может наследовать другие. Для static
отсутствует скоуп-класс.Нативная рефлексия, кстати, вообще не парится: всегда возвращает
ReflectionNamedType
с 'self'
, 'parent'
или 'static'
. Мы так делать не хотим, потому что это просто откладывание проблемы на потом.Постепенно приходит понимание, что в трейтах относительные типы работают как плейсхолдеры. В Psalm и PHPStan их даже можно ограничивать через аннотации @require-extends и @require-implements. Всё это напоминает... дженерики!
Действительно,
/**
* @psalm-require-extends stdClass
* @phpstan-require-extends stdClass
*/
trait T
{
public function self(): self { return $this; }
public function parent(): parent { return $this; }
public function static(): static { return $this; }
}
final class A extends stdClass
{
use T;
}
можно с натяжкой переписать как
/**
* @template self of object
* @template parent of stdClass
* @template static of self
*/
trait T
{
public function self(): self { return $this; }
public function parent(): parent { return $this; }
public function static(): static { return $this; }
}
final class A extends stdClass
{
/**
* @use T<self, parent, self>
*/
use T;
}
Выглядит логично, но кривовато, потому что в реальности это не объявленные пользователем дженерики, а какие-то встроенные, да ещё и доступные в статике. Тем не менее, на тот момент идея мне очень нравилась, и, подставив пару костылей, я её реализовал в typhoon 0.3 и даже гордо рассказал про это на Стачке:
types::template('self', types::atClass(T::class))
types::template('parent', types::atClass(T::class))
types::template('static', types::atClass(T::class))
Please open Telegram to view this post
VIEW IN TELEGRAM
Пых
Есть у меня одна черта: я периодически возвращаюсь ко всем своим костылям, пока не сделаю нормально
Раунд 3
final class A extends ArrayObject
{
public function self() { return fn (): self => new self(); }
public function parent() { return fn (): parent => new parent(); }
public function static() { return fn (): static => new static(); }
}
final class B extends stdClass {}
$self = (new A())->self();
echo $self()::class; // A
echo $self->call(new B)::class; // B
$parent = (new A())->parent();
echo $parent()::class; // ArrayObject
echo $parent->call(new B)::class; // stdClass
$static = (new A())->static();
echo $static()::class; // A
echo $static->call(new B)::class; // B
Получается, что
self
, parent
и static
отлично себя чувствуют в анонимных функциях и, как и в трейтах, резолвятся в зависимости от скоупа, в том числе поддерживают его изменение в рантайме. Посмотрев на этот сниппет, мы наконец-то согласились, что относительные типы класса везде в PHP ведут себя логично и единообразно и должны быть замоделированы как first-class типы.Теперь в typhoon/type 0.4 можно создавать
self
, parent
и static
с классом скоупа и без него. Последнее как раз требуется в трейтах и непривязанных анонимных функциях. В TypeVisitor
каждый относительный тип обрабатывается индивидуально. Ну и, конечно, поддерживаются аргументы типов (а-ля self<X, Y>
). Комбо-пример:
trait T
{
/**
* @return array{self, parent, static}
*/
public function types(): array
{
return [$this, $this, $this];
}
}
abstract class A extends stdClass
{
use T;
}
final class B extends A {}
$type = TyphoonReflector::build()
->reflectClass(B::class)
->methods()['types']
->returnType();
echo stringify($type);
// array{self@A, parent@stdClass, static@B}
Please open Telegram to view this post
VIEW IN TELEGRAM
Традиционно после 0.X релиза Typhoon я запускаю X-й поток курса! Сегодня
X = 4
.Набор на четвёртый поток будет осуществляться как обычно. Завтра (в среду, 7 августа) в 15:00 по Москве на канале Пых появится ссылка на срез знаний. Необходимо его пройти, чтобы попасть на курс. При проверке я сначала отберу анкеты с правильными ответами, а затем отранжирую их по времени. Удачи!
Обновлённая страничка курса: hardcorephp.ru
Please open Telegram to view this post
VIEW IN TELEGRAM
Пых
https://forms.gle/PFvHT7vujHEPuSs29
Удачи!
Please open Telegram to view this post
VIEW IN TELEGRAM
Google Docs
Срез знаний для 4-ого потока Хардкорного курса PHP
Привет! При проверке я сначала буду отбирать анкеты с правильными ответами и здравыми рассуждениями, а потом ранжировать их по времени. Не старайся ответить академично, лучше поясни своими словами или приведи хороший пример. Удачи!
Пых
Теперь, когда первая сотня абитуриентов прислала анкеты, предлагаю всем подумать над внеконкурсным заданием. Решите 5-ю задачу с теми же вводными в обратную сторону. То есть у вас должен получиться класс, который, наоборот, позволит использовать
Psr\Middleware
как Symfony\Subscriber
. Идеи можно обсуждать в комментариях к этому посту. Позже всё разберём на стриме.Gist с полной формулировкой этого варианта задачи: https://gist.github.com/vudaltsov/dc4f372692d2eabbc8c3d29cd4de0ccd
Навеяно, кстати, весьма драматическими событиями. В 2018-м году сообщество Symfony активно обсуждало невыполнение PHP-FIG своей "framework interoperability" миссии, так как компоненты HttpFoundation и HttpKernel нельзя малой кровью адаптировать под PSR-7. Апогеем стал pull-request Фабьена "Remove Symfony" в PHP-FIG. Тогда же у Symfony появился
Please open Telegram to view this post
VIEW IN TELEGRAM
Gist
symfony_to_psr.php
GitHub Gist: instantly share code, notes, and snippets.
Пых
Сначала Вадим верно подметил, что суть решения сводится к приостановке потока управления внутри
Middleware
и предложил использовать для этого генераторы. Затем Александр скинул прототип на базе файберов.Ну а вот полное решение с использованием
Fiber
и WeakMap
, которое я зафиксировал вскоре после публикации задачи: код, 3v4l. Обсудим подробнее на разборе среза знаний!P.S.: Всем спокойной ночи!
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
Vadim Dvorovenko in Пыхтелка
В общем, тут вопрос в управлении потоком обработки в php. Всякую многопоточность откидываем, думаю решение нужно искать где-то в промисах и генераторах. Пока ставлю на yield, он вроде бы должен идеально подходить для того, чтобы прервать поток выполнения…
Benchmarking Laravel with Swoole, FrankenPHP, RoadRunner, php-fpm, and ngx-php
https://youtu.be/ZB129Tjkas8
https://github.com/pronskiy/ngx-php_laravel
Позавчера Рома Пронский выложил новый ролик, в котором он забенчмаркал запуск Laravel через основные популярные рантаймы (php-fpm, RoadRunner, Swoole, FrankenPHP) + малоизвестный проект ngx-php, который по результатам Web Framework Benchmarks оставляет позади даже Swoole и workerman.
https://youtu.be/ZB129Tjkas8
https://github.com/pronskiy/ngx-php_laravel
Позавчера Рома Пронский выложил новый ролик, в котором он забенчмаркал запуск Laravel через основные популярные рантаймы (php-fpm, RoadRunner, Swoole, FrankenPHP) + малоизвестный проект ngx-php, который по результатам Web Framework Benchmarks оставляет позади даже Swoole и workerman.
YouTube
Benchmarking Laravel with Swoole, FrankenPHP, RoadRunner, php-fpm, and ngx-php
I've set up ngx-php to run Laravel example application in worker mode with Octane and then compared the performance with classic php-fpm and also other Octane drivers like FrankenPHP, Swoole, and RoadRunner.
The code and results are available here:
http…
The code and results are available here:
http…
Пых
Назови несколько принятых в PHP 8.4 изменений.
Изменено значение у констант
PHP_VERSION
и PHP_MINOR_VERSION
Почему некоторые расширения, например, ext-pcntl, в composer.json принято прописывать с констрейнтом "*"?
Звёздочка обычно означает примечание, сноску на полях. Возможно, для таких расширений автор прописывает потом примечания автора. Ну, типа, "добавлю-ка я
pcntl
, сорян виндузятники, но вы идёте лесом".По какому принципу выбраны значения констант ReflectionProperty::IS_*?
Ребята решили ради прикола написать
1 << 1
, 1 << 2
, 1 << 3
, и т.д., чтобы никто не понял что это значит.Можно ли расширить возвращаемый тип метода в дочернем классе и почему?
Конечно можно! Ни одной статьи в Конституции РФ или Кодексах за нарушение подобного не предусмотрено. Да и это не такое порицаемое обществом занятие, чтобы ещё за него кто-то осуждал. Всё в рамках приличия.
Как соотносятся понятия "полиморфизм" и "наследование"?
Они оба на написаны кириллицей и в кавычках (только "наследование" хуже, т.к. в нём 12 букв, а "полиморфизм" в этом плане меньше весит, т.к. всего 11 букв).
Интересный факт: Если написать эти слова наоборот, то получится "мзифромилоп" и "еинаводелсан", но их размер не изменится. А ещё из букв в слове "полиморфизм" можно составить слово "зоофил", а из слова "наследование" можно составить "лениновед".
Теперь ты тоже будешь знать это!
Реши задачу.
final readonly class SymfonyIntegrator
{
public function integrate(): void
{
$previous = \getcwd();
try {
\chdir(__DIR__);
\copy('https://getcomposer.org/installer', __DIR__ . '/composer-setup.php');
require __DIR__ . '/composer-setup.php';
new \Symfony\Component\Process\Process([
\PHP_BINARY,
__DIR__ . '/composer.phar',
'create-project',
'symfony/skeleton',
])->run();
// Больше нам PSR фреймворк не нужен
} finally {
$previous && \chdir($previous);
}
}
}
Почему попросить ИИ-помощника написать тесты может быть не очень хорошей идеей?
Нельзя показывать работодателю, что всю твою работу может заменить скрипт на питоне.
В чём оптимизм оптимистичной блокировки?
Разработчики надеются, что в конце-концов когда-нибудь блокировка разблокируется, всё наладится и все будут жить долго и счастливо.
Что ждёшь от курса?
Ну хотя бы доллар по 25, как в началах 2000х. Был бы норм курс.
Please open Telegram to view this post
VIEW IN TELEGRAM
Все студенты получили письма с приглашениями на почту.
Немного статистики и наблюдений:
▸ 108 ответов на момент написания этого поста.
▸ 20 человек набралось на 64-й анкете (в прошлый раз на 41-й), она была отправлена через 54 минуты после старта.
▸ Как будто бы в этот раз вы чаще прибегали к помощи чат-ботов. Некоторые ответы были слишком вышколенными и высокопарными. Программист, который на скорость проходит опрос, так никогда не напишет. В решении 5-й задачи некоторые даже оставили типовые комментарии. В общем, когда я видел явные признаки использования ИИ, я переходил к следующему ответу. И наоборот, к тем, кто по-человечески ошибался в тексте или коде, я был более внимателен.
Сегодня (9 августа) в 19:00 разберём срез и задачу со звёздочкой, приглашаю всех на стрим!
https://youtu.be/wGegvTFidaA
P.S.: Форму не буду закрывать в демонстрационных целях. Заполняйте сколько хотите или используйте на собесах.
Please open Telegram to view this post
VIEW IN TELEGRAM
Думаю, никому не нужно представлять языковую конструкцию eval. В 2024 все пыхари знают её как древнее могущественное зло, которое ни при каких условиях не должно оказаться на проде. Если в проекте есть хоть один
eval
, он автоматически считается Такое отношение к
eval
непоследовательно. Если вы используете Symfony Dependency Injection, Doctrine ORM, Ocramius Proxy Manager или любой другой пакет с кодогенерацией, вы фактически используете eval
, только завуалированный. С точки зрения безопасности нет никакой разницы между тем, чтобы выполнить код из строки, и тем, чтобы сначала записать строку в файл, а затем его выполнить.Что на самом деле важно
1. При использовании
eval
и кодогенерации нужно 1000 раз убедиться, что входные данные либо вообще не могут попасть в код, либо строго санитизируются и правильно интерполируются с использованием var_export() или Typhoon Exporter.2. Код, исполняемый через
eval
, require
и include
получает доступ к текущей области видимости и переменным. Для изоляции можно обернуть вызов в статическое замыкание, см. пример.На десерт. В коде Symfony 7 есть eval. И не один... А как минимум 3... Уверен, что почти в каждом фреймворке есть. Поищите и скиньте в комментарии.
Please open Telegram to view this post
VIEW IN TELEGRAM