TGViewer
Пых Пых @phpyh · 7.83K subscribers
Post #531 6.54K
В последний момент исправляю рефлексию в PHP 8.4!

На неделе я начал добавлять поддержку PHP 8.4 в Typhoon Reflection, и очень рад, что взялся за это до релиза.

Во-первых, я зарепортил отсутствие обещанной в RFC хуков константы ReflectionProperty::IS_VIRTUAL. Но это тривиально, PR уже готов.

А вот что меня реально загрузило, так это поведение новых методов ReflectionProperty::isPrivateSet() и isProtectedSet() из Asymmetric Visibility RFC. Посудите сами:


final class Foo
{
// isPrivateSet() = true 👌
public private(set) mixed $public_private_set;

// isPrivateSet() = false 🤯
private private(set) mixed $private_private_set;

// isPrivateSet() = false 🤯
private mixed $private;

// isProtectedSet() = true 👌
public readonly mixed $public_readonly;

// isProtectedSet() = false 🤯
protected readonly mixed $protected_readonly;

// isProtectedSet() = false 🤯
protected protected(set) readonly mixed $protected_protected_set_readonly;

// isPrivateSet() = false 👌, isProtectedSet() = false 👌
public bool $virtual_no_set_hook { get => true; }
}


Сначала я подумал, что это баг, и создал тикет php-src#16175. Ilija, автор RFC, объяснил, почему так работает. Дело в том, что у свойств с симметричной видимостью отсутствует флаг ассиметричности. Поэтому для private и private private(set) isPrivateSet() возвращают false, а не true, как было бы логично ожидать. readonly свойства без явного (set) под капотом получают protected (set) (см. "Relationship with readonly" в RFC), поэтому public readonly будет ассиметричным с isProtectedSet() = true, а protected readonly — симметричным с isProtectedSet() = false.

Стало понятно, вот только пользоваться такой рефлексией по-прежнему дико неудобно. В API протекли детали реализации, которые, наоборот, должны быть инкапсулированы. Задача рефлексии — предоставить пользователю комфортный способ изучать код, а не продемонстрировать подкапотное устройство языка.

Но это ещё ладно. Сегодня до меня дошло, что в текущем виде рефлексия в PHP 8.4 ломает обратную совместимость! Если раньше проверка $reflectionProperty->isPublic() гарантировала, что не readonly свойства доступны на запись и чтение из глобального скоупа, то при текущей реализации в 8.4 она будет гарантировать только чтение!


$reflectionProperty = new ReflectionProperty($class, $property);

if ($reflectionProperty->isPublic() && !$reflectionProperty->isReadonly()) {
$object->{$property} = $value;
}


Например, такой код корректно отработает для любых классов в PHP 8.3, но споткнётся на public private(set) $property в 8.4, потому что isPublic() вернёт true, а запись в свойство бросит ошибку.

Вот что я предложил в письме к internals, которое составил в Сапсане по дороге на Live PHP:

• ReflectionProperty::isPublic(), isProtected() и isPrivate() должны сохранить своё поведение и возвращать true только если свойство симметричное. Для public readonly метод будет возвращать false, потому что под капотом оно асимметричное с protected(set). Да, это сломает обратную совместимость, но не так критично, потому что все библиотеки уже учитывают тот факт, что в readonly нельзя писать из глобального скоупа.
• Добавить ReflectionProperty::isPublicGet(), isProtectedGet() и isPrivateGet(). Они должны возвращать true, если свойство симметрично или асимметрично доступно на чтение.
• Добавить ReflectionProperty::isPublicSet() и поменять поведение isProtectedSet() и isPrivateSet(): они должны возвращать true, если свойство симметрично или асимметрично доступно на запись.

Вся проблема в том, что недавно вышел PHP 8.4 RC1, и вносить изменения уже поздно. Надеюсь, что мой посыл про нарушение обратной совместимости всё-таки убедит сделать исключение.
externals.io Asymmetric visibility Reflection API problems - Externals #externals - Opening PHP's #internals to the outside
  • 👍 45
  • 🤯 37
  • 🔥 14
  • ❤ 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 →