Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127522 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 EC7C51A00BC for ; Sun, 1 Jun 2025 07:48:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1748763974; bh=mB6r/I3RbJNLT21EJirGdUX5Pn0qOOAizoT+Uo4sIrE=; h=Date:From:To:In-Reply-To:References:Subject:From; b=n+tHk8rJuIsp9/h2Qpqk4HqVywpvLlnOSLogW7QzQKT9/qOfc76DwY7zG0jQxiDRb tIOqRvTJQYrzhKvxTTvB6HfJ7cckVmqNQPk6mXOlSVBYHCqNgz4FnZtDKAxvQWSD3P 7isO5i/ZM0/eKOw1PvbRKkaxPHQey7+8Ho1n/Q1gKv3S8MQCGqLK2mvn3aJx4kEH3u JyBJfRqduam6TdYWRqYbp+XmidWrKD8TOMEgDtWnD9NWr3ulm71JIzJoeOh0F2Sejp 1RUBeq4nyEl70rt5NOE1n1Tz5eY4p3CNpf/1WgGBFBu5MtB68Qz/Iiovmv7z59XAXt VDxsM3icTugQA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 8007018038C for ; Sun, 1 Jun 2025 07:46:13 +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-b1-smtp.messagingengine.com (fhigh-b1-smtp.messagingengine.com [202.12.124.152]) (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, 1 Jun 2025 07:46:13 +0000 (UTC) Received: from phl-compute-05.internal (phl-compute-05.phl.internal [10.202.2.45]) by mailfhigh.stl.internal (Postfix) with ESMTP id EACE22540115 for ; Sun, 1 Jun 2025 03:48:17 -0400 (EDT) Received: from phl-imap-05 ([10.202.2.95]) by phl-compute-05.internal (MEProxy); Sun, 01 Jun 2025 03:48:17 -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=1748764097; x=1748850497; bh=Y0YMohb1it eZnufHbANNcQT4eYM4+kApyaJA9+RkvSs=; b=fNFItle1q9ChWxXDn6l9Oh0Qxz dZk6QkJnkmARhIIrrABGsJOJNyBdGMxG95UVDGzC0E8kKUHNi0qSyojZJx5Z5OKO f6UL+mD/mQTzeW9ji8u66aUie80o0ouBmym43y5yDqU8NVfDinWHZRH7kI96Cmnr eJPZzVOooAu7LOfAuZNCqbNVDKr43j7hEB0E+ikMAeFVRjxC82JCVR1Tv49NpOfp yBTfFqEKy4TaSq7X2HCYoOtpVzqL8iyqGKIRNxnjn+ViaY1fN/l5LkowA9jJi2xf SUS45Gnt0w8sTEsmwtYWx1IdKqOgHkNVTIO5OfLiLY2KVBhONrIpMrKrQcJw== 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= 1748764097; x=1748850497; bh=Y0YMohb1iteZnufHbANNcQT4eYM4+kApyaJ A9+RkvSs=; b=JePOdguJfbb6N0xDSYxDJ/73Pq4E0zEkcDo4TCLEWJvJjmcoB+O SQsGgLHYu74eQjIkKyPfxZezDXpviosENAp410tX/53NtTjZfrV5KXydr7gUd75M D87ccqK2TPSpkdCTZZUShyQSjqYi30sKsmuuqX5DIMHKrpDZBBLUpNaNdp8PvyIr lQRK+smz+FYBlpggyJsRhNJY1QPCYlAQzPBPpZHPUWjz7tDXIwXvXc+iuS8wZRFI KjK4PBqpwIYYRKHz/qpzleoVdju3m9Y2+clKT39BGjlQWQkBgoUs7/B4UowoWYD/ xayDMHmyPcuKMpjZs58JWO9sjZMNy0bAZ7A== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtddtgdefgedvvdculddtuddrgeefvddrtd dtmdcutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggft fghnshhusghstghrihgsvgdpuffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftd dtnecunecujfgurhepofggfffhvffkjghfufgtsegrtderreertdejnecuhfhrohhmpedf tfhosgcunfgrnhguvghrshdfuceorhhosgessghothhtlhgvugdrtghouggvsheqnecugg ftrfgrthhtvghrnhepleekhedtgfefhfelieelgfegiefhkedvleefjedtffelhfehheff gfduteduuddtnecuffhomhgrihhnpehphhhprdhnvghtnecuvehluhhsthgvrhfuihiivg eptdenucfrrghrrghmpehmrghilhhfrhhomheprhhosgessghothhtlhgvugdrtghouggv shdpnhgspghrtghpthhtohepuddpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtohepih hnthgvrhhnrghlsheslhhishhtshdrphhhphdrnhgvth X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 551521820067; Sun, 1 Jun 2025 03:48:17 -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: T018bd9ffc60205f7 Date: Sun, 01 Jun 2025 09:47:54 +0200 To: internals@lists.php.net Message-ID: In-Reply-To: <6cbfb0ca-5be3-4c00-94ba-4595cfad3738@app.fastmail.com> References: <78641D8B-AF1D-4912-920A-D75A37C32F05@rwec.co.uk> <354cb888-97c4-4f8c-a0da-359d1e63c0f9@rwec.co.uk> <10D95B6E-094B-4EAE-A18A-AF6B795CB352@rwec.co.uk> <2adbff61-5e11-4d39-ab5c-d7950a4550a6@app.fastmail.com> <79E7FA26-2F5A-470C-B1DF-12CC46A08FE5@rwec.co.uk> <1c6dcd84-9016-48e1-971f-de7749cbdce8@rwec.co.uk> <44F59416-3922-4AF4-881A-C64F2C4E9345@rwec.co.uk> <7F11844A-A98C-4843-BC94-815FBCD2B73F@garsi.de> <7840468C-F60C-4A44-AE40-16F9007EF428@rwec.co.uk> <160E9B1D-9AF6-479B-A628-A73C618D7C1B@garsi.de> <6cbfb0ca-5be3-4c00-94ba-4595cfad3738@app.fastmail.com> Subject: Re: [PHP-DEV] Module or Class Visibility, Season 2 Content-Type: multipart/alternative; boundary=8cfbb1fc9cba4f5492a51988de5273d9 From: rob@bottled.codes ("Rob Landers") --8cfbb1fc9cba4f5492a51988de5273d9 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Sun, Jun 1, 2025, at 09:17, Rob Landers wrote: >=20 >=20 > On Sun, Jun 1, 2025, at 07:26, Michael Morris wrote: >> Ok, the conversation is getting sidetracked, but I think some progres= s is being made. >>=20 >> I started this latest iteration last year with a thread about introdu= cing something similar to the ES module system of JavaScript to PHP. Wha= t attracts me to this particular model is that it should already be fami= liar to the vast majority of PHP users. Prior to ES modules browsers had= no natural module import mechanic. Prior to ES modules all symbols wer= e attached to the window. You can see this if you serve open this index.= html from a server (Note that opening the file locally will result in th= e js being blocked by modern browser security. ) >>=20 >> ```html >> >> >> >> >> >> >> >> >> >> ``` >> The above spits 1234 into the console twice. Second example - let's = put a module in. >>=20 >> ```html >> >> >> >> >> >> >> >> >> >> >> ``` >> This outputs 1234 twice and an error is raised about b being undefine= d. >>=20 >> I bring the above up to demonstrate that is the desired behavior of w= hat I originally called a PHP module and have been bullied over and take= n to task about not understanding the meaning of "module". Rowain seems = to be more comfortable characterizing this as containers. If everyone is= happy with that term I really don't care - I just want a way to isolate= a code block so that whatever happens in there stays in there unless I = explicitly export it out, and the only way I see things in that scope is= if I bring them in. >>=20 >> The other thing that was done with ES is that the syntax for the modu= les was tightened. JavaScripters cannot dictate what browser a user choo= ses, so the bad decisions of the early days of JS never really went away= until ES came along which enforced their strict mode by default. PHP h= as no such strict mode - it has a strict types mode but that isn't the s= ame thing. There are multiple behaviors in PHP that can't go away becau= se of backwards compatibility problems, and one of those might indeed be= how namespaces are handled. In PHP a namespace is just a compile shortc= ut for resolving symbol names. The namespace is prefixed to the start of= every symbol within it. Unlike Java or C#, PHP has no concept of namesp= ace visibility. At the end of the day it's a shortcut and its implementa= tion happens entirely at compile time. >>=20 >> Previously in the discussion Alwin Garside made a long but insightful= post on namespaces and their workings that I've been thinking on and tr= ying to digest for the last several days. What I've arrived at is the di= scussions about composer and autoloaders are indeed a red herring to the= discussion. At the end of the day, PHP's include statements are a means= to separate the php process into multiple files. In his email he explor= ed some of the rewriting that could be done, and myself and Rowain have = also explored this in the form of namespace pathing and aliasing. >>=20 >> We've gotten away from the original focus of containing this code and= how that would work. So once again this moron is going to take a stab a= t it. >>=20 >> Container modules are created with require_module('file/path'). All c= ode that executes as a result of this call is isolated to its container.= That includes the results of any require or include calls made by the m= odule file itself or any file it requires. >>=20 >> Since the module file is cordoned off to its own container from the r= est of the application whatever namespaces it uses are irrelevant to out= side code. Any symbols created in the module will not be established in = the script that made the require_module() call. Since it is coming into = being with a new require mechanism it could be subjected to more efficie= nt parsing rules if that is desired, but that's a massive can of worms f= or later discussion. One of those will be necessary - it will need to re= turn something to the php code that called it. The simplest way to go a= bout this is to just require that it have a return. So... >>=20 >> $myModule =3D require_module('file/path'); >>=20 >> or perhaps >>=20 >> const myModule =3D require_module('file/path'); >>=20 >> The module probably should return a static class or class instance, b= ut it could return a closure. In JavaScript the dynamic import() statem= ent returns a module object that is most similar to PHP's static classes= , with each export being a member or method of the module object. >>=20 >> Circling back to a question I know will be asked - what about autoloa= ders? To which I answer, what about them? If the module wants to use an= autoloader it has to require one just as the initial php file that requ= ired it had to have done at some point. The container module is for all= intents and purposes its own php process that returns some interface to= allow it to talk to the process that spawned it.=20 >>=20 >> Will this work? I think yes. Will it be efficient? Hell no. Can it be= optimized somehow? I don't know. >>=20 >=20 > This could work! I have a couple of critiques, but they aren=E2=80=99t= negative: >=20 > I think I like it. It might be worth pointing out that JavaScript "hoi= sts" the imports to file-level during compilation =E2=80=94 even if you = have the import statement buried deep in a function call. Or, at least i= t used to. I haven=E2=80=99t kept track of the language that well in the= last 10 years, so I wouldn=E2=80=99t be surprised if it changed; or did= n=E2=80=99t. I don=E2=80=99t think this is something we need to worry ab= out too much here. >=20 > It=E2=80=99s also worth pointing out that when PHP compiles a file, ev= ery file has either an explicit or implicit return. https://www.php.net/= manual/en/function.include.php#:~:text=3DHandling%20Returns%3A,from%20in= cluded%20files. >=20 > So, in other words, what is it about require_module that is different = from `require` or `include`? Personally, I would then change PHP from "c= ompile file" mode when parsing the file to "compile module" mode. From a= totally naive point-of-view, this would cause PHP to: > 1. if we already have a module from that file; return the module inst= ead of compiling it again. > 2. swap out symbol tables to the module=E2=80=99s symbol table. > 3. start compiling the given file. > 4. concatenate all files as included/required. > 5. compile the resulting huge file. > 6. switch back to the calling symbol table (which may be another modu= le). > 7. return the module. > For a v1, I wouldn=E2=80=99t allow autoloading from inside a module =E2= =80=94 or any autoloaded code automatically isn=E2=80=99t considered to = be part of the module (it would be the responsibility of the main progra= m to handle autoloading). This is probably something that needs to be so= lved, but I think it would need a whole new approach to autoloading whic= h should be out of scope for the module RFC (IMHO). >=20 > In other words, you can simply include/require a module to load the en= tire module into your current symbol table; or use require_module to "co= ntain" it. >=20 > As for what should a module return? I like your idea of just returning= an object or closure. >=20 > =E2=80=94 Rob I just had another thought; sorry about the back-to-back emails. This wo= uldn=E2=80=99t preclude something like composer (or something else) from= being used to handle dependencies, it would just mean that the package = manager might export a "Modules" class + constants =E2=80=94 we could al= so write a composer plugin that does just this: require_once 'vendor/autoload.php'; $module =3D require_module Vendor\Module::MyModule; where Vendor\Module is a generated and autoloaded class containing const= s to the path of the exported module. =E2=80=94 Rob --8cfbb1fc9cba4f5492a51988de5273d9 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable


On Sun, Jun 1, 2025, at 09:17, Rob Landers wrote:


=
On Sun, Jun 1, 2025, at 07:26, Michael Morris wrote:
Ok,= the conversation is getting sidetracked, but I think some progress is b= eing made.

I started this latest iteration last= year with a thread about introducing something similar to the ES module= system of JavaScript to PHP. What attracts me to this particular model = is that it should already be familiar to the vast majority of PHP users.= Prior to ES modules browsers had no natural module import mechanic.&nbs= p; Prior to ES modules all symbols were attached to the window. You can = see this if you serve open this index.html from a server (Note that open= ing the file locally will result in the js being blocked by modern brows= er security. )

```html
<!DOCT= YPE html>
<html>
  <head>
<= div>    <script>
      var a =3D= 1234
    </script>
  </head= >
  <body>
    <script>= ;
      console.log(a)
    =   console.log(window.a)
    </script>
  </body>
</html>
```<= /div>
The above spits 1234 into the console twice.  Second exam= ple - let's put a module in.

```html
=
<!DOCTYPE html>
<html>
  <h= ead>
    <script>
    &= nbsp; var a =3D 1234
    </script>
&= nbsp;   <script type=3D"module">
    &nbs= p; const a =3D 5678
      var b =3D 9123
<= div>    </script>
  </head>
  <body>
    <script>
=       console.log(a)
      conso= le.log(window.a)
      console.log(b)
    </script>
  </body>
= </html>
```
This outputs 1234 twice and = an error is raised about b being undefined.

I b= ring the above up to demonstrate that is the desired behavior of what I = originally called a PHP module and have been bullied over and taken to t= ask about not understanding the meaning of "module". Rowain seems to be = more comfortable characterizing this as containers. If everyone is happy= with that term I really don't care - I just want a way to isolate a cod= e block so that whatever happens in there stays in there unless I explic= itly export it out, and the only way I see things in that scope is if I = bring them in.

The other thing that was done wi= th ES is that the syntax for the modules was tightened. JavaScripters ca= nnot dictate what browser a user chooses, so the bad decisions of the ea= rly days of JS never really went away until ES came along which enforced= their strict mode by default.  PHP has no such strict mode - it ha= s a strict types mode but that isn't the same thing.  There are mul= tiple behaviors in PHP that can't go away because of backwards compatibi= lity problems, and one of those might indeed be how namespaces are handl= ed. In PHP a namespace is just a compile shortcut for resolving symbol n= ames. The namespace is prefixed to the start of every symbol within it. = Unlike Java or C#, PHP has no concept of namespace visibility. At the en= d of the day it's a shortcut and its implementation happens entirely at = compile time.

Previously in the discussion Alwi= n Garside made a long but insightful post on namespaces and their workin= gs that I've been thinking on and trying to digest for the last several = days. What I've arrived at is the discussions about composer and au= toloaders are indeed a red herring to the discussion. At the end of the = day, PHP's include statements are a means to separate the php process in= to multiple files. In his email he explored some of the rewriting that c= ould be done, and myself and Rowain have also explored this in the form = of namespace pathing and aliasing.

We've gotten= away from the original focus of containing this code and how that would= work. So once again this moron is going to take a stab at it.

Container modules are created with require_module('file/= path'). All code that executes as a result of this call is isolated to i= ts container. That includes the results of any require or include calls = made by the module file itself or any file it requires.

Since the module file is cordoned off to its own container from= the rest of the application whatever namespaces it uses are irrelevant = to outside code. Any symbols created in the module will not be establish= ed in the script that made the require_module() call. Since it is coming= into being with a new require mechanism it could be subjected to more e= fficient parsing rules if that is desired, but that's a massive&nbs= p;can of worms for later discussion. One of those will be necessary - it= will need to return something to the php code that called it.  The= simplest way to go about this is to just require that it have a return.= So...

$myModule =3D require_module('file/path'= );

or perhaps

const my= Module =3D require_module('file/path');

The mod= ule probably should return a static class or class instance, but it coul= d return a closure.  In JavaScript the dynamic import() statement r= eturns a module object that is most similar to PHP's static classes= , with each export being a member or method of the module object.
<= div>
Circling back to a question I know will be asked - wh= at about autoloaders?  To which I answer, what about them? If the m= odule wants to use an autoloader it has to require one just as the initi= al php file that required it had to have done at some point.  The c= ontainer module is for all intents and purposes its own php process that=  returns some interface to allow it to talk to the process that&nbs= p;spawned it. 

Will this work? I think yes= . Will it be efficient? Hell no. Can it be optimized somehow? I don't kn= ow.


This coul= d work! I have a couple of critiques, but they aren=E2=80=99t negative:<= /div>

I think I like it. It might be worth pointing o= ut that JavaScript "hoists" the imports to file-level during compilation= =E2=80=94 even if you have the import statement buried deep in a functi= on call. Or, at least it used to. I haven=E2=80=99t kept track of the la= nguage that well in the last 10 years, so I wouldn=E2=80=99t be surprise= d if it changed; or didn=E2=80=99t. I don=E2=80=99t think this is someth= ing we need to worry about too much here.

It=E2= =80=99s also worth pointing out that when PHP compiles a file, every fil= e has either an explicit or implicit return. https://www.php.net/manual/en/function.include.= php#:~:text=3DHandling%20Returns%3A,from%20included%20files.

So, in other words, what is it about require_module th= at is different from `require` or `include`? Personally, I would then ch= ange PHP from "compile file" mode when parsing the file to "compile modu= le" mode. From a totally naive point-of-view, this would cause PHP to:
  1. if we already have a module from that file; return the modul= e instead of compiling it again.
  2. swap out symbol tables to the m= odule=E2=80=99s symbol table.
  3. start compiling the given file.
  4. concatenate all files as included/required.
  5. compile the re= sulting huge file.
  6. switch back to the calling symbol table (whic= h may be another module).
  7. return the module.
For a= v1, I wouldn=E2=80=99t allow autoloading from inside a module =E2=80=94= or any autoloaded code automatically isn=E2=80=99t considered to be par= t of the module (it would be the responsibility of the main program to h= andle autoloading). This is probably something that needs to be solved, = but I think it would need a whole new approach to autoloading which shou= ld be out of scope for the module RFC (IMHO).

I= n other words, you can simply include/require a module to load the entir= e module into your current symbol table; or use require_module to "conta= in" it.

As for what should a module return? I l= ike your idea of just returning an object or closure.

=E2=80=94 Rob

<= /div>
I just had another thought; sorry about the back-to-back email= s. This wouldn=E2=80=99t preclude something like composer (or something = else) from being used to handle dependencies, it would just mean that th= e package manager might export a "Modules" class + constants =E2=80=94 w= e could also write a composer plugin that does just this:

=
require_once 'vendor/autoload.php';

= $module =3D require_module Vendor\Module::MyModule;

=
where Vendor\Module is a generated and autoloaded class containing = consts to the path of the exported module.

=E2=80=94 Rob
--8cfbb1fc9cba4f5492a51988de5273d9--