On Sun, Nov 9, 2025, at 16:33, Larry Garfield wrote: > 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: > > [snip] > > Whether that is a design flaw or a feature is, I suppose, debatable. > > > --Larry Garfield
Hi Larry (and everyone else following the thread), I think we’re all aligned that PHP would benefit from a proper module or package boundary. Many features people want — including namespace visibility — become cleaner once such a boundary exists. One doesn’t strictly require the other, but they definitely complement each other. The difficulty is that PHP currently has no agreed-upon definition of what a “module” or “package” *is*: • Composer root namespaces? • Physical directories? • Compilation units? • Attributes? • Something else entirely? Because of that, there’s no existing boundary we can safely build on without first settling that much larger question. That’s why this RFC deliberately stays within a boundary the language *already* defines: the lexical namespace. It doesn’t try to define packages or introduce any new scoping model. It also doesn’t prevent a future RFC from doing so. If the community reaches consensus on a formal module/package boundary later, namespace-level visibility can coexist with it or even be folded into it. Nothing in this RFC blocks that path. What this RFC does is provide a useful, enforceable intermediate step that doesn’t require the community to solve “packages” first. If we require a full module system before adding any visibility improvements, we’re essentially saying that no incremental progress is acceptable until the hardest part of the problem is fully solved. That’s historically not how PHP evolves. To keep this discussion focused: If someone has concerns about *this RFC’s* semantics, performance, syntax, implementation, error messaging, interaction with inheritance/traits, or BC impact — that’s absolutely fair and I’d like to address them: But I’d like to avoid turning this into a thread about defining a package/specification/module system. That’s a valid discussion, and I’d happily participate in another thread, but it’s not one this RFC is trying to solve. Namespace visibility is intentionally small, intentionally conservative, and intentionally compatible with whatever direction modules eventually take. It’s the smallest useful step the language can take today, without blocking future work, while still being useful. ---- Now, to reply to your specific points about this RFC: First, syntax vs. AViz. Aviz establishes `visibility(operation)` as the pattern for asymmetric visibility, where the keyword controls the caller set and parentheses restrict the operation (get/set). That’s why `private(namespace)(set)` follows the same rule: the base visibility is still "private", and the parentheses narrows who may call it. If we introduced a standalone keyword like `internal` or `nsviz`, we’d effectively be adding a new visibility class, not a refinement of `private` and would bring its own semantics, collision issues, and interactions with any future module work. This RFC aims to minimise surface area, which is why it treats namespace visibility as a refinement. That said, if the consensus emerges around a new keyword, that’s something I can adjust. The important behaviour is the caller rule, not the exact token spelling. Second, is exact-match useful enough? Yes, there are plenty of codebases where internal helpers live side-by-side in one namespace, especially in domain-driven or layered architectures where namespaces are the boundaries. Today, teams either make them public, wrap them in a service class, use `@internal`, or wire them together via reflection or debug_backtrace. All of those come with tradeoffs. Exact-match namespace visibility offers a simple enforceable boundary without designing a whole package system or assuming anything about code hierarchy. It’s not the most expressive possible rule, but it’s useful and predictable. If the community prefers prefix-based visibility or package-level visibility, that could be explored in a follow-up RFC. I’m not opposed to more expressive forms; I’m just not binding this RFC to a package model the language hasn’t defined yet. And lastly, isn’t namespace visibility easy to bypass? Yes — but so is private and protected. No PHP visibility is intended as a security boundary. This is a developer-intent boundary: encapsulation, static analysis, and making accidental misuse harder. If a future module/package system introduces stronger enforcement, this RFC can layer underneath it without a conflict. Sincerely, — Rob
