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
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
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
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/constantsAttribute
- 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 functionalityFor 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
On Mon, May 4, 2026 at 12:50 PM Larry Garfield larry@garfieldtech.com
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
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
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