Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129171 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id 9C7D81A00BC for ; Sun, 9 Nov 2025 17:20:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1762708842; bh=fGxR9lx+iIZUqk8BAka+xnV53Dvoc0fyQjlCNbCjfm4=; h=Date:From:To:In-Reply-To:References:Subject:From; b=TTnVhd0HfDe77P5J2JNIxKeSATK4WR1Yus8SMXlyaiJnFyddWR0m5U5i3vUGODiYF PLW+a6Y6mASoEOy5kAsQQyci0TvtK/prdgSS1eC87osfJV/IcQZG88ao3QvCAQOZYO tH1XT9beWG7mXp82dRt22yYIBDMwv4xlVy9VRxySjtDOktiv0jLyjlslzSNFA0e3Wl TF8nP9YG9jL7PKgbdfrnYv4Q+1tIDtSVACSwc05Ma9ZJeuIXV2FXPkC0iUk1THJ4w6 5aUQzO5GAuElqk1J7Ep8h5hrAYE6p7GVvSloonB1jFOZwZmrfVQQR3fK/uxQFYK0qt +gD99kiOW1DAQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id CAC9E1801E2 for ; Sun, 9 Nov 2025 17:20:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-0.9 required=5.0 tests=BAYES_40,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,HTML_MESSAGE, RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from fhigh-a2-smtp.messagingengine.com (fhigh-a2-smtp.messagingengine.com [103.168.172.153]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sun, 9 Nov 2025 17:20:35 +0000 (UTC) Received: from phl-compute-12.internal (phl-compute-12.internal [10.202.2.52]) by mailfhigh.phl.internal (Postfix) with ESMTP id 36E2F1400186 for ; Sun, 9 Nov 2025 12:20:30 -0500 (EST) Received: from phl-imap-05 ([10.202.2.95]) by phl-compute-12.internal (MEProxy); Sun, 09 Nov 2025 12:20:30 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bottled.codes; h=cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1762708830; x=1762795230; bh=eRrpDcqMcw WbdqKrK7bO6sCIECme9YyQ99CjTEJJEoQ=; b=Mn/pg5TYAU/7eG4QOzvHW5/5X0 Jp/3kezQ2QlbhhFhlxu3/E3M9WDDvh9fwJSCGCK/98eKJgFwFc3OYelWnrK+ZOY2 qT5JvJWt7i5AjjKUEZHrKt39E1bESZHdebSDOWITY6dGci3DAvlb8E6XvDgasp93 f+jfDL03v60oqpyJHbHjDdfIym4xvZ1NHRwvqkilu64OxNtFfV8/8/Le26LZJVd5 FFARWApphDzcURCYeaEfgDLdeaVfq3lLSiHUBl2mcZ+rmO5E4GyMrovqVr3ftcZx Sufm+XY/ojGX3q5+bLHo8+o+IMsy4vid8gW3AULhxLYBSr/SdOQLt5V610fw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t= 1762708830; x=1762795230; bh=eRrpDcqMcwWbdqKrK7bO6sCIECme9YyQ99C jTEJJEoQ=; b=D+YL4T+LZF22ing8wAT7rbVysSvoOruaEcVktFM9Pxi+DGRAzIK c/URcvDLrXiOSx9ZWV+TbHOR3H45DooHK0sWmvPxVBW3jIxBxeH36l5Yp1+3Uv2r lwcT6EGXQZ/hb/SZfcqYRRduJLVEH+lTsf+XspM4KPkZ2oG33NdmAUxl844P0hp8 jHGqbnIvaGUZw6mHlbnBefiP9x30hrOKlJ/cIxc4U01qCumgwItJEMlR5V4jXRQZ eOt0/ZMYGpQ52re8HrluvQAHorH2MK1dOrAlsiflDOLAUPpMbpUvFPH4Om9PuwfT AS1ZdEecVNr8mFFJmheqDsaNaM3sKOkz/zg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdduleeitddtucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucenucfjughrpefoggffhffvkfgjfhfutgesrgdtreerre dtjeenucfhrhhomhepfdftohgsucfnrghnuggvrhhsfdcuoehrohgssegsohhtthhlvggu rdgtohguvghsqeenucggtffrrghtthgvrhhnpedtueejtdethfeulefhtdelieduteelff dtudelheffgedtieehhfelieejgfevgeenucevlhhushhtvghrufhiiigvpedtnecurfgr rhgrmhepmhgrihhlfhhrohhmpehrohgssegsohhtthhlvggurdgtohguvghspdhnsggprh gtphhtthhopedupdhmohguvgepshhmthhpohhuthdprhgtphhtthhopehinhhtvghrnhgr lhhssehlihhsthhsrdhphhhprdhnvght X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id C2E0A1820054; Sun, 9 Nov 2025 12:20:29 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 X-ThreadId: AZgO4gJIj6HZ Date: Sun, 09 Nov 2025 18:20:09 +0100 To: internals@lists.php.net Message-ID: <1606b9e5-62b8-446b-adac-519ac19d01c3@app.fastmail.com> In-Reply-To: <8978174c-04fc-451a-8bf5-cb7c54346318@app.fastmail.com> References: <72f90052-fa19-415c-9f5a-ae75275fd030@rwec.co.uk> <2d9f8f1d-e568-4bb5-b30c-0a9e54a8f5fe@rwec.co.uk> <8978174c-04fc-451a-8bf5-cb7c54346318@app.fastmail.com> Subject: Re: [PHP-DEV] RFC: Namespace-Scoped Visibility for Methods and Properties Content-Type: multipart/alternative; boundary=f2b76d14d7e54533b2b167edce79947f From: rob@bottled.codes ("Rob Landers") --f2b76d14d7e54533b2b167edce79947f Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable 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: >=20 > >> One advantage of keeping this RFC small is that it can be expanded=20 > >> later without a BC break. For example, prefix matching (maybe=20 > >> something like `private(namespace: Acme\AuthLib)`) or a=20 > >> protected-namespace variant could be layered on top if the communit= y=20 > >> wants to go in that direction. > > > > That's a reasonable argument, but the risk is that if we don't consi= der=20 > > what that future scope would look like, we can end up with syntax or=20 > > semantics that makes our lives unnecessarily difficult later. As I=20 > > understand it, this happened to some extent with the "readonly" keyw= ord. >=20 > Exactly the example I was thinking of. :-) "Junior version first" app= roaches sometimes work out (FCC doesn't seem to have caused issues for P= FA 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 in= teract). I'd much rather know what the "full solution" looks like and p= lan for it, even if it's in incremental steps, than throw a junior versi= on at the wall and hope for the best. >=20 > >> This RFC isn=E2=80=99t intended to solve the entire space; it=E2=80= =99s the smallest=20 > >> useful step that seems to fairly cleanly fit into PHP=E2=80=99s cur= rent model=20 > >> without too much churn on the engine. > > > > I think my fundamental question is: is it actually that useful? How=20 > > often, in practice, do people want exact namespace matching, vs=20 > > something more flexible? >=20 > In practice, the extra-class boundary I most often want is "my compose= r package." I rarely need to protect things beyond that. >=20 > 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. >=20 > In particular, the syntax is a hard-no. It runs contrary to how the a= viz syntax was defined, as others have already noted. >=20 > If you don't want to use `internal(set)` to save `internal` for some o= ther use, that's fine. Come up with a different keyword. :-) But () is the syntax model that aviz established, and t= ossing extra parens in there just confuses things for everyone. >=20 > 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 Ro= wan's attribute proposal becomes even more compelling. >=20 > 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 as= sumption is that your "allowed" scope is something you control. So if y= ou don't want to use that property from child classes in your own namesp= ace... just don't. If you don't want to allow it to be used by child cl= asses in another namespace... then nsviz(get) solves that problem. >=20 >=20 > I will also note that while it's typical for namespace and file path t= o be 1:1, there's nothing that requires it. That means any strictly nam= espace-based visibility is trivial to bypass. >=20 > For example: >=20 > [snip] >=20 > Whether that is a design flaw or a feature is, I suppose, debatable. >=20 >=20 > --Larry Garfield Hi Larry (and everyone else following the thread), I think we=E2=80=99re all aligned that PHP would benefit from a proper m= odule or package boundary. Many features people want =E2=80=94 including= namespace visibility =E2=80=94 become cleaner once such a boundary exis= ts. One doesn=E2=80=99t strictly require the other, but they definitely = complement each other. The difficulty is that PHP currently has no agree= d-upon definition of what a =E2=80=9Cmodule=E2=80=9D or =E2=80=9Cpackage= =E2=80=9D *is*: =E2=80=A2 Composer root namespaces? =E2=80=A2 Physical directories? =E2=80=A2 Compilation units? =E2=80=A2 Attributes? =E2=80=A2 Something else entirely? Because of that, there=E2=80=99s no existing boundary we can safely buil= d on without first settling that much larger question. That=E2=80=99s wh= y this RFC deliberately stays within a boundary the language *already* d= efines: the lexical namespace. It doesn=E2=80=99t try to define packages= or introduce any new scoping model. It also doesn=E2=80=99t prevent a f= uture RFC from doing so. If the community reaches consensus on a formal module/package boundary l= ater, namespace-level visibility can coexist with it or even be folded i= nto it. Nothing in this RFC blocks that path. What this RFC does is provide a useful, enforceable intermediate step th= at doesn=E2=80=99t require the community to solve =E2=80=9Cpackages=E2=80= =9D first. If we require a full module system before adding any visibili= ty improvements, we=E2=80=99re essentially saying that no incremental pr= ogress is acceptable until the hardest part of the problem is fully solv= ed. That=E2=80=99s historically not how PHP evolves. To keep this discussion focused: If someone has concerns about *this RFC=E2=80=99s* semantics, performanc= e, syntax, implementation, error messaging, interaction with inheritance= /traits, or BC impact =E2=80=94 that=E2=80=99s absolutely fair and I=E2=80= =99d like to address them: But I=E2=80=99d like to avoid turning this into a thread about defining = a package/specification/module system. That=E2=80=99s a valid discussion= , and I=E2=80=99d happily participate in another thread, but it=E2=80=99= 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=E2=80=99s 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 v= isibility, where the keyword controls the caller set and parentheses res= trict the operation (get/set). That=E2=80=99s why `private(namespace)(se= t)` follows the same rule: the base visibility is still "private", and t= he parentheses narrows who may call it. If we introduced a standalone keyword like `internal` or `nsviz`, we=E2=80= =99d effectively be adding a new visibility class, not a refinement of `= private` and would bring its own semantics, collision issues, and intera= ctions with any future module work. This RFC aims to minimise surface ar= ea, which is why it treats namespace visibility as a refinement. That said, if the consensus emerges around a new keyword, that=E2=80=99s= 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-s= ide in one namespace, especially in domain-driven or layered architectur= es where namespaces are the boundaries. Today, teams either make them pu= blic, wrap them in a service class, use `@internal`, or wire them togeth= er via reflection or debug_backtrace. All of those come with tradeoffs. Exact-match namespace visibility offer= s a simple enforceable boundary without designing a whole package system= or assuming anything about code hierarchy. It=E2=80=99s not the most ex= pressive possible rule, but it=E2=80=99s useful and predictable. If the community prefers prefix-based visibility or package-level visibi= lity, that could be explored in a follow-up RFC. I=E2=80=99m not opposed= to more expressive forms; I=E2=80=99m just not binding this RFC to a pa= ckage model the language hasn=E2=80=99t defined yet. And lastly, isn=E2=80=99t namespace visibility easy to bypass? Yes =E2=80=94 but so is private and protected. No PHP visibility is inte= nded as a security boundary. This is a developer-intent boundary: encaps= ulation, 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, =E2=80=94 Rob --f2b76d14d7e54533b2b167edce79947f Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable
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 
>> some= thing like `private(namespace: Acme\AuthLib)`) or a 
>= > protected-namespace variant could be layered on top if the communit= y 
>> 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 l= ike, we can end up with syntax or 
> semantics that ma= kes our lives unnecessarily difficult later. As I 
> u= nderstand it, this happened to some extent with the "readonly" keyword.<= /div>

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 (readon= ly was a major PITA for aviz, and even delayed it for a release as we fi= gured 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=E2=80=99t intended to solv= e the entire space; it=E2=80=99s the smallest 
>> u= seful step that seems to fairly cleanly fit into PHP=E2=80=99s current m= odel 
>> without too much churn on the engine.
>
> I think my fundamental question is: is it actu= ally that useful? How 
> often, in practice, do people= want exact namespace matching, vs 
> something more f= lexible?

In practice, the extra-class boundary = I most often want is "my composer package."  I rarely need to prote= ct things beyond that.

I am broadly in favor of= extra-class visibility controls, whether they go through a module syste= m or something else.  Whether the current RFC is a good way of doin= g so, I am not convinced.

In particular, the sy= ntax is a hard-no.  It runs contrary to how the aviz syntax was def= ined, as others have already noted.

If you don'= t want to use `internal(set)` to save `internal` for some other use, tha= t's fine.  Come up with a different keyword. :-)  But <allo= wed scope>(<operation>) is the syntax model that aviz establish= ed, and tossing extra parens in there just confuses things for everyone.=

If it really does need to be an entirely separ= ate dimension of scoping, then I would argue it's too complex to capture= in just keywords and Rowan's attribute proposal becomes even more compe= lling.

That said, I'm not convinced it is a sep= arate 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 p= roperty 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 names= pace... 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 suppos= e, debatable.


--Larry Garfield

 Hi Larry (and everyone else f= ollowing the thread),

I think we=E2=80=99re all= aligned that PHP would benefit from a proper module or package boundary= . Many features people want =E2=80=94 including namespace visibility =E2= =80=94 become cleaner once such a boundary exists. One doesn=E2=80=99t s= trictly require the other, but they definitely complement each other. Th= e difficulty is that PHP currently has no agreed-upon definition of what= a =E2=80=9Cmodule=E2=80=9D or =E2=80=9Cpackage=E2=80=9D is:
<= /div>
  • Composer root namespaces?
  • Physi= cal directories?
  • Compilation units?
  • Attributes?
  • Something else entirely?
Because of that, there=E2=80=99s no existing bound= ary we can safely build on without first settling that much larger quest= ion. That=E2=80=99s why this RFC deliberately stays within a boundary th= e language already defines: the lexical namespace. It doesn=E2=80= =99t try to define packages or introduce any new scoping model. It also = doesn=E2=80=99t prevent a future RFC from doing so.

=
If the community reaches consensus on a formal module/package bound= ary later, namespace-level visibility can coexist with it or even be fol= ded into it. Nothing in this RFC blocks that path.

<= div>What this RFC does is provide a useful, enforceable intermediate ste= p that doesn=E2=80=99t require the community to solve =E2=80=9Cpackages=E2= =80=9D first. If we require a full module system before adding any visib= ility improvements, we=E2=80=99re essentially saying that no incremental= progress is acceptable until the hardest part of the problem is fully s= olved. That=E2=80=99s historically not how PHP evolves.

To keep this discussion focused:

If so= meone has concerns about this RFC=E2=80=99s semantics, performanc= e, syntax, implementation, error messaging, interaction with inheritance= /traits, or BC impact =E2=80=94 that=E2=80=99s absolutely fair and I=E2=80= =99d like to address them:

But I=E2=80=99d like= to avoid turning this into a thread about defining a package/specificat= ion/module system. That=E2=80=99s a valid discussion, and I=E2=80=99d ha= ppily participate in another thread, but it=E2=80=99s not one this RFC i= s trying to solve.

Namespace visibility is inte= ntionally small, intentionally conservative, and intentionally compatibl= e with whatever direction modules eventually take. It=E2=80=99s the smal= lest useful step the language can take today, without blocking future wo= rk, while still being useful.

----
Now, to reply to your specific points about this RFC:

First, syntax vs. AViz.

Aviz establishes vi= sibility(operation) as the pattern for asymmetric visibility, whe= re the keyword controls the caller set and parentheses restrict the oper= ation (get/set). That=E2=80=99s why private(namespace)(set) follows the same rule: th= e base visibility is still "private", and the parentheses narrows who ma= y call it.

If we introduced a standalone keywor= d like internal or nsviz, = we=E2=80=99d effectively be adding a new visibility class, not a refinem= ent of private and would bring its own semantics, collision issues, and interact= ions 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=E2=80=99s something I can adjust. The important behaviour is the = caller rule, not the exact token spelling.

Seco= nd, is exact-match useful enough?

Yes, there ar= e plenty of codebases where internal helpers live side-by-side in one na= mespace, especially in domain-driven or layered architectures where name= spaces are the boundaries. Today, teams either make them public, wrap th= em in a service class, use @internal, or wire them together via reflection or debug_b= acktrace.

All of those come with tradeoffs. Exa= ct-match namespace visibility offers a simple enforceable boundary witho= ut designing a whole package system or assuming anything about code hier= archy. It=E2=80=99s not the most expressive possible rule, but it=E2=80=99= s useful and predictable.

If the community pref= ers prefix-based visibility or package-level visibility, that could be e= xplored in a follow-up RFC. I=E2=80=99m not opposed to more expressive f= orms; I=E2=80=99m just not binding this RFC to a package model the langu= age hasn=E2=80=99t defined yet.

And lastly, isn= =E2=80=99t namespace visibility easy to bypass?

Yes =E2=80=94 but so is private and protected. No PHP visibility is int= ended as a security boundary. This is a developer-intent boundary: encap= sulation, static analysis, and making accidental misuse harder.

If a future module/package system introduces strong= er enforcement, this RFC can layer underneath it without a conflict.

Sincerely,

=E2=80=94 Rob
--f2b76d14d7e54533b2b167edce79947f--