On Sun, Jun 1, 2025, at 12:26 AM, Michael Morris wrote:

> $myModule = require_module('file/path');
>
> or perhaps
>
> const myModule = require_module('file/path');
>
> The module probably should return a static class or class instance, but 
> it could return a closure.  In JavaScript the dynamic import() 
> statement 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.
>
> Circling back to a question I know will be asked - what about 
> autoloaders?  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 required 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. 
>
> Will this work? I think yes. Will it be efficient? Hell no. Can it be 
> optimized somehow? I don't know.

I think there's a key assumption here still that is at the root of much of the 
disagreement in this thread.

Given that code from multiple files is clustered together into a "thing"
and Given we can use that "thing" to define a boundary for:
* name resolution (what Michael is after);
* visibility (what I am after);
* more efficient optimizations (what Arnaud showed is possible);
* various other things
Then the key question is: Who defines that boundary?

Is it the code *author* that defines that boundary?  Or is it the code 
*consumer*?  

Similarly, is it the code author or consumer that has to Do Work(tm) in order 
to leverage the desired capability?  Or both?

This is an abstract question that I think needs to be resolved before we go any 
further.  There are certainly ways to do it with either party in control of the 
boundary, but I suspect many of them will be mutually-exclusive, so deciding 
which tradeoffs we want and what future features we're OK with blocking is 
highly important.

My own take:

The boundary *must* be definable by the author.  The author knows the code 
better than the consumer.  The odds of the author botching the boundary and 
making subtle bugs is orders of magnitude less than the consumer of the code 
botching the boundary.  (Eg, if a class is declared module-private, but it's 
the consumer that defines what module it is in, then access to that class is 
completely out of the control of the author and it's really easy for some code 
to break.)  Potentially we could allow the consumer to decide how they want to 
leverage that boundary (either by just using the code as is normally now, or 
wrapping it into a name resolution container), but the boundary itself needs to 
be author-defined, not consumer defined, or things will break.

I realize that makes it less useful for the goal of "support old and 
unmaintained WordPress plugins that haven't been updated in 3 years" (as it 
will be about 15 years before WP plugins that have bothered to make 
modules/containers/boundaries get abandoned), but my priority is the 
consistency and reliability of the language mroeso than supporting negligent 
maintainers.

One possible idea: Starting from the proposal Arnaud and I made earlier (see 
earlier posts), have a Module.php file rather than module.ini, which defines a 
class that specifies the files to include/exclude etc.  Then in addition to the 
"just use as it is" usage pattern we described, the consumer could also run 
something like:

$container = require_modules(['foo/Module.php', 'bar/Module.php'], 
containerize: true);

Which would give back an object/class/thing through which all the code that was 
just loaded is accessed, creating a separate loading space that is build along 
the boundaries established by the module/package authors already.  (Note: This 
still relies on all of those packages being modularized by their authors, but 
again, I think that is a requirement.)

--Larry Garfield

Reply via email to