Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126812 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 qa.php.net (Postfix) with ESMTPS id 31ED61A00BC for ; Mon, 17 Mar 2025 18:59:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1742237791; bh=OkPAQRqKD3sqG3FyUqPygbzPzbO5JxCn11G1SM29yWA=; h=Date:From:To:Cc:In-Reply-To:References:Subject:From; b=A6PN5Mkabo0+mWSkai+WBTJGFycZjvzqTfa4NKUmRKtA7T+q6xJxPTe2aOUS25Zvw xO9t39pj0TQq6Z+H6Z1Pdd+6TPrVTQ30CpCPOlXhbD+eXxDFLDzE8IcnCUkYrJOlBp EYllvRwFiRN3oIwg7pFDyD2KuvoqI0pU7tZPZbpM2tv0+/LO8KRvFVFnnlMsr1ABig HA9GiS5zzx5qltgGlpB2bqbecDIR14Lb4omsv2T+od9sAN3emXPgAyy8yEvQ5Ofho3 RmaTbgwsh6x2xa2PbyyREQZmKdRc/LC0dJhzGHj7cmh4STBsmPyGiTAHF97xSEUsoc /a7UDWxS4V7Dg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id D89AE180340 for ; Mon, 17 Mar 2025 18:56:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,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.0 X-Spam-Virus: No X-Envelope-From: Received: from fhigh-a8-smtp.messagingengine.com (fhigh-a8-smtp.messagingengine.com [103.168.172.159]) (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, 17 Mar 2025 18:56:29 +0000 (UTC) Received: from phl-compute-11.internal (phl-compute-11.phl.internal [10.202.2.51]) by mailfhigh.phl.internal (Postfix) with ESMTP id C68DC11401BD; Mon, 17 Mar 2025 14:59:00 -0400 (EDT) Received: from phl-imap-09 ([10.202.2.99]) by phl-compute-11.internal (MEProxy); Mon, 17 Mar 2025 14:59:00 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bottled.codes; h=cc: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=fm2; t=1742237940; x= 1742324340; bh=kIwmkMkVuMIBvFKF16tiJCoYTHoD1zyxbx3ZWOKxd+I=; b=J j6HUxMmOAiFqZlQvmCVgzblJBGX6zPGFuv3VPsYzK0SZNeMoy3TRge+5HuU6Q6VB qrYMmr8guouQvNG5l13Nh0XQPoKo91PZqjPWQhN+tmswuIE9SoZAAQBAJcSRgfiL nwZAJLH+6QCVRvKFbWjCo+8N7W+vkjUBd+aR034/FhhUOLGQGMwzBJPA96xXWkUy L6vgtjp3soPYn6MmOLj0IOFMWZ3eGFpaObdlyzCkGoQ7TK+lZGkf4+/kzlg3039/ HtcTVVI6kcLOwgYmiP3fDG9/H0KcoMLxL1vsw7pthgdsI2UmNrhNrsVhXX0RzCa5 tLIDF+K38mOh//6Ba9E8w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc: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=fm1; t= 1742237940; x=1742324340; bh=kIwmkMkVuMIBvFKF16tiJCoYTHoD1zyxbx3 ZWOKxd+I=; b=sm103Stzc6xlKdGYi/xGafYuEYdHIcUGFqTl6mMvhVxr3uom5mP bjyFhtxlevlhv8z/j636GqJ3C7XRpVJPGGYOM56Wx9/dW4iXhtrD6smFSTPR/jgH C7aeamky74tlzsPoS5wxRusn2+O0ZoV4feh0ZlpeuxNwSYfE12m8iwjNf0g8Iory Z0bOFxMIDL0ZncFs99PuWp/WB56cMQIaTDsFHID57UQgSPbUhAo8f9Ehl5JZv1sS qSk1HEMyM/7u5JB8m6q+go2bE3YSWHfXzXBXHNaEibM4nebfgGCvIJ5D4CDS0TcA Z9qOyy7+hA8w3aPCMfZ5XXmwlPBLCB4NMFg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgddugedtfedtucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggv pdfurfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpih gvnhhtshculddquddttddmnecujfgurhepofggfffhvfevkfgjfhfutgesrgdtreerredt jeenucfhrhhomhepfdftohgsucfnrghnuggvrhhsfdcuoehrohgssegsohhtthhlvggurd gtohguvghsqeenucggtffrrghtthgvrhhnpeeiueethedvvdefjefhgfeiheelheehtdfh feekjefflefgvedvkeduteejjedttdenucevlhhushhtvghrufhiiigvpedtnecurfgrrh grmhepmhgrihhlfhhrohhmpehrohgssegsohhtthhlvggurdgtohguvghspdhnsggprhgt phhtthhopeefpdhmohguvgepshhmthhpohhuthdprhgtphhtthhopehfvghnnhhitghloh hgsehgmhgrihhlrdgtohhmpdhrtghpthhtohepsghosgifvghileeshhhothhmrghilhdr tghomhdprhgtphhtthhopehinhhtvghrnhgrlhhssehlihhsthhsrdhphhhprdhnvght X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 6F07E780068; Mon, 17 Mar 2025 14:59:00 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 Date: Mon, 17 Mar 2025 19:58:39 +0100 To: "Bob Weinand" , "fennic log" Cc: internals@lists.php.net Message-ID: <782d76d9-711a-4cee-ae0e-fe0d69973f53@app.fastmail.com> In-Reply-To: References: <3e4ba7ea-a154-452d-abfc-05ef1322fade@app.fastmail.com> Subject: Re: [PHP-DEV] RFC: short and inner classes Content-Type: multipart/alternative; boundary=301cea8b1ff646038d13b9a68efc01d5 From: rob@bottled.codes ("Rob Landers") --301cea8b1ff646038d13b9a68efc01d5 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Mon, Mar 17, 2025, at 19:05, Bob Weinand wrote: > Hey Rob, >=20 > On 17.3.2025 17:53:26, Rob Landers wrote: >> On Mon, Mar 17, 2025, at 16:30, fennic log wrote: >>> 2. As with any syntax change and new operator there needs to be very= careful consideration, do we need a new operation, or could `::` if the= parent is static or `->` if the class is initialized? >>=20 >> There's quite a long thread already about this very topic. That being= said, the inner class has no bearing on whether the outer class is inst= antiated or not. Originally, I used `::` as the separator, but it seems = there are some good arguments for `\`, so we will see. > I have not grasped any single argument in favour of \, except "other l= anguages are doing it too", "existing tooling splitting on backslash wou= ld continue to work" and "we could use the existing use statement as is". >=20 >=20 > The problems are numerous though: > 1. Unlike other languages (e.g. C# and java), namespaces and classes m= ay share a name in PHP. E.g. class "Y" in a namespace "X" and class "X" = may not exist both. In PHP that's allowed. Inner classes compete with na= mespaced classes for their fully qualified name. > 2. Autoloading will have to become aware of inner classes. > 3. Autoloading will have to do a non-cacheable check for existence on = the inner class, before iteratively testing whether any parent has a res= pective .php file. Currently autoloading takes a class name, transforms = it to a single canonical path, and includes it. Always succeeding. > 4. Humans, navigating to a path, will not be able to navigate to a fil= e directly but have to search for it. > 5. Tooling splitting on backslash might assume the 1:1 mapping to the = filesystem and break. It's really not a catch all. Some things may be br= oken and some not, but all need to be probably revisited anyway. > 6. It makes accessing via parent, self or static weird. These keywords= have always been followed by a double colon. (Even if this particular R= FC does not end up adding them) And it will conflict with a namespace na= med "parent" for example. > 7. At least right now, every backslash identified symbol is trivially = universally public. With \ as an inner class separator, this would no lo= nger be the case. Maybe that will eventually change, but today this can = be relied upon. >=20 > Also, just because other languages are doing a mistake, it does not me= an we have to repeat it. They are generally doing it because their ident= ifier separator is universal and it's consistent. It does not mean that = it's without its own problems. >=20 >=20 > Using the double colon is a very minor BC break (accessing a class by = a class constant value?! That's also quite inconsistent that it works at= all, as you can't do that with normal constants, only class constants.). > Using another sigil would also be possible (like :>). But for the back= slash I only see drawbacks. >=20 > Also, nothing precludes us from allowing "use Foo\Bar::Inner;". >=20 >=20 >=20 >>> 3. The idea that extending the parent class doesnt no inherit the ch= ild classes doesnt make sense to me.=20 >>> As then if you extend a parent class and call a function of that cla= ss which could rely on the existence of an inner class, I can see a lot = of headaches caused by this exact scenario. >>> As a developer, if I extend a class, I expect the entire dependance = of that class to be inherited, otherwise the extending class won't work.=20 >>=20 >> I'm not sure what you mean. When you inherit a class, you do not nece= ssarily inherit everything from its superclass. You are free to override= it however you want. Since we are defining "types" in the sense of PHP,= we cannot merely inherit a "type", otherwise we would cause all kinds o= f issues with LSP. This is specifically why inheritance works the way it= does in this RFC and why `static::` is forbidden. > I don't understand the problem here. >=20 >=20 > for each nested class in parent class: > class_alias(substitute parent class with child class in class name= , class name) >=20 > Very simple. There's no magic needed, it can be simply class aliases. = This will also make static, self and parent trivially work. >=20 PHP doesn't go out of its way to prevent the developer from violating LS= P -- but where it can, it does. If a type were inherited, then the subcl= asses wouldn't be able to guarantee that an inner/nested class implement= ed the parent inner/nested class. Or, if it did, it would require that a= ll subclasses using a class of the same name MUST inherit from the paren= t class as well. This is non-trivial to implement as the parent class may or may not have= been compiled yet when we are compiling the subclass. So, we have no id= ea what the parent class actually looks like until runtime. Further, it = is much simpler to reason about each class as a distinct type vs. maybe = inheriting a type from a supertype. Thus, if you want to inherit from the super-class's inner classes, you c= an, but this RFC won't force you to do so. In my mind, this is the bigge= st argument for a `\`, because the enclosing class acts more like a name= space than a type, from the perspective of the inner class. If we were to embrace `\`, then it could be argued that a namespace is t= echnically a class in itself, (but a partial class, to borrow from C# te= rminology) and every class in a namespace is essentially just a public c= lass in that super-class/namespace. Nobody has argued that perspective, but I believe it may be interesting = (and would lay a foundation for namespace private/public class behavior/= visibility). That being said, it truly does cause issues with autoloadin= g -- at least, PSR-4 autoloading -- and I'm not sure whether we should s= olve that problem here; however, it is something to be cognizant of, for= sure. There are other types of autoloading supported by tools, such as = composer, that do not have any issues with using `\` as a separator. > On 15.3.2025 00:37:08, Rob Landers wrote: >=20 >=20 >=20 >> Classes don't actually know their inner classes -- they aren't like p= roperties. In essence, an inner class is just a regular class with a fun= ny name and access to scopes it wouldn't normally have access to. We cou= ld probably add `getOuterClass(): string` if that is useful. It is possi= ble to keep track of a class's inner classes, but then that introduces a= paradox chicken/egg type problem during construction, which may or may = not be a problem. >>=20 >=20 >=20 > I don't see the chicken-and-egg problem here. You can simply collect a= ll the inner class names at compilation. You don't even need to actually= store the zend_class_entry - just collect the names and fetch from the = class table at runtime (and ignore missing ones, e.g. if there was an er= ror during linking). >=20 =F0=9F=99=83sometimes the obvious solutions are the best solutions. =E2=80=94 Rob --301cea8b1ff646038d13b9a68efc01d5 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable


On Mon, Mar 17, 2025, at 19:05, Bob Weinand wrote:
=

Hey Rob,

=
On 17.3.2025 17:53:26, Rob Landers=0A = wrote:
On Mon, Mar 17, 2025, at = 16:30, fennic log wrote:
2. As with any syntax change and new operator the= re=0A needs to be very careful consideration, do we need a = new=0A operation, or could `::` if the parent is static or=0A= `->` if the class is initialized?
=

There's quite a long thread already abo= ut this very topic.=0A That being said, the inner class has no be= aring on whether the=0A outer class is instantiated or not. Origi= nally, I used `::` as=0A the separator, but it seems there are so= me good arguments for=0A `\`, so we will see.

I have not grasped any single argument in favour of \, except=0A = "other languages are doing it too", "existing tooling splitting on=0A= backslash would continue to work" and "we could use the existing=0A= use statement as is".

The problems are numerous= though:
1. Unlike other languages (e.g. C# and java), na= mespaces and=0A classes may share a name in PHP. E.g. class "Y" in = a namespace "X"=0A and class "X" may not exist both. In PHP that's = allowed. Inner=0A classes compete with namespaced classes for their= fully qualified=0A name.
2. Autoloading will have t= o become aware of inner classes.
3. Autoloading will have= to do a non-cacheable check for existence=0A on the inner class, b= efore iteratively testing whether any parent=0A has a respective .p= hp file. Currently autoloading takes a class=0A name, transforms it= to a single canonical path, and includes it.=0A Always succeeding.=
4. Humans, navigating to a path, will not be able to nav= igate to a=0A file directly but have to search for it.
5. Tooling splitting on backslash might assume the 1:1 mapping to=0A = the filesystem and break. It's really not a catch all. Some things=0A= may be broken and some not, but all need to be probably revisited=0A= anyway.
6. It makes accessing via parent, self or s= tatic weird. These=0A keywords have always been followed by a doubl= e colon. (Even if=0A this particular RFC does not end up adding the= m) And it will=0A conflict with a namespace named "parent" for exam= ple.
7. At least right now, every backslash identified sy= mbol is=0A trivially universally public. With \ as an inner class s= eparator,=0A this would no longer be the case. Maybe that will even= tually=0A change, but today this can be relied upon.

Also, just because other languages are doing a mistake, it does=0A = not mean we have to repeat it. They are generally doing it because=0A= their identifier separator is universal and it's consistent. It=0A= does not mean that it's without its own problems.

Using the double colon is a very minor BC break (accessing a=0A = class by a class constant value?! That's also quite inconsistent=0A = that it works at all, as you can't do that with normal constants,=0A = only class constants.).
Using another sigil would also= be possible (like :>). But for=0A the backslash I only see draw= backs.

Also, nothing precludes us from allowing "use = Foo\Bar::Inner;".


3. The idea that extending= the parent class doesnt no=0A inherit the child classes do= esnt make sense to me. 
As then if you extend a = parent class and call a=0A function of that class which cou= ld rely on the existence=0A of an inner class, I can see a = lot of headaches caused by=0A this exact scenario.
As a developer, if I extend a class, I expect the=0A = entire dependance of that class to be inherited, otherwise=0A = the extending class won't work. 

I'm not sure what you mean. When you inherit a cl= ass, you do=0A not necessarily inherit everything from its superc= lass. You are=0A free to override it however you want. Since we a= re defining=0A "types" in the sense of PHP, we cannot merely inhe= rit a "type",=0A otherwise we would cause all kinds of issues wit= h LSP. This is=0A specifically why inheritance works the way it d= oes in this RFC=0A and why `static::` is forbidden.

I don't understand the problem here.

for = each nested class in parent class:
    cla= ss_alias(substitute parent class with child class in class=0A name,= class name)

Very simple. There's no magic needed, it= can be simply class=0A aliases. This will also make static, self a= nd parent trivially=0A work.


PHP doesn't go out of its way to prevent the developer from violating = LSP -- but where it can, it does. If a type were inherited, then the sub= classes wouldn't be able to guarantee that an inner/nested class impleme= nted the parent inner/nested class. Or, if it did, it would require that= all subclasses using a class of the same name MUST inherit from the par= ent class as well.

This is non-trivial to i= mplement as the parent class may or may not have been compiled yet when = we are compiling the subclass. So, we have no idea what the parent class= actually looks like until runtime. Further, it is much simpler to reaso= n about each class as a distinct type vs. maybe inheriting a type from a= supertype.

Thus, if you want to inherit fr= om the super-class's inner classes, you can, but this RFC won't force yo= u to do so. In my mind, this is the biggest argument for a `\`, because = the enclosing class acts more like a namespace than a type, from the per= spective of the inner class.

If we were to = embrace `\`, then it could be argued that a namespace is technically a c= lass in itself, (but a partial class, to borrow from C# terminology) and= every class in a namespace is essentially just a public class in that s= uper-class/namespace.

Nobody has argued tha= t perspective, but I believe it may be interesting (and would lay a foun= dation for namespace private/public class behavior/visibility). That bei= ng said, it truly does cause issues with autoloading -- at least, PSR-4 = autoloading -- and I'm not sure whether we should solve that problem her= e; however, it is something to be cognizant of, for sure. There are othe= r types of autoloading supported by tools, such as composer, that do not= have any issues with using `\` as a separator.

On 15.3.2025 00:37:08, Rob= Landers wrote:


Clas= ses don't actually know their inner classes -- they=0A aren't= like properties. In essence, an inner class is just a=0A reg= ular class with a funny name and access to scopes it=0A would= n't normally have access to. We could probably add=0A `getOut= erClass(): string` if that is useful. It is possible=0A to ke= ep track of a class's inner classes, but then that=0A introdu= ces a paradox chicken/egg type problem during=0A construction= , which may or may not be a problem.


I don't see the chicken-and-egg problem here. You can simply=0A = collect all the inner class names at compilation. You don't even=0A = need to actually store the zend_class_entry - just collect the=0A = names and fetch from the class table at runtime (and ignore=0A mi= ssing ones, e.g. if there was an error during linking).


=F0=9F=99=83sometimes the obvious solutions are = the best solutions.

=E2=80=94= Rob
--301cea8b1ff646038d13b9a68efc01d5--