Re: RFC: Namespace-Scoped Visibility for Methods and Properties
| From: | Larry Garfield | Date: | Sun, 09 Nov 2025 15:33:36 +0000 |
| Subject: | Re: RFC: Namespace-Scoped Visibility for Methods and Properties | ||
| References: | 1 2 3 4 5 6 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-129168@lists.php.net to get a copy of this message | ||
On Sat, Nov 8, 2025, at 5:13 PM, Rowan Tommins [IMSoP] wrote:
> On 08/11/2025 21:56, Rob Landers wrote:
>> One advantage of keeping this RFC small is that it can be expanded
>> later without a BC break. For example, prefix matching (maybe
>> something like
private(namespace: Acme\AuthLib)) or a
>> protected-namespace variant could be layered on top if the community
>> wants to go in that direction.
>
> That's a reasonable argument, but the risk is that if we don't consider
> what that future scope would look like, we can end up with syntax or
> semantics that makes our lives unnecessarily difficult later. As I
> understand it, this happened to some extent with the "readonly" keyword.
Exactly the example I was thinking of. :-) "Junior version first" approaches sometimes
work out (FCC doesn't seem to have caused issues for PFA in practice), and other times not
(readonly was a major PITA for aviz, and even delayed it for a release as we figured out how they
should interact). I'd much rather know what the "full solution" looks like and plan
for it, even if it's in incremental steps, than throw a junior version at the wall and hope for
the best.
>> This RFC isn’t intended to solve the entire space; it’s the smallest
>> useful step that seems to fairly cleanly fit into PHP’s current model
>> without too much churn on the engine.
>
> I think my fundamental question is: is it actually that useful? How
> often, in practice, do people want exact namespace matching, vs
> something more flexible?
In practice, the extra-class boundary I most often want is "my composer package." I
rarely need to protect things beyond that.
I am broadly in favor of extra-class visibility controls, whether they go through a module system or
something else. Whether the current RFC is a good way of doing so, I am not convinced.
In particular, the syntax is a hard-no. It runs contrary to how the aviz syntax was defined, as
others have already noted.
If you don't want to use internal(set) to save internal for some
other use, that's fine. Come up with a different keyword. :-) But <allowed
scope>(<operation>) is the syntax model that aviz established, and tossing extra parens in
there just confuses things for everyone.
If it really does need to be an entirely separate dimension of scoping, then I would argue it's
too complex to capture in just keywords and Rowan's attribute proposal becomes even more
compelling.
That said, I'm not convinced it is a separate dimension yet. I'd put "nsviz"
between public and protected, not protected and private. The assumption is that your
"allowed" scope is something you control. So if you don't want to use that property
from child classes in your own namespace... just don't. If you don't want to allow it to
be used by child classes in another namespace... then nsviz(get) solves that problem.
I will also note that while it's typical for namespace and file path to be 1:1, there's
nothing that requires it. That means any strictly namespace-based visibility is trivial to bypass.
For example:
// vendor/foo/bar/Baz.php
namespace Foo\Bar\Baz;
class Careful {
nsviz string $secret;
}
// /app/User.php
namespace Foo\Bar;
class Invader {
public function hax(Careful $c): string {
return $c->secret;
}
}
namespace App;
class User {
public function doStuff(Careful $c) {
$secret = new Foo\Bar\Invader($c)->hax();
// Boom, we've read the value.
}
}
Whether that is a design flaw or a feature is, I suppose, debatable.
--Larry Garfield