Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:124240 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 2D3C31A009C for ; Sat, 6 Jul 2024 06:12:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1720246424; bh=XCFRpnIgaye4vTxnGgbxYYm38KEV3uEiE/O6NytCTac=; h=From:Subject:Date:In-Reply-To:Cc:To:References:From; b=oE95/TBIsMq0KmK4qSFtrE/xrYS2iMrqlK/XL+Osxfts9kH5Ktcd+Ykx7nk7r2sPK kklqnkei4qbji/eRYA2ErfX9fOOdDnTRb8Ww16fojUC7bEAf3jpwap/G321CyViaSj VjeGYVoCXnXgFHQaqoT61n1FeQ+tYG5bRiH/BYxIPCfgmfRzbD9Mx9zoomfk6ff2i7 B+H7Sf5ZLz5pjpQA0Rh46ILGVEqbkySXfigcOuepbPEHS4WKo4tHAYWd7wtupn3aDi Wu3XOxXsr4Nd22BZVOmZBPo4UZP4ntO9u0O877QjH4CGud3YZTpnaeZK20OzVxvo3b eBxHumw5rPEug== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id D46D81801E0 for ; Sat, 6 Jul 2024 06:13:42 +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.8 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DMARC_MISSING,HTML_MESSAGE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_NONE,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-yw1-f174.google.com (mail-yw1-f174.google.com [209.85.128.174]) (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 ; Sat, 6 Jul 2024 06:13:42 +0000 (UTC) Received: by mail-yw1-f174.google.com with SMTP id 00721157ae682-65011d9bd75so19249747b3.2 for ; Fri, 05 Jul 2024 23:12:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=newclarity-net.20230601.gappssmtp.com; s=20230601; t=1720246338; x=1720851138; darn=lists.php.net; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:from:to:cc:subject:date:message-id:reply-to; bh=SoL8rdcFherbuMKHZraJjt+fKvvl1f4LWR3OnA8sOts=; b=1vuiQuYZWzRWCynpKi5WUTfI8cCNAX8MVImMjpJN3Mn7JbwClLaMUf18d+68d9gXwh g9fZpNeiHZDp1CbBO2tfF/S9kscr0fp50aG8c7P1qmG3AIRyBE3PasyPtK3ygl3OyT2g Ajg7j1EkPS64LHeffrLvnVZrlaDYsyjzxmV3O7xbvFryf8UyLcwABSrjkoULGTz7JdPr YPRndGOUVHftkmZeHnuqGBQTdNAzKb73DcWptwbGD/IBIYjDXdJwR/bi/xBkbBxVrrfi R9BpLGbs0C6IWHgCiMTsApMGBO2ICGaiL1ZdPqUPGsfYgKqaYAuOQTWmFPTVi/2zcDk0 iQNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720246338; x=1720851138; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=SoL8rdcFherbuMKHZraJjt+fKvvl1f4LWR3OnA8sOts=; b=iNl514nBHpWjdkRjPvP4KTBresJ6dhECPsjo6EPS9W3wRT+xMXFxchGoPm1huH8QSe hAOwLwwIweSawOKURBocHvZBUVI0u/gl6z0MxcmnBfUz1hZjwc+0NpD2EspksjKGTBve r1YJ/cDB+Hvluv1if0FpY1u42cHdpfLtSFFsajpUUGiiJf5Y4KaGybOy+pY228uJGJXo OZIacIAVvXX3X881Ivy4khYCcWFQ2NNxOyUAe4zSP6EUMM1hxO+O+bDC/+ORD/rBhGeu WaTWQ3XTK7KBlf2+u2zz7hRvcUfYa900TXdyt6Rk+ZOVyBkBdbFY3k3+3e6AQwmGf0dt nXpQ== X-Gm-Message-State: AOJu0Yyii5pLs9GVTCOlxQ0CA719QRm2EnvilSYxFZ1S0bVTXO2sD1US nubXy8+px5izYxJbS4d/IG78FWydSZyHoi+Yi3TOJ4kE6zR4wGGyXolPgl6tF6k= X-Google-Smtp-Source: AGHT+IGiK+7YH1QXELGA2OY/BOZXUvDK8g+idGzdgI5Msz541s+bSXmsTfoeBpSsLFZYaEBxN/4dRA== X-Received: by 2002:a81:430b:0:b0:643:d92c:697a with SMTP id 00721157ae682-652d7870858mr64629307b3.33.1720246337937; Fri, 05 Jul 2024 23:12:17 -0700 (PDT) Received: from smtpclient.apple (c-98-252-216-111.hsd1.ga.comcast.net. [98.252.216.111]) by smtp.gmail.com with ESMTPSA id 00721157ae682-65332e8bb6csm6929467b3.112.2024.07.05.23.12.16 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 05 Jul 2024 23:12:16 -0700 (PDT) Message-ID: Content-Type: multipart/alternative; boundary="Apple-Mail=_3E631502-2DE9-4CD7-878A-A0EC5B62099F" Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3696.120.41.1.8\)) Subject: Re: [PHP-DEV] [PHP-Dev] Versioned Packagers (Iteration IV) Date: Sat, 6 Jul 2024 02:12:15 -0400 In-Reply-To: Cc: PHP internals To: Michael Morris 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> X-Mailer: Apple Mail (2.3696.120.41.1.8) From: mike@newclarity.net (Mike Schinkel) --Apple-Mail=_3E631502-2DE9-4CD7-878A-A0EC5B62099F Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On Jul 5, 2024, at 1:47 PM, Michael Morris wrote: > 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. I very much like this direction of thought. For context, when I worked with WordPress for about a decade I only ever = used only Composer for websites but never for my own plugins, and I = almost never used namespaces nor PSR-4 autoloaders for anything except = when a plugin used them. I almost exclusively used naming convensions = for "namespacing" and classmaps for autoloading.=20 Why? Was it because I was a "bad" programmer? No, it was because when = in Rome, you do as the Romans do. And also because when I tried to use = Composer and PSR-4 I was always fighting when them to do things in the = way that worked best for WordPress. Or to use a more modern analogy to PHP and WordPress, even though you = may be landlocked by the country of Italy, if you are within the borders = of Vatican City you follow the laws and conventions of Vatican City when = they conflict with those of Italy. > 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. Obviously I agree with having only one format, but not sure I concur = with the use of .ini. However, me debating against `.ini` would be me = bikeshedding and thus I will demure here. > spl_autoload_map( string $filepath ); Adding an `spl_autoload_map()` function and feature really resonates = with me. As I said, I (almost?) always used class maps with WordPress = so if I were to build another WordPress site with a future PHP that made = an `spl_autoload_map()` available, I would TOTALLY use it. Reading this however caused me to ponder things certain people has said = recently =E2=80=94 and many people have said for years on this list =E2=80= =94 and I think I am recognizing something that I have always known but = never put the pieces together before. Many (most?) people on PHP Internals view WordPress coding standards as = bad and some even view addressing WordPress developers needs as bad for = PHP. And in general I concur that those people are reasonably justified = in their belief WordPress' coding standards are not the standards that = PHP developer who want to do professional level software engineering = should aspire.=20 And since many (most?) PHP Internals members generally do not experience = the issues that WordPress developers have they do not recognize that = they are issues; IOW, "out of sight, out of mind."=20 I also think some list members tend to dismiss WordPress developers = pains as unimportant and/or think that addressing those pains have will = harm PHP.=20 (BTW, I recently had a dialog off-list with someone who wrote in an = email that "Wordpress is an exception, but nobody these days treats = WordPress as a valid example to do anything. It is an ancient piece of = legacy code that has no bearing on modern situation and it's their = problem to deal with." So I am not just erecting a straw man here.) But I think what most may not consciously recognize is that WordPress is = a different type of web app than an app build using Symfony or Laravel = and deployed by its developers, or by some other professional developer.=20= WordPress differs from the apps many (most?) developers on PHP Internals = work with in the following way: WordPress =3D User-managed app Most =3D Developer-managed apps In a Developer-Managed app developers choose which 3rd party = functionality will be incorporated into their sites whereas with a = User-managed app users choose which 3rd party functionality will be = incorporated into their site. And that is the KEY difference.=20 So I am wondering if we can get people on this PHP Internals list who = dismiss the needs of WordPress developer BECAUSE it is WordPress to = recognize that User-Managed apps ARE a class of PHP applications have = needs that deserve to be addressed? =20 Two (2) unmet needs of User-Managed apps that "standard" PHP currently = does not address come to mind: User-managed apps needs to be able to handle both: 1. User-added add-ons ("plugins" in WordPress, "modules" in Drupal) that = have conflicting dependencies, and 2. Add-on directory structures that do not follow a PSR-4 directory = hierarchy. As for #2, even if those apps could rearchitect their existing directory = structure they cannot realistically be expected to do with because of = the huge BC issues their users would experience.=20 And newly created User-managed apps may still find that a PSR-4 = directory structure is not in the best interest of their project or = their users. To elaborate, PSR-4 generally assumes that ALL code goes = into ONE hierarchy and that any and all code that will be autoload gets = placed in that hierarchy. But with add-ons it makes a lot more sense to have the entire add-on = contained in its own add-on directory. This is exactly where PSR-4 = breaks down with respect to User-managed apps. Sure, you can have multiple PSR-4 autoloader root directories, but that = does not scale well to websites with a large number of add-ons as many = WordPress sites I worked on used. Some had over 100 plugins. With a = hierarchy of autoloader maps that Michael Morris is proposing WordPress = could collect up all the maps and create one map every time a plugin is = added, updated or deleted. Based on my above labeled epiphany, I think MOST of what you recently = proposed could address those unmet needs of User-managed apps written in = PHP, with a few caveats and improvements. Read on. > ; 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/' It is not clear to me what a trailing slash means, and especially why it = is needed on the left-hand side? And why slash here when namespaces use = backslash? Also, as someone raised on DOS and then Windows only "converting" in = 2009, I still get confused in *nix when to use a trailing slash and when = to not, so this trailing slash worries me, if only for that reason = alone. > ; 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' Using the `@` here feels cryptic, and hard to discover and remember. I think this would be infinitely easier to follow if packages were just = included in a `[packages]` section. Your comments also confuse me a bit. =20 Is this saying that your hypothetical app =E2=80=94 which you stated = this `.ini` file is for =E2=80=94 needs to use a package named `C` use = "definition" is located at './path/to/C/autoload.ini' then it would use = this syntax, and that in the app its components would be accessed at = namespace `\C`? And I were to have: @Foo\Bar\Baz =3D './path/to/Foo/Bar/Baz/autoload.ini' Then in the app its components would be accessed at namespace = `\Foo\Bar\Baz`? I think if your examples used hypothetical "real-world" symbols it would = be easier to follow than A, B, C, D, etc. > ; 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/' >=20 > ; 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/' >=20 > ; Nothing stops a different package from loading a different version = now. > @E\Twig/ =3D './path/to/Twig/Version4/' Okay, this makes sense. OTOH, this is the part that of your proposal = that is incomplete for the needs of User-managed apps IMO. I think you are implying a necessary "best practice" that whenever any = PHP library, or package would include code they would need to prefix the = namespace of package when importing it and then when using it. Given an = org named ACME that released a library called Widgets then if it were to = use Twig it should import and use Twig like this (did I understand your = intent correctly?): @ACME\Widgets\Twig/ =3D './path/to/Twig/' And in PHP code?: use \ACME\Widgets\Twig; I think that would work well for newer libraries and packages authored = and used by developers of Developer-managed apps. OTOH I do not think it = would be sufficient for any existing libraries or frameworks, nor for = non-professional developers scratching their own itch on a User-managed = apps and then deciding to publish it for others to use (which happens a = lot with User-managed apps.) The problem would be that most (all?) of those would not be = namespace-prefixing Twig but instead using it directly. I believe you = need an ADDITIONAL `replace` sectionS that allowed an app/website = developer to indicate that namespace A should instead be replaced in = `use` statements and direct references with `B\A` for code that exists = in directory(s) `C` but not in directories `C\D` where `C` and `D` can = be globs. To illustrate I created a completely hypothetical `.ini` that the = WordPress plugin admin page could create any time a user would install = WordPress and any time the user would add/edit/delete plugins or themes = (I did try to modifying your A/B/C example but couldn't come up with = anything that could illustrate the use-case): [default] root =3D '/wp-content/' [includes] UpdraftPlus =3D './plugins/updraft-plus/index.php' # Uses Twig v4 Automattic\JetPack =3D './plugins/jetpack/jetpack.php' # Uses Twig Elementor =3D './plugins/elementor/elementor.php' # Uses Twig v4 [packages] Yoast\SEO =3D './plugins/yoast-seo/autoload.ini' # Uses Twig v4 as = Yoast\Twig WPForms =3D './plugins/wp-forms/autoload.ini' # Uses Twig as = WPForms\Twig [replace] Twig[UpdraftPlus] =3D 'Twig_edaf27eb' Twig[Elementor] =3D 'Twig_edaf27eb' In the above example `[packages]` are ones that have gotten religion and = have delivered a best-practices package where they have namespaced Twig. = We can ignore them for now as they follow your best-practices.=20 The `[includes]` are ones that have paid no attention to newer best = practice and/or simply have not been updated by their authors. They were = implemented to load and use Twig as simply `\Twig`. The `[replace]` section tells PHP that when `\Twig` is found included or = used within the `[includes]` files denoted by those namespaces = referenced such as `UpdraftPlus` it should instead use the namespace of = `\Twig_edaf27eb` (dynamically generated by WordPress), and the same goes = for any includes and uses by `Elementor`. My hypothetical design may not survive a fully-working implementation, = but I hope it illustrates that we need to: 1.) Handle those who are NOT following best practices, AND=20 2.) Alias namespaces when used IN ADDITION TO when imported. Of course if the code in any of the three plugins included expect the = namespaces to be exact via reflection then they would break, but I think = it would be a reasonable breakage as most plugins won't do this and most = plugins that break could either be updated by their authors or disabled = for installs on newer PHP by the WordPress plugin repo. BTW, Go uses `replace` in `go.mod` albeit as a compiled language its use = is not a one-to-one analogue to the example above. If you are interested = in seeing them in the wild here is what the use of `replace` looks like = for Kubernetes: = https://github.com/kubernetes/kubernetes/blob/master/go.mod#L227-L258 As an "optimization", WordPress could recognize that Twig and Twig4 are = being used not only by the includes but also by the packages and could = generate this optimization instead: [default] root =3D '/wp-content/' [includes] UpdraftPlus =3D './plugins/updraft-plus/index.php' # Uses Twig v4 Automattic\JetPack =3D './plugins/jetpack/jetpack.php' # Uses Twig Elementor =3D './plugins/elementor/elementor.php' # Uses Twig v4 [packages] Yoast\SEO =3D './plugins/yoast-seo/autoload.ini' # Uses Twig v4 as = Yoast\Twig WPForms =3D './plugins/wp-forms/autoload.ini' # Uses Twig as = WPForms\Twig [replace] Twig[UpdraftPlus] =3D 'Twig_edaf27eb' Twig[Elementor] =3D 'Twig_edaf27eb' Twig[Yoast\SEO] =3D 'Twig_edaf27eb' Twig[Automattic\JetPack] =3D 'Twig_2ba3f91f' Twig[WPForms] =3D 'Twig_2ba3f91f' As a further optimization, WordPress could reach into all the `.ini` = files recursively and create a SINGLE autoload map, but to do that we = would need an additional section: `[ignore]`:=20 [ignore] Yoast\SEO =3D './plugins/yoast-seo/autoload.ini' =20 WPForms =3D './plugins/wp-forms/autoload.ini' =20 The above assumes that WordPress already generated everything that was = needed to no longer need to load the autoload.ini files for either the = `Yoast\SEO` or `WPForms` namespaces and thus the ignore tells = `spl_autoload_map()` to ignore any calls to these `autoload.ini` files = if called later. (I would have created a complete example but at this = point I am too tired for that.) And lastly, because WordPress would need to generate this and having a = web app write to a file is a modern security no-no, then = `spl_autoload_map()` should accept multiple different valid values: spl_autoload_map( string|array|\PHP\AutoloadMap $map); 1. String would be the `.ini` file path 2. Array would be the format returned by parse_ini_file() for parsing an = applicable `.ini` file 3. \PHP\AutoloadMap could be a new class containing the required values = in object format. (Hopefully adding such a class as a third option would = not be controversial to the list members who criticize those developers = still wanting to use arrays as hash maps?) And that is about it for my feedback today. -Mike --Apple-Mail=_3E631502-2DE9-4CD7-878A-A0EC5B62099F Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8
On Jul 5, 2024, at 1:47 PM, Michael Morris = <tendoaki@gmail.com> wrote:
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.

I very much like this direction of = thought.

For context, when I worked = with WordPress for about a decade I only ever used only Composer for = websites but never for my own plugins, and I almost never used = namespaces nor PSR-4 autoloaders for anything except when a plugin used = them.  I almost exclusively used naming convensions for = "namespacing" and classmaps for autoloading. 

Why? Was it because I was a "bad" programmer? =  No, it was because when in Rome, you do as the Romans do. =  And also because when I tried to use Composer and PSR-4 I was = always fighting when them to do things in the way that worked best for = WordPress.

Or to use a more modern = analogy to PHP and WordPress, even though you may be landlocked by the = country of Italy, if you are within the borders of Vatican City you = follow the laws and conventions of Vatican City when they conflict with = those of Italy.

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.

Obviously I agree with having only one format, but not = sure I concur with the use of .ini. However, me debating against `.ini` = would be me bikeshedding and thus I will demure here.

spl_autoload_map( string $filepath = );

Adding an `spl_autoload_map()` function and = feature really resonates with me.  As I said, I (almost?) always = used class maps with WordPress so if I were to build another WordPress = site with a future PHP that made an `spl_autoload_map()` available, I = would TOTALLY use it.

<epiphany>

Reading this however caused me to ponder things = certain people has said recently =E2=80=94 and many people have said for = years on this list =E2=80=94 and I think I am recognizing something that = I have always known but never put the pieces together = before.

Many (most?) people on PHP = Internals view WordPress coding standards as bad and some even view = addressing WordPress developers needs as bad for PHP. And in general I = concur that those people are reasonably justified in their belief = WordPress' coding standards are not the standards that PHP developer who = want to do professional level software engineering should = aspire. 

And since many = (most?) PHP Internals members generally do = not experience the issues that WordPress developers have they = do not recognize that they are issues; IOW, "out of = sight, out of mind." 

I = also think some list members tend to dismiss WordPress developers = pains as unimportant and/or think that addressing those pains have will = harm PHP. 

(BTW, I recently had a dialog off-list with = someone who wrote in an email that "Wordpress is an = exception, but nobody these days treats WordPress as a valid example to = do anything. It is an ancient piece of legacy code that has no = bearing on modern situation and it's their problem to deal = with." So I am not just erecting a straw man = here.)

But I think what most may not = consciously recognize is that WordPress is a different = type of web app than an app build using Symfony or Laravel and = deployed by its developers, or by some other professional = developer. 

WordPress differs from the apps = many (most?) developers on PHP Internals work with in = the following way:

WordPress =3D User-managed app
Most =3D Developer-managed apps

In a Developer-Managed app developers choose which = 3rd party functionality will be incorporated into their sites whereas = with a User-managed app users choose which 3rd party = functionality will be incorporated into their site. And that is the KEY = difference. 

So I am wondering = if we can get people on this PHP Internals list who dismiss the needs of = WordPress developer BECAUSE it is WordPress to recognize = that User-Managed apps ARE a class of PHP applications have needs = that deserve to be addressed? =  

Two (2) unmet needs of User-Managed apps that "standard" PHP currently does not address come to = mind:

User-managed apps needs to be = able to handle both:

1. User-added add-ons ("plugins" in WordPress, "modules" in Drupal) that have = conflicting dependencies, and

2. Add-on directory structures that do not follow a PSR-4 = directory hierarchy.

As for #2, even = if those apps could rearchitect their existing directory structure they = cannot realistically be expected to do with because of the huge BC = issues their users would experience. 

And newly created User-managed apps may still find = that a PSR-4 directory structure is not in the best interest of their = project or their users. To elaborate, PSR-4 generally assumes that ALL = code goes into ONE hierarchy and that any and all code that will be = autoload gets placed in that hierarchy.

But with add-ons it makes a lot more sense to have = the entire add-on contained in its own add-on directory. This is exactly = where PSR-4 breaks down with respect to User-managed = apps.

Sure, you can have multiple = PSR-4 autoloader root directories, but that does not scale well to = websites with a large number of add-ons as many WordPress sites I worked = on used. Some had over 100 plugins.  With a hierarchy of autoloader = maps that Michael Morris is proposing WordPress could collect up all the = maps and create one map every time a plugin is added, updated or = deleted.

</epiphany>

Based on my above labeled epiphany, I think = MOST of what you recently proposed could address those unmet needs of = User-managed apps written in PHP, with a few caveats and improvements. =  Read on.

  ; 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/'

It is not clear to me what a trailing slash means, and = especially why it is needed on the left-hand side? And why slash here = when namespaces use backslash?

Also, = as someone raised on DOS and then Windows only "converting" in 2009, I = still get confused in *nix when to use a trailing slash and when to not, = so this trailing slash worries me, if only for that reason = alone.

  ; 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'

Using the `@` here feels cryptic, and hard to discover = and remember.

I think this would be = infinitely easier to follow if packages were just included in a = `[packages]` section.

Your = comments also confuse me a bit.  

Is this saying that your hypothetical app =E2=80=94 = which you stated this `.ini` file is for =E2=80=94 needs to use a = package named `C` use "definition" is located = at './path/to/C/autoload.ini' then it would use this syntax, and = that in the app its components would be accessed at namespace = `\C`?

And I were to = have:

@Foo\Bar\Baz =3D = './path/to/Foo/Bar/Baz/autoload.ini'

Then = in the app its components would be accessed at namespace = `\Foo\Bar\Baz`?

I think if your examples = used hypothetical "real-world" symbols it would be easier to follow than = A, B, C, D, etc.

  ; 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/'

Okay, this makes sense.  OTOH, this is the = part that of your proposal that is incomplete for the needs of = User-managed apps IMO.

I think you = are implying a necessary "best practice" that whenever any PHP library, = or package would include code they would need to prefix the namespace of = package when importing it and then when using it. Given an org named = ACME that released a library called Widgets then if it were to use Twig = it should import and use Twig like this (did I understand = your intent correctly?):

@ACME\Widgets\Twig/ =3D = './path/to/Twig/'

And in PHP = code?:

use = \ACME\Widgets\Twig;

I think that would work well for newer libraries = and packages authored and used by developers of Developer-managed apps. = OTOH I do not think it would be sufficient for any existing libraries or = frameworks, nor for non-professional developers scratching their own = itch on a User-managed apps and then deciding to publish it for others = to use (which happens a lot with User-managed = apps.)

The problem would be that = most (all?) of those would not be namespace-prefixing Twig but instead = using it directly. I believe you need an ADDITIONAL `replace` sectionS = that allowed an app/website developer to indicate that namespace A = should instead be replaced in `use` statements and direct references = with `B\A` for code that exists in directory(s) `C` but not in = directories `C\D` where `C` and `D` can be globs.

To illustrate I created a completely = hypothetical `.ini` that the WordPress plugin admin page could = create any time a user would install WordPress and any time the user = would add/edit/delete plugins or themes (I did try to = modifying your A/B/C example but couldn't come up with anything that = could illustrate the use-case):

[default]
root = =3D '/wp-content/'

[includes]
UpdraftPlus = =3D './plugins/updraft-plus/index.php' # Uses Twig v4
Automattic\JetPack =3D './plugins/jetpack/jetpack.php' # Uses Twig
Elementor = =3D './plugins/elementor/elementor.php' # Uses Twig v4

[packages]
Yoast\SEO = =3D './plugins/yoast-seo/autoload.ini' # Uses Twig v4 as = Yoast\Twig
WPForms =3D './plugins/wp-forms/autoload.ini' # Uses Twig as = WPForms\Twig

[replace]
Twig[UpdraftPlus] =3D 'Twig_edaf27eb'
Twig[Elementor] =3D 'Twig_edaf27eb'

In the above example = `[packages]` are ones that have gotten religion and have delivered a = best-practices package where they have namespaced Twig.  We can = ignore them for now as they follow your = best-practices. 

The = `[includes]` are ones that have paid no attention to newer best practice = and/or simply have not been updated by their authors. They were = implemented to load and use Twig as simply `\Twig`.

The `[replace]` section tells PHP that when = `\Twig` is found included or used within the `[includes]` files denoted = by those namespaces referenced such as `UpdraftPlus` it should instead = use the namespace of `\Twig_edaf27eb` (dynamically generated by = WordPress), and the same goes for any includes and uses by = `Elementor`.

My hypothetical design = may not survive a fully-working implementation, but I hope it = illustrates that we need to:

1.) = Handle those who are NOT following best practices, = AND 
2.) Alias namespaces when used IN ADDITION TO when = imported.

Of course if the code in = any of the three plugins included expect the namespaces to be exact via = reflection then they would break, but I think it would be a reasonable = breakage as most plugins won't do this and most plugins that break could = either be updated by their authors or disabled for installs on newer PHP = by the WordPress plugin repo.

BTW, Go uses `replace` in `go.mod` = albeit as a compiled language its use is not a one-to-one analogue to = the example above. If you are interested in seeing them in the wild here = is what the use of `replace` looks like for Kubernetes: https://github.com/kubernetes/kubernetes/blob/master/go.mod#L22= 7-L258

As an = "optimization", WordPress could recognize that Twig and Twig4 are being = used not only by the includes but also by the packages and could = generate this optimization instead:

[default]
root =3D '/wp-content/'

[includes]
UpdraftPlus = =3D './plugins/updraft-plus/index.php' # Uses Twig v4
Automattic\JetPack =3D './plugins/jetpack/jetpack.php' # Uses Twig
Elementor = =3D './plugins/elementor/elementor.php' # Uses Twig v4

[packages]
Yoast\SEO = =3D './plugins/yoast-seo/autoload.ini' # Uses Twig v4 as = Yoast\Twig
WPForms =3D './plugins/wp-forms/autoload.ini' # Uses Twig as = WPForms\Twig

[replace]
Twig[UpdraftPlus] =3D 'Twig_edaf27eb'
Twig[Elementor] =3D 'Twig_edaf27eb'
Twig[Yoast\SEO] =3D 'Twig_edaf27eb'

Twig[Automattic\JetPack] =3D = 'Twig_2ba3f91f'
Twig[WPForms] =3D 'Twig_2ba3f91f'
<= div>
As a further optimization, WordPress could reach into = all the `.ini` files recursively and create a SINGLE autoload map, but = to do that we would need an additional section: = `[ignore]`: 
[ignore]
Yoast\SEO = =3D './plugins/yoast-seo/autoload.ini'
WPForms = =3D './plugins/wp-forms/autoload.ini' =
The above assumes that WordPress already generated everything = that was needed to no longer need to load the autoload.ini files for = either the `Yoast\SEO` or `WPForms` = namespaces and thus the ignore tells `spl_autoload_map()` to ignore any = calls to these `autoload.ini` files if called later. =  (I would have created a complete example but at this point I am = too tired for that.)

And lastly, = because WordPress would need to generate this and having a web app write = to a file is a modern security no-no, then `spl_autoload_map()` should = accept multiple different valid values:

spl_autoload_map( string|array|\PHP\AutoloadMap = $map);

1. String would be the = `.ini` file path

2. Array would be = the format returned by parse_ini_file() for parsing an applicable `.ini` = file

3. \PHP\AutoloadMap could be a = new class containing the required values in object format. (Hopefully adding such a class as a third option would not be = controversial to the list members who criticize those developers still = wanting to use arrays as hash maps?)

And that is about it for my feedback = today.

-Mike
= --Apple-Mail=_3E631502-2DE9-4CD7-878A-A0EC5B62099F--