Пых
📝 new MyClass()->method() без скобок В конце прошлого года я придумал правку для синтаксиса PHP, которая позволит не оборачивать new выражения в cкобки для обращения к ним: final class MyClass { const CONSTANT = 'constant'; public static $staticProperty…
https://wiki.php.net/rfc/new_without_parentheses#proposed_voting_choices
Кстати, следить за всеми RFC можно через монитор: https://php-rfc-watch.beberlei.de/
P.S.: Всех с праздником!
Please open Telegram to view this post
VIEW IN TELEGRAM
🎉71🔥36👍26🤮15👎1
Пых
Дмитрий Стогов одобрил мой PR! На текущий момент RFC набрал 16 голосов "за" и 2 "против".
👍152🔥63🍾32🤮9❤8👎1
ML-assisted completion
Примерно с месяц у меня в PhpStorm включен бесплатный Full Line Code Completion. Если бы после обновления он не был "искаропки", я б, наверное, так и не попробовал ничего подобного. Но раз судьба свела, вот мои наблюдения.
Без помощника:
1. размышляю над тем, что написать дальше (по сути, это самый сложный и долгий этап),
2. пишу код, используя хоткеи, шаблоны и стандартный предсказуемый автокомплит.
С помощником:
1. размышляю над тем, что написать дальше,
2. ввожу пару символов, вижу на экране подсказку (иногда с запозданием),
3. зрительно анализирую её (дополнительная мыслительная деятельность),
4. с вероятностью 40% ассистент не угадывает точь-в-точь,
5. с вероятностью 60% угадывает, нажимаю Tab.
В итоге у меня формируется стойкое ощущение, что я парно программирую с туповатым джуном, который играет со мной в угадайку, причём в тот момент, когда я уже и так знаю, что нужно сделать. По сути, он отвлекает меня от работы! По этой причине мне скорее хочется выключить плагин, чем продолжить им пользоваться.
Возможно, я сейчас написал какой-то ретроградский пост и мне просто нужно установить полноценный AI Assistant, тогда-то всё встанет на свои места. Или я пишу не тот код — надо меньше думать, больше формошлёпить и крудить, а не тайфуны типунить... Короче, разубедите или поддержите меня — я в этой теме новичок.
Примерно с месяц у меня в PhpStorm включен бесплатный Full Line Code Completion. Если бы после обновления он не был "искаропки", я б, наверное, так и не попробовал ничего подобного. Но раз судьба свела, вот мои наблюдения.
Без помощника:
1. размышляю над тем, что написать дальше (по сути, это самый сложный и долгий этап),
2. пишу код, используя хоткеи, шаблоны и стандартный предсказуемый автокомплит.
С помощником:
1. размышляю над тем, что написать дальше,
2. ввожу пару символов, вижу на экране подсказку (иногда с запозданием),
3. зрительно анализирую её (дополнительная мыслительная деятельность),
4. с вероятностью 40% ассистент не угадывает точь-в-точь,
goto 2;5. с вероятностью 60% угадывает, нажимаю Tab.
В итоге у меня формируется стойкое ощущение, что я парно программирую с туповатым джуном, который играет со мной в угадайку, причём в тот момент, когда я уже и так знаю, что нужно сделать. По сути, он отвлекает меня от работы! По этой причине мне скорее хочется выключить плагин, чем продолжить им пользоваться.
Возможно, я сейчас написал какой-то ретроградский пост и мне просто нужно установить полноценный AI Assistant, тогда-то всё встанет на свои места. Или я пишу не тот код — надо меньше думать, больше формошлёпить и крудить, а не тайфуны типунить... Короче, разубедите или поддержите меня — я в этой теме новичок.
JetBrains Marketplace
Full Line Code Completion - IntelliJ IDEs Plugin | Marketplace
Designed to supercharge your code completion with multi-token proposals utilizing a deep learning model. Enjoy the benefits of advanced code completion offline, as it...
👍64💯33😁10❤2🤔2💩1
Пых
Дмитрий Стогов одобрил мой PR! На текущий момент RFC набрал 16 голосов "за" и 2 "против".
Официально объявляю свой RFC принятым!
Не буду ждать утра, чтобы сообщить, что я только что закрыл голосование на отметке в 25 голосов против 4. Это означает, что в PHP 8.4 мы с вами сможем писать
До сих пор не верится, что шальная попытка законтрибьютить в PHP, предпринятая за завтраком 26 декабря прошлого года, увенчалась успехом. Теперь есть запал для пары других идей. Попробую летом их оформить.
Всем огромное спасибо за поддержку!
Не буду ждать утра, чтобы сообщить, что я только что закрыл голосование на отметке в 25 голосов против 4. Это означает, что в PHP 8.4 мы с вами сможем писать
new без скобок! Осталось только дождаться мёрджа PR в мастер.До сих пор не верится, что шальная попытка законтрибьютить в PHP, предпринятая за завтраком 26 декабря прошлого года, увенчалась успехом. Теперь есть запал для пары других идей. Попробую летом их оформить.
Всем огромное спасибо за поддержку!
Telegram
Пых
new MyClass()->method() без скобок!
Вдохновлённый митапом, разобрался с синтаксисом Bison и закинул свой первый Pull Request в исходники PHP. Это изменение позволит обращаться к объектам, созданным через new, не оборачивая их в скобки. Во избежание неоднозначности…
Вдохновлённый митапом, разобрался с синтаксисом Bison и закинул свой первый Pull Request в исходники PHP. Это изменение позволит обращаться к объектам, созданным через new, не оборачивая их в скобки. Во избежание неоднозначности…
🔥329👍80🎉62🤮15❤4🌚2👎1🍾1😎1
Пых
Официально объявляю свой RFC принятым! Не буду ждать утра, чтобы сообщить, что я только что закрыл голосование на отметке в 25 голосов против 4. Это означает, что в PHP 8.4 мы с вами сможем писать new без скобок! Осталось только дождаться мёрджа PR в мастер.…
После исправления косяка, замеченного зорким глазом Никиты Попова, мой PR был окончательно одобрен и наконец-то попал в master! У них там как-то странно это происходит — через отдельный commit и закрытый PR, хотя у меня во всех проектах на GitHub аналогичный squash + rebase по кнопке даёт фиолетовый статус "merged", а не красный "closed". Но не суть.
Тем временем я закинул в internals ещё одну идею. Я предложил вынести методы
ArrayAccess::offsetExists, offsetGet в отдельный интерфейс с рабочим названием ArrayAccessRead, чтобы можно было делать иммутабельные коллекции, поддерживающие $object['key'] синтаксис только в режиме чтения. Но выяснилось, что уже есть драфт отличного RFC, который предлагает куда более глубокое переосмысление кривого ArrayAccess. Надеюсь, что он тоже попадёт в 8.4, а я пока подумаю над чем-то ещё. Please open Telegram to view this post
VIEW IN TELEGRAM
🔥157🎉63👍34💩5👏4❤2👎1👀1
В этот четверг в 19:00 на
Максим Хасанов расскажет про RoadRunner, Алексей Сидоркин про Swoole, а у меня будет секция про память. Обсудим, откуда берутся утечки и как подготовить код для запуска в неумирающих рантаймах.
Только оффлайн, без трансляции и записи. Если ты в Москве, регистрируйся и приходи!
https://beerphp.ru/
Please open Telegram to view this post
VIEW IN TELEGRAM
😢73👍35👎21😡11❤2
Пых
BeerPHP сменил локацию!
Митап пройдёт в лофте "Событие" на Таганке. Организаторы говорят, что эта площадка значительно лучше. Дата и время те же самые: 6 июня (завтра) в 19:00.
Также мне разрешили поделиться с вами записью доклада после мероприятия!
https://beerphp.ru/
Митап пройдёт в лофте "Событие" на Таганке. Организаторы говорят, что эта площадка значительно лучше. Дата и время те же самые: 6 июня (завтра) в 19:00.
Также мне разрешили поделиться с вами записью доклада после мероприятия!
https://beerphp.ru/
Яндекс Карты
Событие Лофт, конференц-зал, Николоямская ул., 28, Москва — Яндекс Карты
Рейтинг 5,0. 64 отзыва, 91 фото. Написать в whatsapp, посмотреть меню, номер телефона, часы работы и построить маршрут вы можете в Яндекс Картах.
🔥55❤46👍17🥰1
К 29-ому дню рождения PHP Рома Пронский опубликовал ролик, в котором он скомпилировал и запустил первую версию языка!
https://youtu.be/0BPExYh5Anw
И ещё несколько ссылок для любознательных:
• интервью с Расмусом про то, как он изобрёл PHP,
• статья Артёма Украинского про PHP 1 на Хабре,
• музей PHP.
Please open Telegram to view this post
VIEW IN TELEGRAM
YouTube
Running PHP 1.0 in 2024
I downloaded the source of PHP 1.0, compiled it on modern MacBook, then wrote a simple CGI server using PHP 8.3, and then tried to understand what was PHP 1.0 actually capable of doing. Spoiler alert: not much.
The code can be found here: https://github…
The code can be found here: https://github…
🎉80👍18🔥9👎2
Завтра (12 июня) в
20:00 встретимся с Димой Елисеевым на новом канале Станислава Ракчаева и команды LivePHP "Абстрактный программист", чтобы обсудить типизацию. Ребята подкупили меня фразой "затронем Typhoon". В общем, заходите, задавайте вопросы, расскажу всё, что знаю.
https://youtu.be/eXfsU-x3bMg
P.S.: Видео с прошедшего BeerPHP обязательно будет, но нужно ещё подождать.
Please open Telegram to view this post
VIEW IN TELEGRAM
YouTube
#1.1 Стримкаст. Типы и типизирование. ООП. Часть I.
Обсудим типизацию, что это такое, какая бывает, зачем нужна. Типы данных в PHP, встроенные типы. Поговорим о том, для чего нужны кастомные типы. Как всё это мешает или помогает при разработке. Конечно, затронем Typhoon. Ответим на вопросы зрителей.
👍43🔥20
Разбор резюме от Егора Бугаенко
https://youtu.be/af6bidlat6Q
Прям очень зашло! Когда снова буду искать работу, обязательно переделаю резюме.
Мои заметки:
• свой документ вместо типовой выгрузки с HH,
• две версии анкеты: сжатая и яркая для технаря, подробная и скучная для HR,
• убрать подработки верстальщиком в интернет-магазине в студенческие времена,
• уникальный опыт на каждом месте работы (так-то все мы рефакторим, пилим фичи и тестируем),
• каждый факт должен подтверждаться ссылкой.
Понравилась следующая мысль. Если я, например, указываю в резюме "Git" и "Symfony 6", то я лукавлю, потому что это неравноценные навыки. Я никогда не просматривал исходники гита, не делал про него докладов, тем более не контрибьютил. Да, я умею в
https://youtu.be/af6bidlat6Q
Прям очень зашло! Когда снова буду искать работу, обязательно переделаю резюме.
Мои заметки:
• свой документ вместо типовой выгрузки с HH,
• две версии анкеты: сжатая и яркая для технаря, подробная и скучная для HR,
• убрать подработки верстальщиком в интернет-магазине в студенческие времена,
• уникальный опыт на каждом месте работы (так-то все мы рефакторим, пилим фичи и тестируем),
• каждый факт должен подтверждаться ссылкой.
Понравилась следующая мысль. Если я, например, указываю в резюме "Git" и "Symfony 6", то я лукавлю, потому что это неравноценные навыки. Я никогда не просматривал исходники гита, не делал про него докладов, тем более не контрибьютил. Да, я умею в
rebase, знаю разные flow, но это само собой разумеется. В то же время у меня суммарно под сотню PR и issue в symfony/symfony, я выступал на SymfonyCon, лично знаком с Core-командой и читаю курс с использованием этого фреймворка. Принципиально другой уровень! Так что в версии резюме для технаря "Git" я уж точно уберу.YouTube
BB1: Будьте смелее, покажите свое резюме
Разобрали несколько резюме программистов в прямом эфире.
Здесь подробнее: https://www.yegor256.com/2016/03/08/pimp-up-your-resume.html
Приходите к нам в группу и покажите свое резюме, обсудим: https://news.1rj.ru/str/resumania
Blog: https://www.yegor256.com
Books:…
Здесь подробнее: https://www.yegor256.com/2016/03/08/pimp-up-your-resume.html
Приходите к нам в группу и покажите свое резюме, обсудим: https://news.1rj.ru/str/resumania
Blog: https://www.yegor256.com
Books:…
👍39🔥13👎11🤡6
Пых
YouTube
#1.1 Стримкаст. Типы и типизирование. ООП. Часть I.
Обсудим типизацию, что это такое, какая бывает, зачем нужна. Типы данных в PHP, встроенные типы. Поговорим о том, для чего нужны кастомные типы. Как всё это мешает или помогает при разработке. Конечно, затронем Typhoon. Ответим на вопросы зрителей.
👍11🥱1
Пых
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 Декомпозируй…
👍70🔥32❤6🥰1🌭1
Хотите музыкальный стрим сегодня с 17 до 18 МСК? Позже, к сожалению, не получится из-за договорённостей с соседями. Сыграю несколько песен на барабанах (можно будет даже заказать), отвечу на ваши вопросы. Посмотрим, что из этого выйдет.
Ставь
Please open Telegram to view this post
VIEW IN TELEGRAM
🤩51🔥14👍13👎7✍3😁2
Пых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍28🔥10🤮10👎4🎉4👏2🤔2💅2⚡1
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 2025
Подайте доклад на конференцию PHP Russia
👍51🔥25🤮5💩2
Александр Кирсанов, руководитель команды KPHP, ушёл из ВК
https://vk.com/@kphp-all
Буду ждать от Саши новых проектов для PHP!
Ребят, я тут затайфунился жёстко. Скоро снова выйду в свет. Куча идей постов, стримов и, конечно, новый поток курса. Просто нужно ещё немного времени. Всех люблю!
https://vk.com/@kphp-all
Буду ждать от Саши новых проектов для PHP!
Ребят, я тут затайфунился жёстко. Скоро снова выйду в свет. Куча идей постов, стримов и, конечно, новый поток курса. Просто нужно ещё немного времени. Всех люблю!
VK
Посвящается никому
24 июля 2017 года был мой первый рабочий день ВКонтакте.
🫡79👍14❤9💩7🔥4🗿4🤔3
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...
🔥29🎉10👍2
Пых
Как вы наверняка знаете, в 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
👍22🔥16❤1👎1🤯1
Пых
В документации 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
👍14🔥2😐1
Пых
В 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
👍8🔥6😐1
Пых
Есть у меня одна черта: я периодически возвращаюсь ко всем своим костылям, пока не сделаю нормально
Раунд 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
👍13🔥3🤔2