leonphp4 Jun 2026 15:22

PHP 8.4 gave us asymmetric visibility on instance properties, the public private(set) style where a property reads public but only writes from inside the class. In 8.5 this extends to static properties. I have a config registry that exposes a static map publicly but should only be mutated through a controlled setter, and this looks like exactly the fit.

Before I lean on it: are there gotchas with the static variant specifically, inheritance, or interaction with readonly, that are not obvious from the basic instance examples?

Replies (5)
ivan_morozov4 Jun 2026 15:47

The basic form works as you expect. You write public private(set) static array $registry = []; and reads are public while writes are restricted to the declaring class. The one thing to internalize is that the set visibility cannot be wider than the get visibility, only narrower. So public get with protected or private set is fine, the reverse is a parse error.

0
jnovak4 Jun 2026 16:42

On inheritance, a protected(set) static lets subclasses write it, private(set) does not, same as instance properties. The subtle static-specific point is that a static property is shared across the class hierarchy in the usual PHP way, so asymmetric visibility controls who can write but not the fact that all subclasses see the same single value. Do not expect per-subclass copies, that is a separate concern from visibility.

0
dmitry_kv4 Jun 2026 18:12

Do not confuse this with readonly. readonly means write exactly once, asymmetric visibility means write as often as you like but only from the allowed scope. A registry you keep mutating wants asymmetric visibility, not readonly, since readonly would forbid the second write entirely. They can combine on instance properties but for a mutable static map you specifically want the visibility feature alone.

0
leonphp4 Jun 2026 19:22

The readonly distinction is the clarity I needed, my registry mutates over the app lifetime so readonly was never right. public read with private(set) static is exactly the contract: callers can read the map freely, only my controlled setter writes it. Saves me writing a getter that returns a copy just to protect a private static. Cleaner and the intent is visible in the declaration.

0
dmytro_lv4 Jun 2026 20:52

One practical note, error messages when external code tries to write are clear now, you get a visibility error pointing at the set scope, which is much better than the old convention of a public property plus a comment begging people not to touch it. Static analysis tools also understand it, so PHPStan will flag an illegal write at analysis time instead of you finding out at runtime.

0
Write a reply
Markdown. ```php blocks are runnable.