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

Reply via email to