On Mon, 14/10/2024 at 06:01, Larry Garfield <la...@garfieldtech.com> wrote:
>
> On Sun, Oct 13, 2024, at 9:37 PM, Valentin Udaltsov wrote:
>
>
> > First of all, I have already agreed above that PHP does not have a BC
> > break here. Now we are discussing the potential problems in the PHP
> > ecosystem and how they could be mitigated.
>
> Ilija and I have discussed this issue a bit.
>
> The first issue is that isPublic() technically means "does this property have 
> the public flag set," and nothing more. Prior to 8.1, that implicitly also 
> meant "can the property be read and written to from public scope," because of 
> how properties worked. (And same for isProtected().) That implicit assumption 
> became invalid in 8.1 with readonly, which stealth introduced limited and not 
> fully designed asymmetric visibility as well as properties that could not be 
> set multiple times from any scope. Full aviz in 8.4 doesn't change that. It 
> just makes the previous assumption change more apparent. The fact that no one 
> seems to have reported it as an issue until now suggests it's not a 
> particularly widespread problem.  In practice, if someone is using reflection 
> to determine the visibility of a property, they'll be writing to it through 
> reflection as well if at all.
>
> The best solution here is probably to just clarify the docs, which I will do 
> as part of the aviz docs that I have already been working on.  cf: 
> https://github.com/php/doc-en/pull/3828
>
> The second issue is that the behavior of isProtectedSet() / isPrivateSet() 
> was not as clearly defined in the RFC as it should have been. That's on us 
> for not being clearer, as we apologize for the oversight.
>
> Those methods follow the low level pattern of isPublic() , that is, they just 
> report of a given flag is set, not what the implications of that flag in 
> various contexts are. That is consistent with the rest of the reflection API, 
> so we feel that is best left as-is.
>
> That still means the "so can I  read/write this property or not?" question 
> has no simple operation for it. Again: it never did, we just kinda sorta had 
> it indirectly and implicitly. For that we feel the best answer, as well as 
> least disruptive given we're in RCs, is dedicated methods as Ilija has 
> already described that take all property behavior and context into account. 
> (isReadable and isWriteable.)
>
> As a reminder, the concept is:
>
> $rProp->isReadable($obj); // Can this property on $obj be read from the 
> calling scope?
> $rProp->isReadable($obj, 'static'); // Same as previous.
> $rProp->isReadable($obj, null); // Can this property on $obj be read from 
> global scope?
> $rProp->isReadable($obj, Foo::class); // Can this property on $obj be read 
> from code inside class Foo?
>
> $rProp->isWriteable($obj); // Can this property on object $obj be written 
> from the calling scope?
> $rProp->isWriteable($obj, 'static'); // Same as previous.
> $rProp->isWriteable($obj, null); // Can this property on object $obj be 
> written from global scope?
> $rProp->isWriteable($obj, Foo::class); // Can this property on object $obj be 
> written from code inside class Foo?
>
> cf: https://github.com/php/php-src/pull/16209
>
> (The use of null to indicate global scope is borrowed from Closure::bind(), 
> which does the same.)
>
> These methods do runtime analysis to see if a property should be 
> readable/writeable.  Specifically:
>
> isReadable()
> * Checks that the property is readable from the passed scope
> * Checks that the property is initialized (i.e. not typed and never written 
> to)
> * Checks that the property is not virtual or has a get hook
> isWritable()
> * Checks that the property is writable (respecting symmetric and asymmetric 
> properties) from the passed scope
> * Checks that the property is not readonly, is not yet initialized, or is 
> reinitializable (__clone)
> * Checks that the property is not virtual or has a set hook
>
> Of note, this does not absolutely guarantee that a read/write will succeed.  
> There's at least two exceptions: One, some PHP built-in classes have 
> effectively immutable properties but do not use `readonly` or `private(set)`. 
>  Those would not be detected here, until and unless they are updated to use 
> the now-available mechanisms.  (See, eg: 
> https://github.com/php/php-src/issues/15309)  The other is that a get or set 
> hook may throw an exception under various circumstances.  There is no way to 
> evaluate that via reflection, so it's a gap that will necessarily always be 
> there.
>
> Whether those methods are OK to add in the RC phase or if they should be left 
> to early 8.5, and if they would need a formal RFC, is up to the RMs to 
> decide. RMs, what is your preference?
>
> --Larry Garfield

Hi, Larry!

Thank you very much for this response. I agree with every point.

I have only one comment about the methods' signatures. They should not
require an object, because properties can be static or the developer
might want to check writable/readable without instantiating an object
(in a code generator, for instance).
Then it makes sense to make `$object` the 2nd parameter. This will
also be consistent with Closure::bind().

isReadable(?string $scope = 'static', ?object $object = null): bool
isWritable(?string $scope = 'static', ?object $object = null): bool

-- 
Best regards,
Valentin

Reply via email to