Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127640 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 CF4BF1A00BC for ; Tue, 10 Jun 2025 21:45:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1749591804; bh=TYx+9a2+b2kUKQMrg8nCaE8UAUUsJD9OSs3E5lzT5Rg=; h=Date:From:To:In-Reply-To:References:Subject:From; b=RT3RHZEeQye2LZxT6ySZagRJ5UxGCl6forrsRA3YY6r7F3jXGhVO6SD9aM1uejqRS CjA7rJtyYbSlg+cZx6/jZBIaHhMDOsdALXF3D9NAbyRdSEbxGmCvptW/F7YIMOms2n +Y7xzYFrIbOJXb8pUKY7ehJdMDzjY5NsBunDqOUi8BizsWPgCC5UzBFVu3IxhUOI9K +rdTBptnGsyUtOqLueOpNTE2AYKU96TfECXEzsC7Wn4MvCJX9S1ExP9oCgEPOd5W5H RjDkb+gtre5uVe8Qab1X7nlV0qGzHuCEmBT9CURIfaSSBmHISQDHtbjwJYn3pemphu 6Xc7pSFlmFLTA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id E143B180082 for ; Tue, 10 Jun 2025 21:43:22 +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=-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.1 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from fhigh-a3-smtp.messagingengine.com (fhigh-a3-smtp.messagingengine.com [103.168.172.154]) (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 ; Tue, 10 Jun 2025 21:43:22 +0000 (UTC) Received: from phl-compute-05.internal (phl-compute-05.phl.internal [10.202.2.45]) by mailfhigh.phl.internal (Postfix) with ESMTP id 8B2E11140152 for ; Tue, 10 Jun 2025 17:45:23 -0400 (EDT) Received: from phl-imap-05 ([10.202.2.95]) by phl-compute-05.internal (MEProxy); Tue, 10 Jun 2025 17:45:23 -0400 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=fm2; t=1749591923; x=1749678323; bh=wqKMeqbp/7 8c4oTSckzK+wcCRuWfP6RLAAQaaPt6Wtg=; b=B9azC8dVeApP04PyAGQVy4FSI1 80PtY+pbvZqe6pP3y13AAQPNxxE2UDq7j/N+NU9xJ+1IGh9JbT798b9QwidelkUf w6zifcyUX00KAiho5/3NFRaqRqiWmnmQwglp4El2ohuNu9ZS81WpZ42DymoUtBPc /JB4y4ZFgFf/BKKql5UiAHDI1RUqofhHC9y7/jIGLIyCXZW0maaA+DuKoXQk3r4m OXXBbaReVBC8yjaokNVvc7KoZuyUl0uJAqNQvvoRPXFh46DKW74yRKA3FwXwJXrv mwrOYu4azKcvn6j0e24ensQqFNJal0qvM9ztSP6flXVFNBw8m4oR73eWnAQA== 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=fm1; t= 1749591923; x=1749678323; bh=wqKMeqbp/78c4oTSckzK+wcCRuWfP6RLAAQ aaPt6Wtg=; b=fZmRxfmM/ktfMqbrXMEYspaRyIiUpGVMJOZN6qEzP7tyMFAuoYV zaI4ZyRg2Ej8y/qKsmAxx47sKcTyKS/ZMdNFmZ8kzm8/NYubjMZgtwsoYuGTRaPC kDw9MQ+cTY8S85KNJ0m1mBiUvQHS5HlZM6yvurpoCg6FJtrVOCPtoMnURW3RFI4L FcUdW0xh/BBl+nDaxTNFZaASSmYfFmbpHSG3T8MTFeXD0RFU0SVPXf48a2HqtrUT FASC1ZhSq6nJpoTgJe+t6He3hFaS+5qk087gMo4Uy+hW4mfFpfal21fXyELz4VUb FKzwBKLbFvd32WZ5JQOVhTW0xI0zwybC8sw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtddugdduudeftdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuuhhsphgvtghtff homhgrihhnucdlgeelmdenucfjughrpefoggffhffvkfgjfhfutgesrgdtreerredtjeen ucfhrhhomhepfdftohgsucfnrghnuggvrhhsfdcuoehrohgssegsohhtthhlvggurdgtoh guvghsqeenucggtffrrghtthgvrhhnpedtiedtvddvvefhudffhfegleffteegffevkeeh keefleeuuddtieevkedvteejvdenucffohhmrghinhepfehvgehlrdhorhhgnecuvehluh hsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomheprhhosgessghothht lhgvugdrtghouggvshdpnhgspghrtghpthhtohepuddpmhhouggvpehsmhhtphhouhhtpd hrtghpthhtohepihhnthgvrhhnrghlsheslhhishhtshdrphhhphdrnhgvth X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 12EFF1820067; Tue, 10 Jun 2025 17:45:22 -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 X-ThreadId: T50d26af4e5cb2915 Date: Tue, 10 Jun 2025 23:45:02 +0200 To: internals@lists.php.net Message-ID: <4c5b7a48-1ca2-4197-a103-9d7fa94b6e36@app.fastmail.com> In-Reply-To: References: Subject: Re: [PHP-DEV] Feature Discussion | Content-Type: multipart/alternative; boundary=b9e31c128f8b4739ab5e6e919b79dd96 From: rob@bottled.codes ("Rob Landers") --b9e31c128f8b4739ab5e6e919b79dd96 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Tue, Jun 10, 2025, at 22:09, Larry Garfield wrote: > On Tue, Jun 10, 2025, at 2:45 PM, Dmitry Derepko wrote: > > Thanks for participating, Larry. > > > > On Mon, Jun 9, 2025 at 10:29=E2=80=AFPM Larry Garfield wrote: > >> 2. Please link to a PR of your actual implementation. In context i= t looks like your branch comparison link is to the version you said didn= 't work, so it's not that helpful. > > > > Correct, I don't have another one. This is big feature, I need a lot= of=20 > > time to implement it. I don't want to waste my time if we decide tha= t=20 > > RFC won't pass at all. >=20 > Understood. I'd recommend figuring it out, even if it costs a lot of time. Some of t= he feedback I got on nested classes -- even after working on the impleme= ntation nearly every weekend for months -- was that the PoC code was too= hacky and didn't work with opcache. There are hard dates for features t= o be merged; and if you don't hit that date ... well, fun times to be ha= d trying to get it done by the release time, and nobody wants that crunc= h (and the inevitable bugs that follow). There's enough to do just to ge= t a release done. Having working code that is at least somewhat shippabl= e is a big indicator that an RFC will pass. >=20 > >> 3. The biggest question that has come up in the past (Ilija and I h= ave discussed it at length) is, naturally, autoloading. How if at all d= o you address that? > > > > In the original message I mentioned `use extension` construction. Th= is=20 > > should be enough for solution, isn't it? >=20 > Very much not. The `use` construct has no bearing on autoloading curr= ently. Autoloading happens only for classes and class-like things (inte= rfaces, traits, enums). If a function is not found, PHP just crashes. = Various solutions to this have been discussed over the years, none of wh= ich ever made it as far as a vote. >=20 > I toyed with the idea of having extension functions compile to a stati= c method on a class as a way around this, but of course then you end up = with a file-per-function, and the file name has to match not the functio= n name, but whatever mangled class name gets generated. Not at all intu= itive. >=20 > In fairness, I think with universal opcache, preloading, and the incre= asing use of persistent processes, just skipping autoloading for functio= ns and front-loading them via composer.json's "files" block is fine for = the 80% case. But it feels like I am in the minority on that position. >=20 > >> 4. The other big question was determining when to match a given "me= thod" call to an extension function, when the type of a variable is not = always known at compile time. How did you address this? > > > > Cannot understand the passage, could you explain more? >=20 > // index.php >=20 > function Point.area(): int {=20 > return $this->x & $this->y; > } >=20 > function doStuff($p) { > // At compile time, we don't know that $p is a Point. In fact, it ma= y not be. > // The function will allow any value here, even a non-object, so it = doesn't know > // if this should be compiled to Point__area($p) or left as is. > print $p->area(); > } >=20 > The only way I could think of to handle that is to have a method call = "trap" similar to class autoloading, that when hit checks at runtime "he= y, this method didn't exist, but is there a `use`d function that would m= atch based on the runtime type of this value?" But Ilija felt that woul= d be prohibitively slow. It would certainly be slower than just a funct= ion/method call since the trap takes time. Yep, this would def have to be done at runtime; not compile time, which = pretty much rules out `use` as a solution (at least as `use` is currentl= y implemented). What could happen instead is that it literally patches t= he class's method table when you define an extension method. This would = make it globally available once defined; but that is probably fine 99% o= f the time (since you're most likely the only one using that extension).= You could even isolate it to the namespace it is defined in. A solution= could be to encode the namespace in the injected method name as a sort = of mangling. namespace Foo; function \OtherNamespace\Point.area(): int {} // patches OtherNamespace\Point with a method called \Foo\Area() Or something like that. The main issue is that then it can't be resolved= at runtime because namespaces are "erased". You'd have to extract the c= urrent namespace from the current name which means bare code won't be ab= le to call it, even if it is in the namespace because bare code is execu= ted in the global namespace (IIRC): https://3v4l.org/pRsoh I did quite a bit of experimentation on this for nested classes (which n= eeded to be able to differentiate between a namespace and a class of the= same name). It's not simple. I don't really have a good solution; so I'm sorry to only bring issues h= ere. But at least I can name the challenges ahead. Feel free to ask me a= nything about this. > And then we get into questions of inheritance, and, well, it gets even= messier fast. >=20 > One possibility that we riffed on during the pipes discussion (mostly = off list, I think) was using +> for some combination of extension functi= ons and Elixir-style first-arg pipe passing, so that $p+>area() would si= gnal to the engine (compile time or runtime) that area() wasn't a method= but a function that should get $p passed to it. That would solve the "= trap" problem, but still doesn't address autoloading, the lack of compil= e time type knowledge, or how to differentiate between Point.area(), Sha= peInterface.area(), Rect.area(), etc. >=20 > --Larry Garfield =E2=80=94 Rob --b9e31c128f8b4739ab5e6e919b79dd96 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable
On Tue, Jun = 10, 2025, at 22:09, Larry Garfield wrote:
On Tue, Jun 10, 2025, at 2:45 PM, Dmitry Dere= pko wrote:
> Thanks for participating, Larry.
>= ;
> On Mon, Jun 9, 2025 at 10:29=E2=80=AFPM Larry Garfield = <larry@garfieldtech.com= > wrote:
>> 2. Please link to a PR of your actual imp= lementation.  In context it looks like your branch comparison link = is to the version you said didn't work, so it's not that helpful.
<= div>>
> Correct, I don't have another one. This is big f= eature, I need a lot of 
> time to implement it. I don= 't want to waste my time if we decide that 
> RFC won'= t pass at all.

Understood.

I'd recommend figuring it out, even if it costs a lot = of time. Some of the feedback I got on nested classes -- even after work= ing on the implementation nearly every weekend for months -- was that th= e PoC code was too hacky and didn't work with opcache. There are hard da= tes for features to be merged; and if you don't hit that date ... well, = fun times to be had trying to get it done by the release time, and nobod= y wants that crunch (and the inevitable bugs that follow). There's enoug= h to do just to get a release done. Having working code that is at least= somewhat shippable is a big indicator that an RFC will pass.
=

=
>> 3. The biggest question that has come up in the past (Ilij= a and I have discussed it at length) is, naturally, autoloading.  H= ow if at all do you address that?
>
> In the o= riginal message I mentioned `use extension` construction. This 
> should be enough for solution, isn't it?

Very much not.  The `use` construct has no bearing on autoloa= ding currently.  Autoloading happens only for classes and class-lik= e things (interfaces, traits, enums).  If a function is not found, = PHP just crashes.  Various solutions to this have been discussed ov= er the years, none of which ever made it as far as a vote.
I toyed with the idea of having extension functions compile = to a static method on a class as a way around this, but of course then y= ou end up with a file-per-function, and the file name has to match not t= he function name, but whatever mangled class name gets generated.  = Not at all intuitive.

In fairness, I think with= universal opcache, preloading, and the increasing use of persistent pro= cesses, just skipping autoloading for functions and front-loading them v= ia composer.json's "files" block is fine for the 80% case.  But it = feels like I am in the minority on that position.

>> 4. The other big question was determining when to match a gi= ven "method" call to an extension function, when the type of a variable = is not always known at compile time.  How did you address this?
>
> Cannot understand the passage, could you expl= ain more?

<?php 
// index.php=

function Point.area(): int { 
&= nbsp; return $this->x & $this->y;
}

function doStuff($p) {
  // At compile time, we = don't know that $p is a Point. In fact, it may not be.
  = // The function will allow any value here, even a non-object, so it does= n't know
  // if this should be compiled to Point__area($= p) or left as is.
  print $p->area();
}

The only way I could think of to handle that is to = have a method call "trap" similar to class autoloading, that when hit ch= ecks at runtime "hey, this method didn't exist, but is there a `use`d fu= nction that would match based on the runtime type of this value?"  = But Ilija felt that would be prohibitively slow.  It would certainl= y be slower than just a function/method call since the trap takes time.<= /div>

Yep, this would def have to be don= e at runtime; not compile time, which pretty much rules out `use` as a s= olution (at least as `use` is currently implemented). What could happen = instead is that it literally patches the class's method table when you d= efine an extension method. This would make it globally available once de= fined; but that is probably fine 99% of the time (since you're most like= ly the only one using that extension). You could even isolate it to the = namespace it is defined in. A solution could be to encode the namespace = in the injected method name as a sort of mangling.

<= div>namespace Foo;

function \OtherNamespace\Poi= nt.area(): int {}

// patches OtherNamespace\Poi= nt with a method called \Foo\Area()

Or somethin= g like that. The main issue is that then it can't be resolved at runtime= because namespaces are "erased". You'd have to extract the current name= space from the current name which means bare code won't be able to call = it, even if it is in the namespace because bare code is executed in the = global namespace (IIRC): https:/= /3v4l.org/pRsoh

I did quite a bit of experi= mentation on this for nested classes (which needed to be able to differe= ntiate between a namespace and a class of the same name). It's not simpl= e.

I don't really have a good solution; so I'm = sorry to only bring issues here. But at least I can name the challenges = ahead. Feel free to ask me anything about this.

And then we get into que= stions of inheritance, and, well, it gets even messier fast.
<= br>
One possibility that we riffed on during the pipes discuss= ion (mostly off list, I think) was using +> for some combination of e= xtension functions and Elixir-style first-arg pipe passing, so that $p+&= gt;area() would signal to the engine (compile time or runtime) that area= () wasn't a method but a function that should get $p passed to it. = That would solve the "trap" problem, but still doesn't address autoload= ing, the lack of compile time type knowledge, or how to differentiate be= tween Point.area(), ShapeInterface.area(), Rect.area(), etc.
<= br>
--Larry Garfield

=E2=80=94 Rob --b9e31c128f8b4739ab5e6e919b79dd96--