Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129191 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 8C4B71A00BC for ; Mon, 10 Nov 2025 19:19:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1762802401; bh=UgA/Iq/B0Mqkau1ewb0wXZKAEfWCcbo7vFhw+gd7mEk=; h=Date:From:To:In-Reply-To:References:Subject:From; b=UhkdjpYK2NqEogaH+8shhuKlgj2g0zdwMIxyF2j0wPHYOz8DdsPTnJSlIK1Ro5ig1 B5Hdm0uh7kj2psNZijxumPixocZbbCoxvtH7rrIu7jyIXtoMGKmFQiOPRQVmBcx3Sd K04i5dUBDtL2Ni+kWJ70OxZ2qy/SpRo9LAFynSGGF1bfjAuv1pIZEdR/99ZN5FKwBt PSXKmUxdLQCeJH9ktM4S7PBtMrxV56fBcd37Z3V3JY1uXzuLGuYD0H3FAjCZcCkBhs JR6hKVOQPRlx71x3FeKnOD8oHhv6/MqiDmhG7iAHxjwYv4crBBMI3PMu6dUvQgWVL5 NpoeRUVzRbPfQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 8744D1801EB for ; Mon, 10 Nov 2025 19:19:59 +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.1 required=5.0 tests=BAYES_50,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-b7-smtp.messagingengine.com (fhigh-b7-smtp.messagingengine.com [202.12.124.158]) (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 ; Mon, 10 Nov 2025 19:19:59 +0000 (UTC) Received: from phl-compute-12.internal (phl-compute-12.internal [10.202.2.52]) by mailfhigh.stl.internal (Postfix) with ESMTP id 5D6287A0199; Mon, 10 Nov 2025 14:19:53 -0500 (EST) Received: from phl-imap-05 ([10.202.2.95]) by phl-compute-12.internal (MEProxy); Mon, 10 Nov 2025 14:19:53 -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=1762802393; x=1762888793; bh=Gj6X0jrGI0 LvUvuEJENVj49oZoUTFR4KPeFf5lEM8S4=; b=ftWpfjR6nOGCRBoZVM42YTZ3qL yijGwe7xTeHu1xcLcyOZNxSRTmyTwk3MyGttykxNdWks09bAQ5D2Y12Lb45RkOrt 14qjxrLkKvnCW8X6UvcTtgE0qsC5fFIN0lWVB+urSoRbGWvU17N9eXsYQWZ87/Av XNvEcUbYrFdAsP43MWGkG4KWqObF7kj4dsu2G0GvCXkGmlQXoYNdWtvV3vcKGQY5 bf2frKdoEm/71M0FiqqXVpprTROheROjB/fagUbd/MaU0qK8C7RTytR4DrJt2BVo fEZuAKbd86nrH2j6tOPBd6iGcWVPErfjydaZTa3/ivKZgGyIdPWffnjKO1gw== 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= 1762802393; x=1762888793; bh=Gj6X0jrGI0LvUvuEJENVj49oZoUTFR4KPeF f5lEM8S4=; b=hZz/zXDcjQQrryT66m9Ydyf43L0yKquLqmYDK1Xde/xfIqVL8WH C9UwtxkbqI44ljt7U6Cm3cq5535oAZWE/yD0ZjRtvBvOj4rP39MnXXm1x75wBhmg VZj317qUgaCrm3fSPkX8haBBmO2Gri7/SD8fzOqS91eKJvxaluVALWTxBpK/4PjU SS7Od5aCJJrdopNk3vtFhGK8VF01mTmJ9JOmPr7pN7ksRfNJh0mgjMGKzI85+bin DuHickwSsb0vDRVRuZKuecgEcytJTvablKojHjn1qnntKpe+0yA9z7lEuSXCbFxh g4Btk/ySXjG5QUP+WhtnChNLiRceAUqvDcA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdduleeludefucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucenucfjughrpefoggffhffvkfgjfhfutgesrgdtreerre dtjeenucfhrhhomhepfdftohgsucfnrghnuggvrhhsfdcuoehrohgssegsohhtthhlvggu rdgtohguvghsqeenucggtffrrghtthgvrhhnpefgtdegkedvveduffeigfelteehheejud eigfeludefveeiffefgffgleelvedtfeenucffohhmrghinhepphhhphdrnhgvthdptghh rghtghhpthdrtghomhdpghhithhhuhgsrdgtohhmnecuvehluhhsthgvrhfuihiivgeptd enucfrrghrrghmpehmrghilhhfrhhomheprhhosgessghothhtlhgvugdrtghouggvshdp nhgspghrtghpthhtohepvddpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtohepthhimh essggrshhtvghlshhtuhdrsggvpdhrtghpthhtohepihhnthgvrhhnrghlsheslhhishht shdrphhhphdrnhgvth X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 8C9191820054; Mon, 10 Nov 2025 14:19:52 -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: Mon, 10 Nov 2025 20:19:31 +0100 To: =?UTF-8?Q?Tim_D=C3=BCsterhus?= , internals@lists.php.net Message-ID: In-Reply-To: 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> <1606b9e5-62b8-446b-adac-519ac19d01c3@app.fastmail.com> Subject: Re: [PHP-DEV] RFC: Namespace-Scoped Visibility for Methods and Properties Content-Type: multipart/alternative; boundary=4f88ffd7f5354015b8b0c0a6237c54bd From: rob@bottled.codes ("Rob Landers") --4f88ffd7f5354015b8b0c0a6237c54bd Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Sun, Nov 9, 2025, at 22:32, Rob Landers wrote: >=20 >=20 > On Sun, Nov 9, 2025, at 21:51, Tim D=C3=BCsterhus wrote: >> For this one I am however not sure if it ticks the =E2=80=9Ccomposes = well=E2=80=9D=20 >> checkbox - that greatly depends on the syntax choice and how modules=20 >> will look like if/when they eventually arrive. >=20 > I understand the concern. Composability matters a lot, especially for = features that touch visibility. My goal with this RFC is to take a bound= ary PHP already has (the lexical namespace) and make it enforceable with= out needing to answer the bigger "what=E2=80=99s a module/package?" ques= tion first. >=20 > Right now, different people in the ecosystem use namespaces in differe= nt ways: some treat them as hierarchical, some as flat prefixes, some ma= p them to directory trees, some don=E2=80=99t. Trying to define prefix r= ules, upward/downward access, or package-like confinement gets us right = back into the same conversation we=E2=80=99ve been stuck on. That=E2=80=99= s why this RFC deliberately picks the simplest rule PHP could enforce to= day: exact namespace equality. >=20 > If a future RFC defines modules/packages, namespace-visibility can eit= her: > - fold into that boundary, > - be superseded by it, or > - be used inside it (e.g. `internal` for modules, `private(namespace)`= within module internals). >=20 > Nothing in this RFC makes that harder. >=20 >>=20 >> Your RFC appears to use the old template for the =E2=80=9CRFC Impact=E2= =80=9D section=20 >> which doesn't yet include the =E2=80=9CEcosystem Impact=E2=80=9D subs= ection, but=20 >> indicating that =E2=80=9Csignificant OPcache changes=E2=80=9D are req= uired makes me=20 >> wonder about the cost-benefit ratio. >=20 > Thanks! I=E2=80=99ll look at the new template and call out ecosystem i= mpact (this was originally written back in April/May?). On the OPcache p= oint: "significant" is probably overstating it. The change is limited to= persisting one additional interned string on zend_op_array and refcount= ing it correctly. The cost is paid at compile time, not at call time, so= runtime performance impact should be negligible. I=E2=80=99ll reword th= is to be more precise. >=20 >>=20 >> > Aviz establishes `visibility(operation)` as the pattern for asymmet= ric visibility, where the keyword controls the caller set and parenthese= s restrict the operation (get/set). That=E2=80=99s why `private(namespac= e)(set)` follows the same rule: the base visibility is still "private", = and the parentheses narrows who may call it. >> >=20 >> > If we introduced a standalone keyword like `internal` or `nsviz`, w= e=E2=80=99d effectively be adding a new visibility class, not a refineme= nt of `private` and would bring its own semantics, collision issues, and= interactions with any future module work. This RFC aims to minimise sur= face area, which is why it treats namespace visibility as a refinement. >>=20 >> As noted in my reply in the thread from Faizan, calling this a=20 >> refinement of `private` is not really accurate / doesn't work in prac= tice. >=20 > 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=E2=80=99ll update the RFC text to ref= lect that and disallow weird combinations (to be more clearly defined in= the RFC). >=20 >>=20 >> > If the community prefers prefix-based visibility or package-level v= isibility, that could be explored in a follow-up RFC. I=E2=80=99m not op= posed to more expressive forms; I=E2=80=99m just not binding this RFC to= a package model the language hasn=E2=80=99t defined yet. >>=20 >> To do so, the syntax would need to account for that. I have not yet s= een=20 >> a good proposal for that that doesn't end up as =E2=80=9Csymbol soup=E2= =80=9D that=20 >> doesn't really fit the existing language syntactically. >=20 > My earliest version simply used `namespace`: >=20 > class P { > namespace function x() {}=20 > } >=20 > It might make sense to return to that syntax if people don=E2=80=99t l= ike the current syntax. I don=E2=80=99t have a strong attachment to the = exact spelling, what matters is the semantics. >=20 > =E2=80=94 Rob I=E2=80=99ve updated the RFC and the implementation with some significan= t clarifications and corrections: =E2=80=A2 *Inheritance semantics now follow `protected` rather than `pr= ivate`* `private(namespace)` members are inherited and must follow normal signat= ure-compatibility rules. Visibility is enforced based on the declaring namespace rather than the = inheritance hierarchy. =E2=80=A2 *Incompatible redeclarations are now clearly defined* Transitions between `protected` and `private(namespace)` are disallowed = in either direction. This avoids unsound cases where substitutability would be broken for cal= lers in the declaring namespace. =E2=80=A2 *Asymmetric visibility rules clarified* `protected` and `private(namespace)` operate on different axes (inherita= nce vs namespace), so mixed AViz like `protected private(namespace)(set)` is now a compile-time error. =E2=80=A2 *Expanded examples and error messages* The RFC now includes clearer examples of the invalid cases, inheritance = rules, and AViz combinations. =E2=80=A2 *Syntax moved to an explicit open issue* Because the semantics now line up with `protected` rather than `private`= , the spelling `private(namespace)` may not be ideal. I=E2=80=99ve listed this in the =E2=80=9COpen Issues=E2=80=9D section an= d I'll include some previously considered alternatives that preserve the= semantics here: =E2=80=A2 `namespace function x() {}` =E2=80=A2 `local function x() {}` =E2=80=A2 `private:ns function x() {}` =E2=80=A2 `protected:ns function x() {}` My personal preference is toward the simpler forms (`namespace` or `loca= l`), but I=E2=80=99d like to collect feedback before changing the RFC te= xt. Updated RFC: https://wiki.php.net/rfc/namespace_visibility Implementation: https://github.com/php/php-src/pull/20421 Thanks to everyone who pointed out the inheritance edge cases; those sur= faced issues that needed to be addressed. Further feedback is welcome. =E2=80=94 Rob --4f88ffd7f5354015b8b0c0a6237c54bd Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable


On Sun, Nov 9, 2025, at 22:32, Rob Landers wrote:


=
On Sun, Nov 9, 2025, at 21:51, Tim D=C3=BCsterhus wrote:
For this one I a= m however not sure if it ticks the =E2=80=9Ccomposes well=E2=80=9D =
checkbox - that greatly depends on the syntax choice and how = modules 
will look like if/when they eventually arrive.

I understand the concern. Composabi= lity matters a lot, especially for features that touch visibility. My go= al with this RFC is to take a boundary PHP already has (the lexical name= space) and make it enforceable without needing to answer the bigger "wha= t=E2=80=99s 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=E2=80=99t. Trying to define prefix rul= es, upward/downward access, or package-like confinement gets us right ba= ck into the same conversation we=E2=80=99ve been stuck on. That=E2=80=99= s why this RFC deliberately picks the simplest rule PHP could enforce to= day: exact namespace equality.

If a future RFC = defines modules/packages, namespace-visibility can either:
- f= old into that boundary,
- be superseded by it, or
- = be used inside it (e.g. i= nternal for modules, private(namespace) within module internals).

Nothing in this RFC makes that harder.


Your RF= C appears to use the old template for the =E2=80=9CRFC Impact=E2=80=9D s= ection 
which doesn't yet include the =E2=80=9CEcosystem = Impact=E2=80=9D subsection, but 
indicating that =E2=80=9C= significant OPcache changes=E2=80=9D are required makes me 
wonder about the cost-benefit ratio.

Thanks! I=E2=80=99ll look at the new template and call out ecosyst= em impact (this was originally written back in April/May?). On the OPcac= he point: "significant" is probably overstating it. The change is limite= d to persisting one additional interned string on zend_op_array and refc= ounting it correctly. The cost is paid at compile time, not at call time= , so runtime performance impact should be negligible. I=E2=80=99ll rewor= d this to be more precise.


> Aviz establishes `visi= bility(operation)` as the pattern for asymmetric visibility, where the k= eyword controls the caller set and parentheses restrict the operation (g= et/set). That=E2=80=99s why `private(namespace)(set)` follows the same r= ule: 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=E2=80=99d effectively= be adding a new visibility class, not a refinement of `private` and wou= ld 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 i= n practice.

Agreed. After the disc= ussion 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=E2=80=99l= l update the RFC text to reflect that and disallow weird combinations (t= o be more clearly defined in the RFC).


> If the com= munity prefers prefix-based visibility or package-level visibility, that= could be explored in a follow-up RFC. I=E2=80=99m not opposed to more e= xpressive forms; I=E2=80=99m just not binding this RFC to a package mode= l the language hasn=E2=80=99t defined yet.

To d= o so, the syntax would need to account for that. I have not yet seen&nbs= p;
a good proposal for that that doesn't end up as =E2=80=9Csy= mbol soup=E2=80=9D that 
doesn't really fit the existing = language syntactically.

My earlies= t version simply used nam= espace:

class P {=0A  namespace function x() {}=20=0A}

It might make sense to return to that syntax if people don=E2=80= =99t like the current syntax. I don=E2=80=99t have a strong attachment t= o the exact spelling, what matters is the semantics.

=E2=80=94 Rob

I=E2=80=99ve updated the RFC and the implementation with some s= ignificant clarifications and corrections:
  • Inhe= ritance semantics now follow protected rather than private
    private(namespace) members are inherited and must follow no= rmal signature-compatibility rules.
    Visibility is enforced based on = the declaring namespace rather than the inheritance hierarchy.
    =
  • Incompatible redeclarations are now clearly defined=
    Transitions between = protected and priv= ate(namespace) are disallowed in either direction.
    This avoid= s unsound cases where substitutability would be broken for callers in th= e declaring namespace.
  • Asymmetric visibility r= ules clarified
    pr= otected and privat= e(namespace) operate on different axes (inheritance vs namespace)= , so mixed AViz like
    = protected private(namespace)(set) is now a compile-time error.
  • Expanded examples and error messages
    The= RFC now includes clearer examples of the invalid cases, inheritance rul= es, and AViz combinations.
  • Syntax moved to an = explicit open issue
    Because the semantics now line up with protected rather than <= code style=3D"border-top-width:1px;border-right-width:1px;border-bottom-= width:1px;border-left-width:1px;border-top-style:solid;border-right-styl= e:solid;border-bottom-style:solid;border-left-style:solid;border-top-col= or:rgb(204, 204, 204);border-right-color:rgb(204, 204, 204);border-botto= m-color:rgb(204, 204, 204);border-left-color:rgb(204, 204, 204);border-i= mage-source:initial;border-image-slice:initial;border-image-width:initia= l;border-image-outset:initial;border-image-repeat:initial;border-top-lef= t-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;= border-bottom-left-radius:3px;background-image:initial;background-positi= on-x:initial;background-position-y:initial;background-size:initial;backg= round-repeat:initial;background-attachment:initial;background-origin:ini= tial;background-clip:initial;background-color:rgb(246, 246, 246);font-fa= mily:menlo, consolas, monospace;font-size:90%;padding-top:1px;padding-ri= ght:3px;padding-bottom:1px;padding-left:3px;">private, the spelli= ng private(namespace) may not be ideal.
    I=E2=80=99ve listed this in the =E2=80=9COpen = Issues=E2=80=9D section and I'll include some previously considered alte= rnatives that preserve the semantics here:
    • namespace function x() {}=
    • l= ocal function x() {}
    • private:ns function x() {}
    • protected:ns f= unction x() {}
My personal pref= erence is toward the simpler forms (namespace or local), but I=E2=80=99d like to collect feedback before cha= nging the RFC text.


<= div>Implementation:
https://github.com/php/php-src/pull/20421

=
Thanks to everyone who pointed out the inheritance edge cases; thos= e surfaced issues that needed to be addressed. Further feedback is welco= me.

=E2=80=94 Rob
= --4f88ffd7f5354015b8b0c0a6237c54bd--