Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:124118 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 8B9221AD8F6 for ; Sun, 30 Jun 2024 23:13:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1719789271; bh=d1WUDJwePQCbiAl6K8eTX4wmDThqdPxb0dsiSEnd0Qs=; h=References:In-Reply-To:From:Date:Subject:To:From; b=DKr25gfepTnFCcNHUC+akwQbozJvaVOzXc6Zesx00Ex2tKn3y8fuhez37F6EGwVQR pH9ppODA9m/XJrWUGCNxwSIQswu2gY7gKA1rBcEcUzUu0qQWva+D/Fo2Z+xdsLgjVd 47oSrDhKpnFnT5LYDZ9KDJZo7Fukn+kWzFj2LIT1OXN/F/Hp2mukOEGUKBm0xjYPan mfOaZRY+8dEbAYQmAtFmX2lj60XWE1kyT3mXqLrL1zR8uXJNkyUi5DuQI/SW7wWebC N1ZlGO3v+rEySSVvIW3NpSLShczet/RtjNpU4W7/SYVlq7T1Wh/V6VTAnJ2torizQU yzqo0g1mJjotA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 43F2A180830 for ; Sun, 30 Jun 2024 23:14:27 +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-qv1-f42.google.com (mail-qv1-f42.google.com [209.85.219.42]) (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, 30 Jun 2024 23:14:24 +0000 (UTC) Received: by mail-qv1-f42.google.com with SMTP id 6a1803df08f44-6b5834b3a94so18274716d6.2 for ; Sun, 30 Jun 2024 16:13:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1719789183; x=1720393983; 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=WQmHeOPFm4C/7fPIOYaa/r5PMePFcohv2NIHkPaSCck=; b=i6EczHyNs3iy+mb8O9U8M+tXzXKWUVoCsEc/Vv8BTh+bD88oIJpr093qBnb3hqbXCJ sKeo0EC2aeTebBEr67tjEqdNcQdPI//Q2G1MpWkbX3xoBERUDdNmawPRqE5naULfQ+lU 09Z/6N79+eIqr8hb8y6qFNoqMAR+KFEybx/N42WTecjwVLBMkVWoRVYHNLyrQyiDGwmJ ZhfOPki0eOuDQqGPoFzLKxvheHDcMZ0OXDVGD54qNRoQdfGfvRa311XlMbZZE8WdBOqD voJzNylQ0Y3OuvHkZifKaX4PghPBcpBrkbBkAXGDbgRwbnef4TtYljclByKapf68+JuV 5MWw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1719789183; x=1720393983; 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=WQmHeOPFm4C/7fPIOYaa/r5PMePFcohv2NIHkPaSCck=; b=MsOOcc0AVrThiUtGLck4r9Hx9+hV2q6jacXw/10h1MxpiEkoALw/ZYfg3moojgriuo 9/R1I7GVBowY8FQIx0wWPBCYoaYaacxfvtXQdk1miInAeWgNuk6U7GW2Cjqr7nzbGJ0S GcvPDf743bpAqcVj98Qk/yM3HDfSW8ik50IPJ1lsbTqP99hPKdhq4ftVNpYTsMq8mzwN 8euZjx8Q+/KGqkQdyfE4opioU59is46+jmNx0tauCV6ArgH4abcLjRqCFt3lXhea7+D7 ykiRkfDObHY/hnUm1K95j1ph3ZrSr0maYERW7HFtaQ1vKkE5IpSnCkRm6UQE/tRYL0Qk AMmw== X-Gm-Message-State: AOJu0YzkSKDo+V7KCs4x2yhEmJtdSso4zF893iNYH7R9HuZqHS+820kL cwJIHA6MIkZO0tEeuM967c22/B0XMhJFQUXNC4ePGk2B+Kz3t/9Vh1XYeEBkPuNy54v5Qv9WnQL gQPu2UjawoPGF7GQEnwD/qFkvbgCVP2nt X-Google-Smtp-Source: AGHT+IGR+boGnjrTucNR6D5ddzF/nyYkGrcDSyA1WuYeEUnOPGM27nds03WN5L1/zXIwglL+73uolMcOkINkkFxYFYE= X-Received: by 2002:a05:6214:f6e:b0:6b5:a4c6:4b3b with SMTP id 6a1803df08f44-6b5b71ccbeemr51108936d6.54.1719789182889; Sun, 30 Jun 2024 16:13:02 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 References: <1917CF7C-26D8-4DBE-B05C-5AA650AC6C9F@rwec.co.uk> <551cd5b0-1c00-4818-a9ca-97f6b7e8c3dc@app.fastmail.com> <39B496F8-062E-4848-9B3B-529BE8D3415A@newclarity.net> <856F4F70-DC81-4098-82DD-5F6D47CDF3F0@newclarity.net> In-Reply-To: Date: Sun, 30 Jun 2024 19:12:50 -0400 Message-ID: Subject: [PHP-DEV] Packages Iteration 3: was Re: [PHP-DEV] [Initial Feedback] PHP User Modules - An Adaptation of ES6 from JavaScript To: PHP internals Content-Type: multipart/alternative; boundary="00000000000055b45f061c239fcd" From: tendoaki@gmail.com (Michael Morris) --00000000000055b45f061c239fcd Content-Type: text/plain; charset="UTF-8" First off, in 10 years of using gmail I've never had it lose an email. Well, it happened after I spent 4 hours on this. So, this is sorta iteration 4. I'll type this up in Visual Studio code and then paste to gmail. The Wordpress discussion about composer and the decision not to use it keys in the features a package management system must meet. These are * Command Line should not be required * Plugins using version X of a package should not be affected by plugins using version Y * Install and maintenance of the site should remain possible from the browser alone. * Backwards compatibility must be maintained. A core PHP package management system should be a revision of what's come before that doesn't disturb what has come before. PHP packages are as follows: * Extensions, written in C++ * PECL Libraries, which I believe can be in PHP or C, but are server-wide * Phar archives * Composer libraries, which are always in PHP and leverage namespaces, PSR-4 convention and the autoload system. Some of my prior discussions have been about what I'd like to see in a new module system, but for scope, clarity, and sanity reasons I'm going to set that aside. (Not to mention some of the more controversial pieces have been there) Within the package management system there is a single new keyword - import. I'll go into details on it in a bit but suffice to say its behavior is different from include/require. In this schema a PHP application is a collection of packages. Existing PHP code that does not use the import statement or the special directories mentioned below will not invoke anything discussed on this page and will not need to change in any way. Applications The application is the root package. It is the package that imports to the root namespace. When PHP is asked to parse a file it will look for a `.php-packages` folder, first in the current working directory then in parent directories. If it doesn't find one, business as usual. If we do find one we follow its directives about setting up an application environment. The `.php-packages` folder is where PHP will put package related code for the application at hand. Code written explicitly for these changes will also put their package related files there - composer's vendor directory, composer.json, composer.lock, and so on - rather than putting those files in the site root. The folder is hidden to prevent web servers like nginx or apache from serving the files directly in any way. The .php-packages directory will have a configuration file called `php.mod`. This tells the parser: * How to initialize the application * What autoloaders are to be used * How to resolve import Let's look at what such a file might look like for Drupal. For the moment I'm going to use go.mod's syntax. The final syntax to be used, be it ini, yaml, toml, json, is a discussion for another time. The part to focus in on here is what type of information do we need. package Drupal php 10 registry //packagist.org/packages composer init ( composer install ) require ( ./vendor/autoload.php ) imports ( //getcomposer.org/composer.phar ) The directives do the following: * package sets the name of the package if it is imported. Sort of irrelevant here, but present for consistency * registry sets up the default registry for the import statement and the loader used to install packages * init is the command(s) to run before the application is started for the first time. * require is the file(s) to require before running any file in the application * imports are the imports the package needs, in this case the composer.phar to load composer in locally. Now, given the popularity of composer some of these directives likely could be put in as logical defines, particularly the init, require and imports directives just being put in place if composer is selected as a loader. I don't rule out the possibility of a competitor to composer showing up one day though, as yarn was introduced as an alternative to npm. If this theoretical version of Drupal moves its composer.json and composer.lock files into `.php-packages` then the autoloader doesn't have to be required in the index.php file. Also, the application can be started without running `composer install` Import statement Given the Drupal application package in the previous section, we can have an extension file call out its dependencies in code rather than in config. import "twig/twig" But granted, there's not much point to this since Drupal already uses Twig. But suppose for the sake of argument that Symfony releases a Twig 4 with some major BC breaks, and we're working on a Drupal extension that wants to use the new features of that Twig before Drupal itself upgrades Twig in core. Well, now we can do this import "twig/twig ^4.0" as NewTwig Note that we have to mount this package off the root using the alias syntax above. If the new package isn't written with this system in mind then we'll end up having NewTwig prefixed on the normal namespace path which would end up looking like this use NewTwig\Twig\Environment However, if this new twig has a `php-mod` file then the name of the top level namespace must be put there, and all the other files do not have to call out that namespace at their top. This allows the alias to plug in more seamlessly allowing for this use statement use NewTwig\Environment Again, running two versions of the same package is not ideal, but sometimes it's unavoidable. Especially in large ecosystems like WordPress. Imported packages run on their own request thread (I think that's the best way - I'm sure the guys working on the egine know best). They don't see or affect anything outside themselves. They don't see global variables or even the superglobals. Namespace resolution for them is - touchy. We could do it like this: A symbol starting without a \ resolves locally, then goes up the chain till it hits the application root. This is most similar to the current namespace system, but it allows for hidden dependencies and frankly, that worries me. I'm more inclined to isolate package so that if they want to use something they need to import it for themselves even if the hosting application already has the lib. This means namespace resolution in a package stops at the root of the package. We end up with something like this namespace MyExtension import "twig/twig ^3.0" use \Twig\Environment The package manager should be able to provide this without needing to download the package twice. Note also in this import that we specify we want version 3 which we've tested our Extension with. If that matches the App, great! Only one copy of the code needed. If it doesn't, it's suboptimal but it will run. As mentioned above, import also needs to be able to load extensions. Currently extensions are locked into PHP - they can't advance at different rates. This has led to several extension improvements getting abandoned over BC concerns. However, this would be nice import "ext://mysql ^2.0" Architecturally this would allow the PHP suite to move to a more mono-repo style with the various extensions having defaults for the current PHP distribution and newer versions available. It would also stop a repeat of having to have both mysql and mysqli functions loaded at the same time. This is enough to chew on for now. I'll take notes from the conversation that follows and iterate again. --00000000000055b45f061c239fcd Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
First off, in 10 years of using gmail I've never had i= t lose an email. Well, it happened after I spent 4 hours on this.=C2=A0 So,= this is sorta iteration 4.=C2=A0 I'll type this up in Visual Studio co= de and then paste to gmail.

The Wordpress discussion about composer = and the decision not to use it keys in the features a package management sy= stem must meet. These are

* Command Line should not be required
*= Plugins using version X of a package should not be affected by plugins usi= ng version Y
* Install and maintenance of the site should remain possibl= e from the browser alone.
* Backwards compatibility must be maintained.<= br>
A core PHP package management system should be a revision of what= 9;s come before that doesn't disturb what has come before. PHP packages= are as follows:

* Extensions, written in C++
* PECL Libraries, w= hich I believe can be in PHP or C, but are server-wide
* Phar archives* Composer libraries, which are always in PHP and leverage namespaces, PS= R-4 convention and the autoload system.

Some of my prior discussions= have been about what I'd like to see in a new module system, but for s= cope, clarity, and sanity reasons I'm going to set that aside. (Not to = mention some of the more controversial pieces have been there)

Withi= n the package management system there is a single new keyword - import. I&#= 39;ll go into details on it in a bit but suffice to say its behavior is dif= ferent from include/require.

In this schema a PHP application is a c= ollection=C2=A0of packages.=C2=A0 Existing PHP code that does not use the i= mport statement or the special directories mentioned below will not invoke = anything discussed on this page and will not need to change in any way.
=

Applications

The application is the root package. It is the = package that imports to the root namespace. When PHP is asked to parse a fi= le it will look for a `.php-packages` folder, first in the current working = directory then in parent directories.=C2=A0 If it doesn't find one, bus= iness as usual.=C2=A0 If we do find one we follow its directives about sett= ing up an application environment.

The `.php-packages` folder is whe= re PHP will put package related code for the application at hand.=C2=A0 Cod= e written explicitly for these changes will also put their package related = files there - composer's vendor directory, composer.json, composer.lock= , and so on - rather than putting those files in the site root. The folder = is hidden to prevent web servers like nginx or apache from serving the file= s directly in any way.

The .php-packages directory will have a confi= guration file called `php.mod`.=C2=A0 This tells the parser:

* How t= o initialize the application
* What autoloaders are to be used
* How = to resolve import

Let's look at what such a file might look like= for Drupal. For the moment I'm going to use go.mod's syntax. The f= inal syntax to be used, be it ini, yaml, toml, json, is a discussion for an= other time. The part to focus in on here is what type of information do we = need.

=C2=A0 package Drupal

=C2=A0 p= hp 10

=C2=A0 registry //pa= ckagist.org/packages composer

=C2=A0 init (
=C2=A0 =C2=A0 com= poser install
=C2=A0 )

=C2=A0 require (
=C2=A0 =C2=A0 ./vendor= /autoload.php
=C2=A0 )

=C2=A0 imports (
=C2=A0 =C2=A0 //getcomposer.org/composer.phar
=C2=A0 )

The directives do the following:
* package s= ets the name of the package if it is imported. Sort of irrelevant here, but= present for consistency
* registry sets up the default registry for the= import statement and the loader used to install packages
* init is the = command(s) to run before the application is started for the first time.
= * require is the file(s) to require before running any file in the applicat= ion
* imports are the imports the package needs, in this case the compos= er.phar to load composer in locally.

Now, given the popularity of co= mposer some of these directives likely could be put in as logical defines, = particularly the init, require and imports directives just being put in pla= ce if composer is selected as a loader.=C2=A0 I don't rule out the poss= ibility of a competitor to composer showing up one day though, as yarn was = introduced as an alternative to npm.

If this theoretical version of = Drupal moves its composer.json and composer.lock files into `.php-packages`= then the autoloader doesn't have to be required in the index.php file.= =C2=A0 Also, the application can be started without running `composer insta= ll`


Import statement
Given the Drupal application package in = the previous section, we can have an extension file call out its dependenci= es in code rather than in config.

=C2=A0 im= port "twig/twig"

But granted, there's not much = point to this since Drupal already uses Twig.=C2=A0 But suppose for the sak= e of argument that Symfony releases a Twig 4 with some major BC breaks, and= we're working on a Drupal extension that wants to use the new features= of that Twig before Drupal itself upgrades Twig in core. Well, now we can = do this

=C2=A0 import "twig/twig ^4.0&= quot; as NewTwig

Note that we have to mount this package off = the root using the alias syntax above.=C2=A0 If the new package isn't w= ritten with this system in mind then we'll end up having NewTwig prefix= ed on the normal namespace path which would end up looking like this
=C2=A0 use NewTwig\Twig\Environment
However, if this new twig has a `php-mod` file then the name of the top le= vel namespace must be put there, and all the other files do not have to cal= l out that namespace at their top. This allows the alias to plug in more se= amlessly allowing for this use statement

= =C2=A0 use NewTwig\Environment

Again, running two versions of= the same package is not ideal, but sometimes it's unavoidable. Especia= lly in large ecosystems like WordPress.

Imported packages run on the= ir own request thread (I think that's the best way - I'm sure the g= uys working on the=C2=A0egine=C2=A0know best). They don't see or affect= anything outside themselves. They don't see global variables or even t= he superglobals. Namespace resolution for them is - touchy.

We could= do it like this: A symbol starting without a \ resolves locally, then goes= up the chain till it hits the application root. This is most similar to th= e current namespace system, but it allows for hidden dependencies and frank= ly, that worries me.

I'm more inclined to isolate package so tha= t if they want to use something they need to import it for themselves even = if the hosting application already has the lib. This means namespace resolu= tion in a package stops at the root of the package. We end up with somethin= g like this

=C2=A0 namespace MyExtension=C2=A0 import "twig/twig ^3.0"
=C2=A0 use \Twig\Environment

The package manager should be able to provide this without nee= ding to download the package twice. Note also in this import that we specif= y we want version 3 which we've tested our Extension with.=C2=A0 If tha= t matches the App, great!=C2=A0 Only one copy of the code needed. If it doe= sn't, it's suboptimal but it will run.

As mentioned above, i= mport also needs to be able to load extensions. Currently extensions are lo= cked into PHP - they can't advance at different rates. This has led to = several extension improvements getting abandoned over BC concerns. However,= this would be nice

=C2=A0 import "ext= ://mysql ^2.0"

Architecturally this would allow the PHP = suite to move to a more mono-repo style with the various extensions having = defaults for the current PHP distribution and newer versions available. It = would also stop a repeat of having to have both mysql and mysqli functions = loaded at the same time.=C2=A0=C2=A0

This is enough = to chew on for now.=C2=A0 I'll take notes from the conversation that fo= llows and iterate again.
--00000000000055b45f061c239fcd--