TGViewer
Пых Пых @phpyh · 7.83K subscribers
Post #508 5.31K
Пых 💙 Typhoon 0.4. self, parent, static В документации PHP self, parent и static называются относительными типами классов (relative class types). С этой троицей мы боремся с самого начала. Каждый релиз — новый раунд. Раунд 1 Возьмём пару классов: class A…
💙 Typhoon 0.4. self, parent, static.

В 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))
  • 👍 8
  • 🔥 6
  • 😐 1
More from @phpyh
  1. Sep 30, 2026🍺 BeerPHP AI Moscow Кажется, «неделя PHP» потихоньку превращается в месяц PHP. 😅 Будет 2…
  2. Sep 28, 2026Запустили Пыхник и неделю PHP! Залетайте на первый открытый доклад от Дмитрия Dantes про к…
  3. Sep 15, 2026Сейчас один человек с AI может выполнять работу целого IT-отдела. Только хуёво
  4. Sep 12, 2026Спасибо за заявки! Всем напишу в понедельник. Осталось 1 место.
  5. Sep 11, 2026Хардкорный курс асинхронного PHP https://hardcourse.ru/php/async
  6. Sep 11, 2026Ещё полчасика надо — сайт готов, расписываю программу! 🙏
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 →