Le 11/06/2026 à 11:54, Rowan Tommins [IMSoP] a écrit :
On 11 June 2026 09:12:52 BST, Alex Rock<[email protected]> wrote:
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.

Why would you need that?


namespace visibility would still be easily "hackable" without having to touch 
PHP's internals (like from using Reflection).

Visibility isn't a security tool, it's a helper to stop people making mistakes.


That's why some CS fixers enforce adding "use function" or add the "\" root 
namespace to function calls, to prevent from overriding native functions.

I believe that's actually about performance: if you don't specify, the engine 
has to try the lookup on every call, in case a namespaced function was 
registered.


So far, I don't see how namespace/file visibility would help if you don't have 
a bi-directional definition system.

It's really, really simple: you mark the internal parts "internal". Then you 
use them from all the same places they're intended, inside the package's namespace; and 
people using them outside those intended places get a helpful error message that they're 
using the library wrong.

It's possible we also want to add a way to "seal" the namespace against new 
definitions anyway, to help with optimisation. Namespaces, not files, would still be the 
right starting point for that.


What if we have this:

<?php

// vendor/my-library/src/MyClass.php

namespace MyNamespace;

internal class MyClass {};

Fine code would look like this:

<?php

// index.php

function main() {
        $o = new \MyNamespace\MyClass(); // Fatal Error: cannot create instance 
of internal class MyNamespace\MyClass
 outside of the MyNamespace namespace
}

And "not fine code" would look like this:

<?php

// index.php

namespace MyNamespace {
        function createObject() {
                return new \MyNamespace\MyClass();
        }
}

namespace {
        function main() {
                $o = \MyNamespace\MyHack::createObject(); // Works.
        }
}

Your "internal" system would be quite useless, because anyone would be able to do it. It can even be done at the autoloader level if one wanted. Doesn't use Reflection or such.

Then, it leads to your first question:

On 11 June 2026 09:12:52 BST, Alex Rock<[email protected]> wrote:
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.
Why would you need that?

Well, to solve the previously shown issue.

The "internal class" previously set (or moved to "internal namespace": same issue) is useless, and it would kinda do the same thing as /** @internal */ today: cannot be enforced at runtime, so not safe at all.

There's no need to add "internal class" if this system doesn't internalize anything and is easily "hackable" from outside.


If you want to have *actual* internal code, there are only two ways to achieve this:

- have code that's internal on said file, with the proposed "module" system. Sure, it's only for a file, but it's better than nothing - have a "package" system so that a package has an entrypoint that defines private and public files, and said files expose which "package"

I repeat: since PHP is hugely flexible, especially via the whole Reflection API, I don't mean to "make hacking impossible", because, well, with PHP you can override everything. I mean to "make it as hard and ugly as possible". Sure you can execute a private method in a class/object by using either Reflection (or a bounded closure), but these are explicit hacks. With "just namespaces", you can just use the widely used autoload system and create a class somewhere with a static method, or a global function (like above) , it doesn't even look like a hack.


- 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.

Non-issue: as above, visibility is not a security tool.

If bad practices are easily accessible from a new feature, you will expect lots of bad practices, because that's what lots of coders end up doing. We all know that, and if you don't know it, I hope you'll realize it some day. That's why "enforcing good practices" is a better approach, because it doesn't disallow bad code, it just makes it harder to produce, costing more energy, time, money, and technical debt.

- It doesn't solve the issue of having the same package in different versions, 
since namespaces will be the same

A solution to that which requires hundreds of thousands of libraries to rewrite 
all their code to use relative references rather than namespaced global names 
isn't going to get very far.

I'll say it one more time, then stop: any solution needs to start with what we 
have, and what we have is namespaces.

In that case, let's move directly to "packages" without talking about "modules" at all, and make namespaces package-aware somehow. Or the contrary: make a package implicitly create "protected" namespaces.

And use it like this for example:

<?php // vendor/some-package/package.php

define package MyPackage;

package_include MyPackage\MyClass from __DIR__.'/src/MyClass.php';

// ... and possibly all other includes
// (note: this is an idea, there might be another way.
// It could even be an spl_register_internal() function or anything similar
//   that makes sure it's not possible to define package-bounded structures
//   from outside the package definition file



<?php // vendor/some-package/src/MyClass.php

package MyPackage; // implies "namespace MyPackage;" too, to globally reference 
non-internal structures

internal class MyClass {};



<?php // invalid include

include 'vendor/some-package/src/MyClass.php';  // Fatal error: package 
"MyPackage" was not defined.



<?php // invalid instantiation

include 'vendor/some-package/src/package.php';
include 'vendor/some-package/src/MyClass.php'; // Just an appendage to the 
MyPackage, could even be autoloaded

new MyPackage\MyClass(); // Fatal error: cannot create instance of internal 
class MyClass


This way, once a `define package MyPackage` has been called, any further file doing `package MyPackage` will throw an error


The "Package" thing is a bit more recommended, but IMO it needs a bidirectional system.


Though, the concept of "modules" as I explained it, whether it uses namespaces or not, makes "package-alike" systems possible, even if it's in one single file.

Another "workaround" to define structures each in their file and merging them together in a module would be a "merging script" system, but that's ugly, and it is similar to the "compilation/transpilation" process in Node.js, where your publicly available package is a "built" version of your source code (what happens in NPM packages), rather than the source code itself (like in PHP or Rust).


I think I won't convice you of anything, and so far there are not many people participating in this discussion, so feel free to drop out if it's annoying or boring for you, I won't take it personally :)

Reply via email to