Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126807 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 91E8D1A00BC for ; Mon, 17 Mar 2025 16:53:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1742230279; bh=l538vfkzk4nkpmmLxqOR8y0Z2ssYQsofDI+4pl+YdnU=; h=Date:From:To:Cc:In-Reply-To:References:Subject:From; b=CQwyt8FLqBYw7yc1oAzREgHGg91OfDBOONHQk9NA1d5lYHihIG8GZJTnClwdCe0yk TaITVEZWr0UxTO+JANf5ZRWAzinyFVx6icdO2LSDSZkDUSII4aRBbuXvhxtV8w4xKG 9A+ztU2Rs3FjyskhK6VgVMYuIB10nxbCwvMQ5vaTE7IRjcesF/cW/3OQYv7OBgB0TJ /psfSYnLgtD0Q897IUeKScd13yspA/aXE8gQYmNcipHpAVheO6HxiF1sIOvd/zGSKi MU1T5YQPQC6ol3YUuMe17PT9HV26/QJ34wPBuovwuACCjEeH4QhAv0MUhrYsd789SI hhC26Lfy6+lyw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 5498A180083 for ; Mon, 17 Mar 2025 16:51:18 +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 fout-a5-smtp.messagingengine.com (fout-a5-smtp.messagingengine.com [103.168.172.148]) (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 16:51:18 +0000 (UTC) Received: from phl-compute-11.internal (phl-compute-11.phl.internal [10.202.2.51]) by mailfout.phl.internal (Postfix) with ESMTP id 6AD1C13833C3; Mon, 17 Mar 2025 12:53:49 -0400 (EDT) Received: from phl-imap-09 ([10.202.2.99]) by phl-compute-11.internal (MEProxy); Mon, 17 Mar 2025 12:53:49 -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=1742230429; x= 1742316829; bh=BHx+1gtUkA5O48IsLTKM3SdoTrxzlQrYXOATvKCNQi4=; b=Q U7Be+8SxLi2AX78TqdzAxm3BVnjKXmaDQbB+UOsvTjHMpFHP278g5MJUbcNDqRQQ RPU+Wa+vIFlNvJozsS9x1/C4JNxUfPUkBFKTYY5QXZ5pKhV0pTygIBtG26vKr6ck rl8syYIA/Kdm63P+tC56bSbp3QZNZbjonlCpLLdSbxP+gXV4WahMUhZs6uBYZcBR slK+R1VKO6drmXA1BkGnbtO+JVNBSILwxxNmNaTHQEqmKeE3a5o+9P7bRhReYdcr olSBaVoGCYC6BvG8ro4ek6EItOm/9FLpe1pew2lln6T0pKBdX8/gpn0Bviz6gOTB Aum68VXWqnpLUhd6od+jA== 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= 1742230429; x=1742316829; bh=BHx+1gtUkA5O48IsLTKM3SdoTrxzlQrYXOA TvKCNQi4=; b=rE3Pxtx+18L2b4cAjlJhmn86yqzzeo+1lK5QV61Ll0Nq/CAEbuC 8LUgAonM55zrue9H+sr+YmLRvTmQqVi+DxZRLi13rSVYwL1spE2VTSw6sVqrUrpx y/IFFn3f5++zE7KCzPA+uiPvmR8m1DxWq+jp7qx0hb5/yo06lW4aLMA2iL7hCqDg omHw5r+d5277JbdJ/fpWvKMhSJuQCw91h4DAsYnNie7tuFNFkL8+xekm3J+zEG3h OkM1cMktGne/HjWCCkhv3BECbu6Ybhd51ga17GxUUzqnUjAQWi7soMTsQXccg/MO s9PvLB77OJcfvq/I6pZaMaEF3P4bn3DPDUA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgddugedttdehucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggv pdfurfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpih gvnhhtshculddquddttddmnecujfgurhepofggfffhvfevkfgjfhfutgesrgdtreerredt jeenucfhrhhomhepfdftohgsucfnrghnuggvrhhsfdcuoehrohgssegsohhtthhlvggurd gtohguvghsqeenucggtffrrghtthgvrhhnpeetfeffgedvudelgeekvdeuvdfhieffgffg vddujeeikedtledtgfekveefgefgfeenucffohhmrghinhepphhhphdrnhgvthdpghhith hhuhgsrdgtohhmnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhf rhhomheprhhosgessghothhtlhgvugdrtghouggvshdpnhgspghrtghpthhtohepvddpmh houggvpehsmhhtphhouhhtpdhrtghpthhtohepfhgvnhhnihgtlhhoghesghhmrghilhdr tghomhdprhgtphhtthhopehinhhtvghrnhgrlhhssehlihhsthhsrdhphhhprdhnvght X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 1892B780068; Mon, 17 Mar 2025 12:53:48 -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 17:53:26 +0100 To: "fennic log" Cc: internals@lists.php.net Message-ID: <3e4ba7ea-a154-452d-abfc-05ef1322fade@app.fastmail.com> In-Reply-To: References: Subject: Re: [PHP-DEV] RFC: short and inner classes Content-Type: multipart/alternative; boundary=e4c60d741a194b3ea031b907cc939365 From: rob@bottled.codes ("Rob Landers") --e4c60d741a194b3ea031b907cc939365 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Mon, Mar 17, 2025, at 16:30, fennic log wrote: >=20 > On Wed, 5 Mar 2025 at 23:14, Rob Landers wrote: >> __ >> Hello PHP Internals, >>=20 >> I'd like to introduce my RFC for discussion: https://wiki.php.net/rfc= /short-and-inner-classes >>=20 >> This RFC defines a short class syntax as well as the ability to nest = classes inside another class. This introduces an unprecedented amount of= control, flexibility, and expressiveness over how objects are used and = instantiated in PHP. There is a PR (https://github.com/php/php-src/pull/= 17895) that implements this functionality -- all test failures are relat= ed to different/new/incorrect error messages being generated. However, t= he core functionality exists to take for a test ride. >>=20 >> So, what do I mean by "unprecedented amount of control"? With this ch= ange, you can declare an inner class as private or protected, preventing= its usage outside of the outer class: >>=20 >> class User { >> private class Id {} >>=20 >> public function __construct(public self::Id $id) {} >> } >>=20 >> In the above example, the class `User` is impossible to construct eve= n though it has a public constructor (except through reflection) because= User::Id is private; User::Id cannot be instantiated, used as a type hi= nt, or even via `instanceof` outside of the User class itself. This exam= ple isn't practical but demonstrates something that is nearly impossible= in previous versions of PHP, where all classes are essentially publicly= accessible from anywhere within the codebase. >>=20 >> As a number of inner classes will probably be used as DTOs, the RFC i= ntroduces a "short syntax" for declaring classes, which enhances express= iveness, even allowing the usage of traits, all in a single line: >>=20 >> // declare a readonly Point, that implements Vector2 and uses the Evo= lvable trait >> readonly class Point(public int $x, public int $y) implements Vector2= use Evolvable; >>=20 >> When combined with inner classes, it looks something like this: >>=20 >> class Pixel { >> public readonly class Point(public int $x, public int $y) implement= s Vector2 use Evolvable; >> } >>=20 >> // Create a new pixel point with property $x and $y set to 0 >> $p =3D new Pixel::Point(0, 0); >>=20 >> There are far more details in the RFC itself, so please check it out.= I'm quite excited to hear your thoughts! >>=20 >> =E2=80=94 Rob >>=20 >> PS. I know I tend to rush into things, but I want to make it clear th= at I'm not rushing this -- I've learned from my mistakes (thank you to t= hose who have given me advice). I'm going to do this right. >=20 > I have read and reread this RFC, and I am struggling to see=20 >=20 > 1. What problem does this solve that anonymous classes do not? Thank you for asking this question. :) Anonymous classes can be useful t= o "hack your way around" the problem that inner (nested?) classes solve.= Anonymous classes are inline, leading to complex/long functions that wo= uld do nothing but define a class. Anonymous classes can (could?) be hac= ked to allow for reuse (extending), but only exist where they are define= d. An inner class can be extended and reused just fine. Finally, nested = classes allow for more readable code without sacrificing encapsulation. > 2. As with any syntax change and new operator there needs to be very c= areful consideration, do we need a new operation, or could `::` if the p= arent is static or `->` if the class is initialized? There's quite a long thread already about this very topic. That being sa= id, the inner class has no bearing on whether the outer class is instant= iated or not. Originally, I used `::` as the separator, but it seems the= re are some good arguments for `\`, so we will see. > 3. The idea that extending the parent class doesnt no inherit the chil= d classes doesnt make sense to me.=20 > As then if you extend a parent class and call a function of that class= 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 I'm not sure what you mean. When you inherit a class, you do not necessa= rily 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 of i= ssues with LSP. This is specifically why inheritance works the way it do= es in this RFC and why `static::` is forbidden.=20 =E2=80=94 Rob --e4c60d741a194b3ea031b907cc939365 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable
On Mon, Mar 17,= 2025, at 16:30, fennic log wrote:

On Wed, 5 Mar 2025 at 23:14, Rob Landers <rob@bottled.= codes> wrote:

Hello PHP Internals,

I'd like to introduce my RFC for discussion: https://w= iki.php.net/rfc/short-and-inner-classes

This RFC defines a short class syntax as well as the ability to nest cl= asses inside another class. This introduces an unprecedented amount of c= ontrol, flexibility, and expressiveness over how objects are used and in= stantiated in PHP. There is a PR (https://github.com/php/php-src/pull/17= 895) that implements this functionality -- all test failures are rel= ated to different/new/incorrect error messages being generated. However,= the core functionality exists to take for a test ride.
So, what do I mean by "unprecedented amount of control"? Wi= th this change, you can declare an inner class as private or protected, = preventing its usage outside of the outer class:

class User {
  private class Id {}

  public function __construct(public self::Id $id)= {}
}

In the above example, t= he class `User` is impossible to construct even though it has a public c= onstructor (except through reflection) because User::Id is private; User= ::Id cannot be instantiated, used as a type hint, or even via `instanceo= f` outside of the User class itself. This example isn't practical but de= monstrates something that is nearly impossible in previous versions of P= HP, where all classes are essentially publicly accessible from anywhere = within the codebase.

As a number of inner c= lasses will probably be used as DTOs, the RFC introduces a "short syntax= " for declaring classes, which enhances expressiveness, even allowing th= e usage of traits, all in a single line:

//= declare a readonly Point, that implements Vector2 and uses the Evolvabl= e trait
readonly class Point(public int $x, public int $y)= implements Vector2 use Evolvable;

When com= bined with inner classes, it looks something like this:
class Pixel {
  public readonly class Po= int(public int $x, public int $y) implements Vector2 use Evolvable;
<= /div>
}

// Create a new pixel point wit= h property $x and $y set to 0
$p =3D new Pixel::Point(0, 0= );

There are far more details in the RFC it= self, so please check it out. I'm quite excited to hear your thoughts!

=E2=80=94 Rob

PS. I know I tend to rush into things, but I want = to make it clear that I'm not rushing this -- I've learned from my mista= kes (thank you to those who have given me advice). I'm going to do this = right.

I hav= e read and reread this RFC, and I am struggling to see 

1. What problem does this solve that anonymous clas= ses do not?

Thank you for asking this question. :) Anonymous classes can be usefu= l to "hack your way around" the problem that inner (nested?) classes sol= ve. Anonymous classes are inline, leading to complex/long functions that= would do nothing but define a class. Anonymous classes can (could?) be = hacked to allow for reuse (extending), but only exist where they are def= ined. An inner class can be extended and reused just fine. Finally, nest= ed classes allow for more readable code without sacrificing encapsulatio= n.

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?
=

There's quite a long thread alrea= dy about this very topic. That being said, the inner class has no bearin= g on whether the outer class is instantiated or not. Originally, I used = `::` as the separator, but it seems there are some good arguments for `\= `, so we will see.

3. The idea that extending the parent class doesnt no= inherit the child classes doesnt make sense to me. 
=
As then if you extend a parent class and call a function of that cl= ass which could rely on the existence of an inner class, I can see a lot= of headaches caused by this exact scenario.
As a develope= r, if I extend a class, I expect the entire dependance of that class to = be inherited, otherwise the extending class won't work. 
<= /div>

I'm not sure what you mean. = When you inherit a class, you do not necessarily 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 "ty= pe", otherwise we would cause all kinds of issues with LSP. This is spec= ifically why inheritance works the way it does in this RFC and why `stat= ic::` is forbidden. 

=E2= =80=94 Rob
--e4c60d741a194b3ea031b907cc939365--