In other news, Ilija and I said a year ago that we'd take a swing at adding isReadable/isWriteable methods to ReflectionProperty. Took a while, but here we are. A strangely small RFC from us:
https://wiki.php.net/rfc/isreadable-iswriteable
--
Larry Garfield
larry@garfieldtech.com
Hi
Am 2025-11-06 00:24, schrieb Larry Garfield:
In other news, Ilija and I said a year ago that we'd take a swing at
adding isReadable/isWriteable methods to ReflectionProperty. Took a
while, but here we are. A strangely small RFC from us:
I dislike implicitly “scope-dependent” functions, since they effectively
act like magic. This probably makes it harder to understand for humans
and static analysis tools alike. I would therefore suggest making the
$scope parameter required. A user can just pass static::class
themselves and static analysis tools can use class-string|null instead
of class-string|"static"|null as their expected parameter type.
As for the magic method logic: I would suggest to ignore the presence of
__get() and __set(). This more closely aligns with the direction PHP
goes towards and is also easy to work around by checking with
method_exists() whether any such a method exists - the reverse is not
true.
Best regards
Tim Düsterhus
Hi
Am 2025-11-06 00:24, schrieb Larry Garfield:
In other news, Ilija and I said a year ago that we'd take a swing at
adding isReadable/isWriteable methods to ReflectionProperty. Took a
while, but here we are. A strangely small RFC from us:I dislike implicitly “scope-dependent” functions, since they effectively
act like magic. This probably makes it harder to understand for humans
and static analysis tools alike. I would therefore suggest making the
$scopeparameter required. A user can just passstatic::class
themselves and static analysis tools can useclass-string|nullinstead
ofclass-string|"static"|nullas their expected parameter type.
Given that the 90% or more case is likely to be "from my current context", making that the default seems the most ergonomic. (The counter argument, I suppose, is that this is hardly going to be a super-common routine to call so ergonomics don't matter.)
stack-inspection isn't new. Closure::getCurrent() is the most recent example, so we don't think it's especially problematic.
If there's a preference for avoiding magic strings, it would be easy enough to use an enum instead. Something like:
enum CallerScope {
case Caller;
case Global;
}
function isReadable(string|CallerScope $scope = CallerScope::Caller, ?object $objecg = null) { ... }
Caller would still do the same stack inspection, but it makes the type more tightly controlled and eliminates a nullable.
As for the magic method logic: I would suggest to ignore the presence of
__get() and __set(). This more closely aligns with the direction PHP
goes towards and is also easy to work around by checking with
method_exists()whether any such a method exists - the reverse is not
true.
thumbs-up.gif
--Larry Garfield
Hi
(The counter argument, I suppose, is that this is hardly going to be a super-common routine to call so ergonomics don't matter.)
Yes. I expect this to mostly be useful deep within frameworks or
specialized libraries. The type of code where these functions are likely
to be used are very likely to be functions with an above-average
complexity and having explicit code there will help keep the complexity
low. Also it's not like static::class is particularly complicated to use.
One issue I'm seeing with the “magic context” logic is that the code
will suddenly break when the call to ->isReadable() is moved into a
helper function. Particularly when you consider the __get() use case
that I mentioned below: Folks that are interested in wanting to learn
whether there's a property that is actually readable or a magic getter
might want to put this combined logic into a helper - and then the
implicit scope will no longer work.
stack-inspection isn't new.
Closure::getCurrent()is the most recent example, so we don't think it's especially problematic.
The difference is that Closure::getCurrent() is a single-purpose
function that is explicitly defined to operate on the current scope. It
specifically throws an Error when misused. ->isReadable() OTOH will
silently misbehave.
AFAICT it would also be the first reflection function that has dynamic
behavior.
If there's a preference for avoiding magic strings, it would be easy enough to use an enum instead. Something like:
My issue is not primarily with the “magic string”, but with the quite
significant behavioral difference depending on the parameter value.
Best regards
Tim Düsterhus