Le 11/06/2026 à 08:52, Rowan Tommins [IMSoP] a écrit :
On 11 June 2026 01:23:29 BST, Morgan<[email protected]> wrote:
On 2026-06-11 03:24, Rowan Tommins [IMSoP] wrote:

Take Guzzle, for example; it has 43 source files within a specific namespace root. A 
handful of those are marked "@internal", and a way for PHP to error if users 
reference them directly would be useful. Some users end up wanting conflicting versions 
of Guzzle simultaneously, e.g. in different WordPress plugins; so some way of isolating 
or rewriting class names (and all their references) would be useful.

There are not 43 separate "modules", and the maintainers of Guzzle aren't going 
to combine all of them into one file. Defining a single package with multiple files is 
not a stretch goal, it's the only plausible starting point.

Just throwing this out, but couldn't the "module file" - the one that users 
bring into their project and the one that exports what it's declared to export - delegate 
the definitions of the functions etc. both public and private to other files?

I mean, PHP already _has_ an "include" statement...

It could, but that just moves the problem: right now, I can use any class in 
Guzzle from anywhere in my application as long as I configure the right 
autoloader. I can pass objects from Guzzle into and out of other libraries, and 
they all agree on what each class name means.

Having to write an "import" statement means I have to be conscious of where I 
"start" using Guzzle. If every import of the library creates a magically prefixed copy of 
the entire library, I'm not even clear how I'd refer to different Guzzle classes in different files 
of my application; let alone how libraries could pass those objects in and out and agree that they 
were the same class.

Namespace visibility is really really easy; as if file visibility, if you want 
that. Usable namespace rewriting is much more difficult, but doing it per file 
makes it harder, not easier.

Namespace visibility could be implemented, but if you want to have some public code that uses "include" to get access to some other private code in the same namespace, or sub-namespace, then you would somehow hav to specify to whom this namespace becomes visible. Extending the module concept into "packages" makes sure that a package could have an entrypoint that is publicly accessible, and all files in said package would have to specify which package they are part of. But by design, namespaces aren't dynamic, neither conditional (unless you define one class, then register lots of aliases of this class in different namespaces), so namespace visibility would still be easily "hackable" without having to touch PHP's internals (like from using Reflection). It's similar to namespace spoofing where you redefine a function in a certain namespace just for the sake of overriding native behavior. That's why some CS fixers enforce adding "use function" or add the "\" root namespace to function calls, to prevent from overriding native functions. So far, I don't see how namespace/file visibility would help if you don't have a bi-directional definition system. That's usually what Packages are for: they define their public entrypoints, and all the rest is internal to the package and supposedly inaccessible from the global scope.

Another potential workaround would be "Friend classes" (and there are lots of discussions lately about it), but this system only works for classes and cannot be applied to other structure types. It's not a bad idea, but this enforces "hiding" all your internal logic in classes. Constants would have to be internal static class constants, functions would be internal static class functions, and so on. As said, it's not a bad idea, but IMO this is a "workaround with PHP's existing tools", and doesn't improve the language, it just improves the OOP part. And wouldn't fix the "multiple versions of same package" issue either.

As Larry said, just stop trying to make file==module work. It's not the right 
approach for PHP.
If you want to make namespace==module instead, this could maybe be a nice approach for maintainers in making "some private code" in their packages, but it's not enough: - It still allows creating a namespace from anywhere else in order to "hack" into it and publicly expose an API that wasn't supposed to be exposed at all. - It doesn't solve the issue of having the same package in different versions, since namespaces will be the same

The file==module approach is imperfect, indeed. In Rust, you can create tons of modules in one single file, each with their own private and public code, but most of the times, developers create one file per module, and the module's name is the filename itself. A Rust Crate (aka "package") goes even further in allowing a module to expose its API publicly only for the package. I think this is the best approach, and it's safer than how JS modules are implemented. However, considering the dynamic (instead of compile-only) nature of PHP, and considering the ecosystem's occasional needs to have multiple versions for one package, the addition of an internal hashed prefix for each module makes it possible. It reuses everything that PHP already has, and it can be almost transparent for the end-user: they won't write `use` but rather `import` instead, and maybe use a local name instead of a FQCN (though modules can define namespaces, therefore you can import a FCQN). And I still think that using namespaces for that, and namespace visibility, won't help, since they all register things in the global scope with the same names, and doesn't fix the other issues.

Reply via email to