Pre-RFC discussion about adding friendship to PHP

php.internals

Daniel Scherzer

125 days ago
Hi internals, I'd like to add support for friendship in PHP. I don't mean friendship in the PSR-8 huggable way, but rather in the C++ way of allowing access to non-public parts of a class without needing to use Reflection. I haven't started work on implementing this yet, but there is a big question about how to indicate friendship that I wanted to get some feedback on. Specifically, should it be added with a new keyword, or with an attribute? Keyword * matches C++ * suggests that friends are aspects of the class, like properties and constants and methods * but would look a bit ugly if we added support for friends that are just for specific properties/methods/constants Attribute * matches how other metadata is added to classes * would make it look cleaner if subsequently support was added for friendship being applied to specific properties/methods/constants * would differ from the current builtin attributes in that it doesn't just add/remove warnings, but changes some functionality For a more in-depth explanation of the inspiration and these two potential approaches, see https://scherzer.dev/Blog/20260309-php-friends. To be clear, I have not yet written an implementation, much less the RFC, but I wanted to get some initial feedback on if people would prefer a new keyword, or an attribute, for declaring friends. -Daniel

Tim Düsterhus

124 days ago
Hi Am 2026-04-29 19:30, schrieb Daniel Scherzer:
> I haven't started work on implementing this yet, but there is a big > question about how to indicate friendship that I wanted to get some > feedback on. Specifically, should it be added with a new keyword, or > with > an attribute?
It should be a proper keyword for the reasons that are also mentioned in your blog post: Attributes are not part of the public API and thus do not contribute to e.g. LSP checks. They are also expected to gracefully degrade when they do not exist, which means that running code written with friendship in mind on older PHP versions will silently expose a different API instead of failing in a visible way. See also the reasoning that I provided in the #[\Override] RFC: https://wiki.php.net/rfc/marking_overriden_methods#why_an_attribute_and_not_a_keyword. I think the related mailing list discussion provides additional context - and I seem to remember I wrote something similar in some other RFC discussion as well. Best regards Tim Düsterhus

Rob Landers

124 days ago
On Wed, Apr 29, 2026, at 19:30, Daniel Scherzer wrote:
> Hi internals, > > I'd like to add support for friendship in PHP. I don't mean friendship in the PSR-8 huggable way, but rather in the C++ way of allowing access to non-public parts of a class without needing to use Reflection. > > I haven't started work on implementing this yet, but there is a big question about how to indicate friendship that I wanted to get some feedback on. Specifically, should it be added with a new keyword, or with an attribute? > > Keyword > * matches C++ > * suggests that friends are aspects of the class, like properties and constants and methods > * but would look a bit ugly if we added support for friends that are just for specific properties/methods/constants > > Attribute > * matches how other metadata is added to classes > * would make it look cleaner if subsequently support was added for friendship being applied to specific properties/methods/constants > * would differ from the current builtin attributes in that it doesn't just add/remove warnings, but changes some functionality > > For a more in-depth explanation of the inspiration and these two potential approaches, see https://scherzer.dev/Blog/20260309-php-friends. To be clear, I have not yet written an implementation, much less the RFC, but I wanted to get some initial feedback on if people would prefer a new keyword, or an attribute, for declaring friends. > > -Daniel
Hi Daniel, We saw some friendship discussions in my nested class RFC, where nested classes implicitly became friends of the outer class. I'd recommend checking those threads for feedback about friendship and scope. — Rob

Larry Garfield

124 days ago
On Wed, Apr 29, 2026, at 12:30 PM, Daniel Scherzer wrote:
> Hi internals, > > I'd like to add support for friendship in PHP. I don't mean friendship > in the PSR-8 huggable way,
Aw, but why not?
> but rather in the C++ way of allowing access > to non-public parts of a class without needing to use Reflection. > > I haven't started work on implementing this yet, but there is a big > question about how to indicate friendship that I wanted to get some > feedback on. Specifically, should it be added with a new keyword, or > with an attribute? > > Keyword > * matches C++ > * suggests that friends are aspects of the class, like properties and > constants and methods > * but would look a bit ugly if we added support for friends that are > just for specific properties/methods/constants > > Attribute > * matches how other metadata is added to classes > * would make it look cleaner if subsequently support was added for > friendship being applied to specific properties/methods/constants > * would differ from the current builtin attributes in that it doesn't > just add/remove warnings, but changes some functionality > > For a more in-depth explanation of the inspiration and these two > potential approaches, see > https://scherzer.dev/Blog/20260309-php-friends. To be clear, I have not > yet written an implementation, much less the RFC, but I wanted to get > some initial feedback on if people would prefer a new keyword, or an > attribute, for declaring friends. > > -Daniel
There was a lot of related discussion around module/package/file visibility not too long ago that is also worth reviewing. Currently I am highly skeptical of friend classes, as I believe module-level visibility is more useful than class-level, in general. That said, were we to go this route, I agree that keywords would be the way to go for the reasons given in the blog post. Also, there's some plumbing already i place via aviz, at least for properties. In concept, the following should be possible: class User { friend UserFactory; public friend(set) string $name; } class UserFactory { public function makeUser($name) { $u = new User(); $u->name = $name; // This is OK, because UserFactory is a friend. return $u; } } $factory = new UserFactory(); $u = $factory->makeUser('Larry'); print $u->name; // OK, because public get $u->name = 'Daniel'; // Error, because not a friend. Whether that makes sense to extend to methods, I don't know. --Larry Garfield

Daniel Scherzer

119 days ago
On Mon, May 4, 2026 at 12:50 PM Larry Garfield <larry@garfieldtech.com> wrote:
> On Wed, Apr 29, 2026, at 12:30 PM, Daniel Scherzer wrote: > > Hi internals, > > > > I'd like to add support for friendship in PHP. > > > > -Daniel > > There was a lot of related discussion around module/package/file > visibility not too long ago that is also worth reviewing. Currently I am > highly skeptical of friend classes, as I believe module-level visibility is > more useful than class-level, in general. >
I think that perfect should not be the enemy of good, and this also lays the groundwork for namespace-level friends in the future. We shouldn't wait for a potential future "module-level visibility" if we can have friends now.
> > That said, were we to go this route, I agree that keywords would be the > way to go for the reasons given in the blog post. Also, there's some > plumbing already i place via aviz, at least for properties. In concept, > the following should be possible: > > class User { > friend UserFactory; > > public friend(set) string $name; > } >
I think having friends that can access everything is more helpful than a new level of visibility - if you declare a class as a friend you already know that the class exists and wants to access private implementation details, so you can trust it to upload the class invariants. -Daniel

Max Semenik

117 days ago
On Thu, Apr 30, 2026 at 5:10 PM Larry Garfield <larry@garfieldtech.com> wrote:
> class User { > friend UserFactory; > > public friend(set) string $name; > } > > class UserFactory { > public function makeUser($name) { > $u = new User(); > $u->name = $name; // This is OK, because UserFactory is a friend. > return $u; > } > }
This seems like an overcomplication, in current PHP this would work just fine: class User { public function __construct( public readonly string $name, ) {} } Some of C++ OOP features have always felt like kludges to me, and friendships are a good example. A well-written class shouldn't care what other classes are using it, as long as they respect its contract.
-- Best regards, Max Semenik

Daniel Scherzer

115 days ago
On Fri, May 8, 2026 at 2:42 PM Max Semenik <maxsem.wiki@gmail.com> wrote:
> On Thu, Apr 30, 2026 at 5:10 PM Larry Garfield <larry@garfieldtech.com> > wrote: > >> class User { >> friend UserFactory; >> >> public friend(set) string $name; >> } >> >> class UserFactory { >> public function makeUser($name) { >> $u = new User(); >> $u->name = $name; // This is OK, because UserFactory is a friend. >> return $u; >> } >> } > > > This seems like an overcomplication, in current PHP this would work just > fine: > > class User { > public function __construct( > public readonly string $name, > ) {} > } > > Some of C++ OOP features have always felt like kludges to me, and > friendships are a good example. A well-written class shouldn't care what > other classes are using it, as long as they respect its contract. > > -- > Best regards, > Max Semenik >
That example works for users with just a name, but what about users with both a name and user id, with the class invariant that the user with the given name has that specific ID? A class like ``` class User { public function __construct( public readonly string $name, public readonly int $id, ) {} } ``` means that the requirement is on *callers* to get it right, on pain of breaking a whole bunch of things that assume the user id and username correspond to the same record. And while you could do that, it makes it a lot easier to break things. Instead, you would want to have the constructor private. But then, how to create new instances of the User class when you have properly looked up the user id and name in the database? You could add a public static method on User, which would be able to call the constructor, but static methods present other complications with dependency injection and unit testing. And once you move to a separate UserFactory, you wind up with the original issue this seeks to address - how can UserFactory interact with the internals of the User class. Other than making those internals public (which we don't want to do) the only option is to use reflection (which is generally frowned upon). Hence, the proposal to add friends. -Daniel