Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:124232 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 8822D1A009C for ; Fri, 5 Jul 2024 17:47:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1720201747; bh=X23L9YQlt3TJEd4lq0fiaN53ckRitBpzffrca3wpsqo=; h=References:In-Reply-To:From:Date:Subject:To:From; b=eF+8D68IliClUEBBdodTJVtU4fK9o8xP7Xf2H+fvUXpTICfmlQMEOsbjFvaEUeD89 Jmsi8Etj6Z1EkDIoiFtaixJbmV6ykwEtaamGoE/eJBT3W4IJ4FzpZx9eMY9548iA4b deSDjV9l652uAZmwAEflhw4O+HuQiyVGs2t0ViPD3XyYMAIEMVQzuhYPtd6NWjqJ6k F9R1KlJUyERy4FYiIL8MPrf6eKOP5I821LaUgwoxI1o7YxU2k9GU7hXlgEYWI7IeFp 0LclSVt8Emju5yHDyfSvDH1v3cvtDXK2w1Lc9b/xnFDVjbudMJ+CqfvWvmVGJpvgz9 XwLgI9VAnQPwA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 4B1FB18088F for ; Fri, 5 Jul 2024 17:49:06 +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=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from mail-qk1-f176.google.com (mail-qk1-f176.google.com [209.85.222.176]) (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 ; Fri, 5 Jul 2024 17:49:05 +0000 (UTC) Received: by mail-qk1-f176.google.com with SMTP id af79cd13be357-79c0abd3eaaso112031885a.2 for ; Fri, 05 Jul 2024 10:47:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1720201662; x=1720806462; darn=lists.php.net; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=qbQbo4LfsUX5oQ5x7HO6EB/iZ6KfnqCHpwM1d4D+G9M=; b=bZUBTywbHWS823i4j1F6xGnPxig4ffzhcGS+DWZNmUo6QgcINcMgzu6Irk67y0ISwL QgZ3QNpJwP+LBs2maAlM7QpQZhh+S8XCLQjhz6rE4favmawCx9GfzqDVgdnrNRYqpn/H oyvk+hvSTIPaDZiTAf0wuyGVFsLfoOCiiMa5LmdCa8O5BWbk4eVVxeBFyQkC28tU7Vxs q7F5JfnuYIHrdGJZei7X2jP0bfyqZcCRoKVUavNUH3a47h2z3r5ydct8SJPF3qxozNr/ E/LbV4+y3Kbktl0P40ZvNmaQgOVS9KmiK7pxkAgxI9QREWP+Iwimr7ZcqWwzEdqAfi+5 iMMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720201662; x=1720806462; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=qbQbo4LfsUX5oQ5x7HO6EB/iZ6KfnqCHpwM1d4D+G9M=; b=qwbTSwaoDwSVJW51M5aGYwhAnITW+4Dlk6+3ZNk39sPzaHIACsW3hS77QBXXeZ+ftm DkJKeKvTp1PLjjnk+w5KUjYhiHlb+ROkdfO5MPBxJQwCpchA7jEevO/25oWZGxYMtSGH 9iMDtph1Hgyf1VF/PWl/55LWvwnzVgOFhrqRdK6thcg1HHtyatOViquvBkEFl+5Ucste IiMFNic7f03zHIF4BBjk1ER8MvrQjHC2ZOs5wngYFo1D5RkbBgreu3R3yVw67OqtHHzO EbfVy9zHQHzPl5FKusl72pEjVNdBLtoRMZ+A2PRMIMOfgdG4o46AJY0PTWqzsshG05iR Um3g== X-Gm-Message-State: AOJu0YygLK4jbiTwv3+2HGTiqEVLzQxvAAhCQIJ6aRmUBKwlc8GxO/D5 7EiSWFhOfhtykcLfl5yGmLLkR53gC5N2K7uubnW6cNJwh/wdEyd0n0+ng9cAo0pfAv54sdQN74D Sa4dnd6hGfoZ7oUJUO7ivtXI39DW2nLNQ X-Google-Smtp-Source: AGHT+IEAFmMKNoxmxo91vGufapaxcu4jPypWT0FipVGDjDjAqCi71+GC+swYUac8O953IvlGtINkkrd3kDmFDJwa5gg= X-Received: by 2002:a05:6214:518e:b0:6b5:413a:3f97 with SMTP id 6a1803df08f44-6b5ecfaea3bmr62164426d6.30.1720201661770; Fri, 05 Jul 2024 10:47:41 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 References: <09559430-4477-4516-8D78-6F4071E1AA6C@newclarity.net> <0182F3D6-F464-477F-9029-A2D0A8B50C71@koalephant.com> <1AFD7AAE-8BEA-460D-88A8-15BB3D30A775@koalephant.com> <7B633CC7-C768-4852-A4D0-B252A04F7DE1@newclarity.net> <0E11F373-99DC-496E-9BBC-2F8688B9F66A@newclarity.net> <4F720A7A-B7DD-4B31-B0C9-6907419B53A5@newclarity.net> In-Reply-To: <4F720A7A-B7DD-4B31-B0C9-6907419B53A5@newclarity.net> Date: Fri, 5 Jul 2024 13:47:31 -0400 Message-ID: Subject: Re: [PHP-DEV] [PHP-Dev] Versioned Packagers (Iteration IV) To: PHP internals Content-Type: multipart/alternative; boundary="000000000000fdf62c061c83a899" From: tendoaki@gmail.com (Michael Morris) --000000000000fdf62c061c83a899 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Fri, Jul 5, 2024 at 1:29=E2=80=AFAM Mike Schinkel = wrote: > On Jul 4, 2024, at 9:16 PM, Michael Morris wrote: > On Wed, Jul 3, 2024 at 11:11=E2=80=AFPM Mike Schinkel wrote: > >> So I've had more time to mull this over, and some research, and I think = I >> have an approach. > > > First, instead of 'import', use 'require_module'. The parsing rules for > require_module differ from require how the file is parsed, a subject for > another time. Also, it's parallel to what is to follow. > > > +1 > > Speaking of new functions, let's start with these > > spl_set_include_ini_map('importmap.ini'); > spl_set_include_json_map('importmap.json") > > > Those are a mouthful! > > The json file is pretty much identical to the JavaScript importmaps. The > ini file looks like this > > root =3D "/absolute/path/to/application/root" > > [imports] > square =3D "./path/to/square.js" > circle =3D "./path/to/circle.js" > other/ =3D "./path/to/other/" > > [scopes] > \A[square] =3D './path/to/square/in/namespace/A/a.js' > > > I assume rather than `.js` you mean `.php` files in your example? > > Also, I am not following how these imports and scopes will relate to the > actual PHP code that would be affected/using packages. > > Whichever format is used is a matter of personal preference. The file can > be, and likely should be, written by composer or some future package > manager. > > > Part of me likes the flexibility of two formats. The other more pragmatic > part of me says stick with one format for fewer related bugs and to reduc= e > the effort to support it for internal code and by 3rd parties. > > Unless it can be fully cached by opcache I would think it would need to b= e > the format that can be parsed the fastest, which could be binary like a > Protobuf file. > > The root attribute in the map sets the root for all relative paths given > in the map. > > > Are you saying that a publisher of a package would need to write the > absolute path to their `importmap.*` file. How will that work? Even for = a > bespoke app Composer may not have enough access to the server to know thi= s, > and 3rd party packages will definitely not know it for their users. At > least I don't think so. > > Also, at this point trying to keep track of all your ideas is impossible, > at least for me. Have you reconsidered putting it in a repo or at least a > Gist yet so it is easier to see the scope of your current ideas about > packages? > > I'm getting there. I'm trying to boil things down at this point to something that can be put into such. I went to sleep thinking about this post, on import maps in general and how Composer works, specifically when you use a class map instead of the PSR-0 or PSR-4 schemes. In that mode, Composer does pretty much what I've described. This got me to thinking, could setting an import map be an alternative to setting an autoload function? Would having the PHP runtime load the file be faster than mucking with some userland code to do the same? And would the engine be able to do anything that can't be done in userland? I think so. So first, I agree that supporting two formats, while convenient, increases the maintenance burden, so let's just go with ini. As far as the installing function - a better name is this. spl_autoload_map( string $filepath ); This function will register an autoload map wrapped with an internal autoloader to work with it. If called multiple times the maps will resolve in the order they are called. If called along with the existing spl_autoload_register function then the maps and autoload functions will be used in the order of their declaration. Packages are expected to carry their own autoload maps. Autoload maps can only be loaded once - attempts to load the same map multiple times will raise a E_USER_WARNING The contents of the file along with comments as to what they do. ; The root directive affects the relative paths in the map. If set the location specified becomes ; the root. If not set all relative paths are relative to THIS FILE. ;root =3D '/some/path' ; If a package is declared, that is the root namespace for all the includes that follow. ; As this example is for a root autoloader it is commented out, as the root autoload function of ; an app doesn't need a package name. ;package =3D ; A map relates symbols to files. This one is for the existing include/require system. Actual ; file loading is performed by require_once. [includes] A\B\Cat =3D './path/to/Cat.php' ; A symbol can invoke the loading of multiple files. This will be useful if the package manager that ; prepares this file determines that a polyfill will be needed. Files will be loaded in order given. A\TestClass[] =3D './path/to/polyfill.php' A\TestClass[] =3D './path/to/TestClass.php' ; A wildcard can be used if there is a desire to pack multiple symbols together ; Note the path with the most specific match wins here, so \A\foo() will invoke the autoload below, ; but \A\TestClass or \A\B\Cat will trigger their respective definitions above. A\* =3D './path/to/A/Namespaces/functions.php' ; A path fragment can be used, in which case PSR-4 will be used to map the rest of the symbol to the filename. ; Pay attention to the direction of the slash at the tail - if the symbol key has this the value MUST also have this. B/ =3D './path/to/B/' ; A package is declared with a @ and maps the package namespace to its autoload file. ; If the package name here doesn't match what the package calls itself then the symbol ; given here takes precedence, acting as an alias. @C =3D './path/to/C/autoload.ini' ; An import into a package can be done like so ; Twig will load into \C\Twig and that use will need to be used by any code outside the C package. @C\Twig/ =3D './path/to/Twig/' ; The same library can be loaded into a different package, but a symbolic link is used internally in the engine to optimize @D\Twig/ =3D './path/to/Twig/' ; Nothing stops a different package from loading a different version now. @E\Twig/ =3D './path/to/Twig/Version4/' ; Modules are loaded with require_module but their maps work the same. [modules] And, honestly, I think that's it. This autoloader has some tricks up its sleeve a userland autoloader does not 1) Can deal with functions and constants. 2) Can deal with different versions of the same package being loaded. 3) Should be able to run faster than its equivalent userland code. As can be inferred from the above, a full autoload map can get complex in a hurry. However, it is also meant to be created by Composer or another package manager at some point. The advantage is a project like WordPress can ship with this autoload map and not require the end user to install composer unless they want to create their own. Any plugins can register their own autoloaders to handle their needs. --000000000000fdf62c061c83a899 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


=
On Fri, Jul 5, 2024 at 1:29=E2=80=AFA= M Mike Schinkel <mike@newclarity.= net> wrote:
On Jul 4, 2024, at 9:16 PM, Michael Morris <tendoaki@gmail.com> wrote:
On Wed, Jul 3, 2024 at 11:11=E2=80=AFPM Mike Schinkel <mike@newclarity.net&g= t; wrote:
So I&#= 39;ve had more time to mull this over, and some research, and I think I hav= e an approach.

First, instead of 'impor= t', use 'require_module'.=C2=A0 The parsing rules for require_m= odule differ from require how the file is parsed, a subject for another tim= e.=C2=A0 Also, it's parallel to what is to follow.

+1=C2=A0

Speaking of new = functions, let's start with these

=C2=A0 spl_s= et_include_ini_map('importmap.ini');
=C2=A0 spl_set_include_json= _map('importmap.json")
Those are a mouthful!=C2=A0

The json = file is pretty much identical to the JavaScript importmaps. The ini file lo= oks like this

=C2=A0 root= =3D "/absolute/path/to/application/root"

=C2=A0 [import= s]
=C2=A0 square =3D "./path/to/square.js"
=C2=A0 circle = =3D "./path/to/circle.js"
=C2=A0 other/ =3D "./path/to/ot= her/"

=C2=A0 [scopes]
=C2=A0 \A[square] =3D './path/to/s= quare/in/namespace/A/a.js'
I assume rather than `.js` you mean `.php` files in your example?

Also, I am not following how these imports and scop= es will relate to the actual PHP code that would be affected/using packages= .

Whichever format is used is a matter of personal preference= . The file can be, and likely should be, written by composer or some future= package manager.

Part of me likes the flexibi= lity of two formats. The other more pragmatic part of me says stick with on= e format for fewer related bugs and to reduce the effort to support it for = internal code and by 3rd parties.

Unless it can be= fully cached by opcache I would think it would need to be the format that = can be parsed the fastest, which could be binary like a Protobuf file.

The root attribute in the map = sets the root for all relative paths given in the map.

Are you saying that a publisher of a pa= ckage would need to write the absolute path to their `importmap.*` file. Ho= w will that work?=C2=A0 Even for a bespoke app Composer may not have enough= access to the server to know this, and 3rd party packages will definitely = not know it for their users. At least I don't think so.

=
Also, at this point trying to keep track of all your ideas is impossib= le, at least for me. Have you reconsidered putting it in a repo or at least= a Gist yet so it is easier to see the scope of your current ideas about pa= ckages?


I'm = getting there. I'm trying to boil things down at this point to somethin= g that can be put into such.

I went to sleep think= ing about this post, on import maps in general and how Composer works, spec= ifically when you use a class map instead of the PSR-0 or PSR-4 schemes.=C2= =A0 In that mode, Composer does pretty much what I've described.=C2=A0 = This got me to thinking, could setting an import map be an alternative to s= etting an autoload function?=C2=A0 Would having the PHP runtime load the fi= le be faster than mucking with some userland code to do the same? And would= the engine be able to do anything that can't be done in userland?=C2= =A0 I think so.

So first, I agree that supporting = two formats, while convenient, increases the maintenance burden, so let'= ;s just go with ini.=C2=A0 As far as the installing function - a better nam= e is this.

spl_autoload_map( string $filepath );

This function will register an autoload map wrapped= with an internal autoloader to work with it.=C2=A0 If called multiple time= s the maps will resolve in the order they are called.=C2=A0 If called along= with the existing spl_autoload_register function then the maps and autoloa= d functions will be used in the order of their declaration. Packages are ex= pected to carry their own autoload maps.=C2=A0 Autoload maps can only be lo= aded once - attempts to load the same map multiple times will raise a E_USE= R_WARNING

The contents of the file along with comm= ents as to what they do.

= =C2=A0 ; The root directive affects the relative paths in the map.=C2=A0 If= set the location specified becomes
=C2=A0 ; the root. If not set all relative paths are relative to THIS FI= LE.
=C2=A0 ;root =3D '/some/p= ath'

=C2=A0 ; If a package is declared, that is the root = namespace for all the includes that follow.
=C2=A0 ; As this example is for a root autoloader it is commente= d out, as the root autoload function of
=C2=A0 ; an app doesn't need a package name.
=C2=A0 ;package =3D

= =C2=A0 ; A map relates symbols to files. This one = is for the existing include/require system. Actual
=C2=A0 ; file loading is performed by require_once.
=C2=A0 [includes]
=C2=A0 A\B\Cat =3D './path/to/Cat.php'=
=C2=A0=C2=A0
=C2=A0 ; A symbol can invoke the loading o= f multiple files. This will be useful if the package manager that
=C2=A0 ; prepares this file determines tha= t a polyfill will be needed. Files will be loaded in order given.
=C2=A0 A\TestClass[] =3D './path/to/po= lyfill.php'
=C2=A0 A\TestClas= s[] =3D './path/to/TestClass.php'

=C2=A0 ; A wildcard= can be used if there is a desire to pack multiple symbols together<= /div>
=C2=A0 ; Note the path with the most spe= cific match wins here, so \A\foo() will invoke the autoload below,
=C2=A0 ; but \A\TestClass or \A\B\Cat wil= l trigger their respective definitions above.
=C2=A0 A\* =3D './path/to/A/Namespaces/functions.php'= ;

=C2=A0 ; A path fragment can be used, in which case PSR-4 w= ill be used to map the rest of the symbol to the filename.
=C2=A0 ; Pay attention to the direction of the sl= ash at the tail - if the symbol key has this the value MUST also have this.=
=C2=A0 B/ =3D './path/to/B/&= #39;

=C2=A0 ; A package is declared with a=C2=A0@ and maps th= e package namespace to its autoload file.
=C2=A0 ; If the package name here doesn't match what the packa= ge calls itself then the symbol
= =C2=A0 ; given here takes precedence, acting as an alias.
= =C2=A0=C2=A0@C =3D './path/to/C/autoload.ini&#= 39;

=C2=A0 ; An import into a package can be done like so
=C2=A0 ; Twig will load= into \C\Twig and that use will need to be used by any code outside the C p= ackage.
=C2=A0=C2=A0@C\Twig/ =3D './path/to/Twig/'
<= div>
=C2=A0 ; The same library can be loaded into a different package, but a sy= mbolic link is used internally in the engine to optimize
<= font face=3D"monospace">=C2=A0=C2=A0@D\Twig/ =3D './path/to/Twig/'<= /font>

=C2=A0 ; Nothing stops a different package from loading a di= fferent version now.
=C2=A0=C2=A0= @E\Twig/ =3D './path/to/Twig/Version4/'

=C2=A0 ; Modu= les are loaded with require_module but their maps work the same.
=C2=A0 [modules]



And, honestly, I think that's it. T= his autoloader has some tricks up its sleeve a userland autoloader does not=
1) Can deal with functions and constants.
2) Can deal = with different versions of the same package being loaded.
3) Shou= ld be able to run faster than its equivalent userland code.

<= /div>
As can be inferred from the above, a full autoload map can get co= mplex in a hurry.=C2=A0 However, it is also meant to be created by Composer= or another package manager at some point.=C2=A0 The advantage is a project= like WordPress can ship with this autoload map and not require the end use= r to install composer unless they want to create their own.=C2=A0 Any plugi= ns can register their own autoloaders to handle their needs.

=
--000000000000fdf62c061c83a899--