Re: Re: [RFC] [Discussion] Friends
| From: | Daniel Scherzer | Date: | Mon, 08 Jun 2026 18:42:00 +0000 |
| Subject: | Re: Re: [RFC] [Discussion] Friends | ||
| References: | 1 2 3 4 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-131172@lists.php.net to get a copy of this message | ||
On Mon, Jun 8, 2026 at 2:19 AM Tim Düsterhus <tim@bastelstu.be> wrote:
> Hi
>
> Am 2026-06-04 01:13, schrieb Daniel Scherzer:
> > Seeing no further feedback, I have adjusted the RFC and the
> > implementation
> > to only allow access to protected properties/methods/constants.
> > This qualifies as a "major change" and triggers a 14 day cooldown
> > period.
>
> I've given the RFC another read and stumbled over:
>
> > Friendship is not inherited. If UserFactory has a subclass
> > NamedUserFactory, that subclass cannot access the protected details of
> > User
>
> From what I see this would also be in violation of the LSP, because
> subclasses are not fully interchangeable with the top-level class. It
> would also need clarification what the relevant “authority” for
> accessibility is: Is it the class name of the actual class or is it the
> defining class of the method in question?
>
> i.e.
>
> class User { friend UserFactory; protected function __construct() {
> } }
>
> class UserFactory {
> public function foo() { new User(); }
> }
>
> class ChildUserFactory extends UserFactory { }
>
> $f = new ChildUserFactory();
> $f->foo(); // Is this legal? ChildUserFactory is not a friend, but
> foo() is defined in UserFactory.
>
> Best regards
> Tim Düsterhus
>
Since
foo() is defined in UserFactory rather than
ChildUserFactory,
the method call still works - I was going to go add a test for this, but I
already have one, see
https://github.com/DanielEScherzer/php-src/blob/9f3c8dcac5032f11cf8b8c0ee6a4a2611a2a3933/Zend/tests/friends/not_inherited.phpt
Specifically, friendship is checked based on where the caller is *defined*,
i.e. for inherited methods (here ChildUserFactory::foo(), in my test
Baz::testFooAccess()) the parent class which defines the function is what
needs to be a friend.
I've added this clarification to the RFC text with a clearer example (and
updated the implementation with the new example test) - even when foo()
is overridden, using parent::foo() would work. As long as the actual
access is done from code defined in a friend, things work.
Let me know if the updated RFC text is still unclear.
-Daniel