On Sun, Nov 9, 2025, at 21:51, Tim Düsterhus wrote:
For this one I am however not sure if it ticks the “composes well”
checkbox - that greatly depends on the syntax choice and how modules
will look like if/when they eventually arrive.
I understand the concern. Composability matters a lot, especially for features that touch visibility. My goal with this RFC is to take a boundary PHP already has (the lexical namespace) and make it enforceable without needing to answer the bigger “what’s a module/package?” question first.
Right now, different people in the ecosystem use namespaces in different ways: some treat them as hierarchical, some as flat prefixes, some map them to directory trees, some don’t. Trying to define prefix rules, upward/downward access, or package-like confinement gets us right back into the same conversation we’ve been stuck on. That’s why this RFC deliberately picks the simplest rule PHP could enforce today: exact namespace equality.
If a future RFC defines modules/packages, namespace-visibility can either:
- fold into that boundary,
- be superseded by it, or
- be used inside it (e.g.
internal for modules, private(namespace) within module internals).
Nothing in this RFC makes that harder.
Your RFC appears to use the old template for the “RFC Impact” section
which doesn’t yet include the “Ecosystem Impact” subsection, but
indicating that “significant OPcache changes” are required makes me
wonder about the cost-benefit ratio.
Thanks! I’ll look at the new template and call out ecosystem impact (this was originally written back in April/May?). On the OPcache point: “significant” is probably overstating it. The change is limited to persisting one additional interned string on zend_op_array and refcounting it correctly. The cost is paid at compile time, not at call time, so runtime performance impact should be negligible. I’ll reword this to be more precise.
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.
As noted in my reply in the thread from Faizan, calling this a
refinement of private is not really accurate / doesn’t work in practice.
Agreed. After the discussion with you, Alex, and Larray, I think it’s clearer to describe private(namespace) as a distinct caller-set, not a subset of protected or private. I’ll update the RFC text to reflect that and disallow weird combinations (to be more clearly defined in the RFC).
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.
To do so, the syntax would need to account for that. I have not yet seen
a good proposal for that that doesn’t end up as “symbol soup” that
doesn’t really fit the existing language syntactically.
My earliest version simply used namespace:
class P {
namespace function x() {}
}
It might make sense to return to that syntax if people don’t like the current syntax. I don’t have a strong attachment to the exact spelling, what matters is the semantics.
— Rob