On 01/06/2025 17:05, Larry Garfield wrote:
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?
My take on this is that both need to exist as *separate* features.
The author should define the boundary for things like visibility and optimisation. It should be possible to take an existing Composer package, add some metadata to it in some way, and have the engine make some useful assumptions. The consumer of that package should not need to care about the difference, except in edge cases like trying to define additional classes with the same prefix as a third-party package.
On the other hand, the consumer should define the boundary for isolating name resolution. It should be possible to take any folder of PHP files, with no metadata about package management, and load it in a context where duplicate class names are allowed. The author of the package shouldn't need to make any changes, except in edge cases like highly dynamic code which needs additional hints to work correctly when sandboxed.
The first feature is an add-on to the extremely successful ecosystem based on the assumption that packages will inter-operate based on agreed names. The second feature is a bridge between that ecosystem and the very different world of plugin-based web applications, which want to manage multiple pieces of code which are not designed to co-operate, and run them side by side.
JS has come up a few times as a comparison, because there the two features overlap heavily. That's because the language has always started from the opposite assumption to PHP: declarations in JS are local by default, and can only be referenced outside of the current function scope if explicitly passed outwards in some way. In PHP - and Java, C#, and many others - the opposite is true, and declarations have a global name by default; keywords like "private" and "internal" are then used to indicate that although code can name something, it's not allowed to use it.
Both have their strengths and weaknesses, but at this point every JS module going back 15+ years (CommonJS was founded in 2009, to standardise existing practices) is based on the "interact by export" model; and every PHP package going back 25+ years (PEAR founded in 1999; Composer in 2011) is based on the "interact by name" model.
--
Rowan Tommins
[IMSoP]