Re: [RFC] [Discussion] Friends
| From: | Larry Garfield | Date: | Mon, 11 May 2026 16:31:08 +0000 |
| Subject: | Re: [RFC] [Discussion] Friends | ||
| References: | 1 2 3 4 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-130831@lists.php.net to get a copy of this message | ||
On Mon, May 11, 2026, at 10:33 AM, Rob Landers wrote:
> On Mon, May 11, 2026, at 16:58, Daniel Scherzer wrote:
>> Surprisingly I think adding an entirely new syntax would actually result in the fewest
>> breaking changes when userland classes add friends, because there is no ambiguity.
>>
$u->id always refers to the id on
>> whatever class $u happens to be, including applying any shadowing;
>> if you want to be sure to access the base User::$id, use
>> <$u as User>->id.
>>
>> Before I dive in and actually add that, what do people think?
>
> By the end of it, I basically arrived at a calculus that makes a sorta
> sense. Visibility levels are sets of callers, partial-ordered by
> inclusion. An override is admissible iff the child's caller set is a
> superset of the parent's at the call site. P's caller set for
> $x with
> friend F is {P, F}; C's shadowing with
> protected $x gives {C ∪
> descendants(C)}; incomparable, so the override violates LSP.
>
> Through that lens, we can look at your options you identified.
>
> Option 1 basically kills the entire feature.
>
> Option 3 breaks polymorphism. It throws away legitimate overrides.
>
> Option 4 is an escape hatch, not a solution. There's already RFCs for
> "as" in-progress, so you'd step on some toes there. Heh, I think I have
> even proposed "as" before and ... from experience, competing with
> someone's in-progress RFC without discussion with them beforehand is a
> great way to have people get mad at you on this list.
>
> Option 2 is probably the closest "right" answer. It prevents there from
> being invalid caller sets and can provide meaningful error messages at
> compile time: "name collides with friended private variable; must
> friend with class F or change the name x".
>
> Another option to consider is not allowing private variables/methods to
> be accessed by friends. Only protected variables/methods. This allows
> inheritance to work as normal and guarantees overrides are compatible.
>
> — Rob
Honestly, this seems like the easiest model to explain to people. A friend class has the same
access as a child class, ie, it gets protected but not private access. That's a very simple
rule to document and explain, and seems like it would side-step a number of issues. (We had a
similar conversation for aviz, IIRC, which is how we ended up on private => final and readonly
=> protected(set) simplifying a lot of issues.)
That said, I am still skeptical. This seems simple enough, but I worry that it's still
attacking the general problem in too specific a way (compared to modules or similar).
--Larry Garfield