Should PHP reserve a namespace for built-in classes?

php.internals

Nick Lockheart

2 years ago
What is the general feeling about reserving a namespace for PHP's built in classes? As the number of built-in classes grows over time, the chances of naming collisions with user classes will grow. When naming conflicts occur, they happen in an unexpected way, that does not make it readily obvious that a name conflict has occurred. That's because most projects use auto loaders, and the auto loader only runs if a class is unregistered. If a user creates a class called "Directory" and places it in the auto load path, then tries to instantiate it, they will *not* receive any error. If the user then tries to call Directory::MyMethod(), they are told that the method doesn't exist, even when they are staring at the class definition. The user presumes that the auto loader has found and loaded the class, because there isn't a "class not found" message. If new built-in classes are added in the future using common dictionary words as the name, there is a good chance of confusing breaks when the PHP version is updated. Now that namespaces are a thing in PHP, maybe we should take a page from C++'s book and have users include the standard library classes they want, when they need them. ie: use \spl\Directory; I'm also wondering if there would be any performance benefit to not having a bunch of internal classes pre-registered "just in case".

Tim Düsterhus

2 years ago
Hi On 7/24/24 19:43, Nick Lockheart wrote:
> What is the general feeling about reserving a namespace for PHP's built > in classes?
see https://wiki.php.net/rfc/namespaces_in_bundled_extensions Best regards Tim Düsterhus

Nick Lockheart

2 years ago
On Wed, 2024-07-24 at 19:51 +0200, Tim Düsterhus wrote:
> Hi > > On 7/24/24 19:43, Nick Lockheart wrote: > > What is the general feeling about reserving a namespace for PHP's > > built > > in classes? > > see https://wiki.php.net/rfc/namespaces_in_bundled_extensions > > Best regards > Tim Düsterhus
Thank you. I've read through the RFC and see it was approved. Is it too late to comment on this? My concern is that placing things into new and arbitrary namespaces as per the RFC is just a different variation on the global name problem. The problem, as I see it, is that new names that come bundled with PHP can be arbitrary. If new bundled classes can have arbitrary dictionary words as the namespace, then we may actually have a bigger problem as no name space is safe from future collisions. The biggest problem with built-ins is that you can't unregister them. I think a better solution would be to have one namespace for all bundled classes, so that a specific namespace is reserved in advance. From the RFC:
> 3rd-party extensions clearly cannot start out under a PHP namespace, > as they have no direct relation to, endorsement by, or oversight of > the PHP project. If all symbols in bundled extensions are to be > prefixed by PHP, this would require a rename of all symbols when an > extension moves from 3rd-party to bundled.
I think this is the real issue: How could we use a small number of reserved namespaces for built-ins, but deal with permanence of those names as things move around? What if we had a grandfather policy? Once a third party is accepted into core, it gets a core namespace. If it is later removed from core, it gets grandfathered into being allowed to use the core namespace, even if it is once again third party. The RFC did mention that once something moves to core, it seldom moves back out, if ever. There was a vote on something similar four years ago, 13(no)/17(yes), declined. It was four votes shy of passing: https://wiki.php.net/rfc/php_namespace_policy There was more in that proposal though: the use of component namespaces in addition to just `\php`. Could this issue possibly be revisited and voted on with a more narrow scope? I think if we reserved `\php` and `\ext`, then there would be no need to have multi-level namespaces, like the prior RFC proposed. I think every standard class could just be `\spl\classname` without any naming conflicts between core classes. And that would also avoid future namespace collisions.

Tim Düsterhus

2 years ago
Hi On 7/24/24 21:44, Nick Lockheart wrote:
> Thank you. I've read through the RFC and see it was approved. Is it too > late to comment on this? My concern is that placing things into new and > arbitrary namespaces as per the RFC is just a different variation on > the global name problem.
Commenting is of course possible, but any changes would require another RFC. In any case, the RFC's policy has already been used in the design of the new randomness API added in PHP 8.2.
> I think a better solution would be to have one namespace for all > bundled classes, so that a specific namespace is reserved in advance.
Needing to prefix everything by \PHP or something like this would provide for a terrible developer experience when using the standard library.
> There was a vote on something similar four years ago, 13(no)/17(yes), > declined. It was four votes shy of passing:
This is false. That RFC required a 2/3 majority to pass.
> I think if we reserved `\php` and `\ext`, then there would be no need > to have multi-level namespaces, like the prior RFC proposed. I think > every standard class could just be `\spl\classname` without any naming > conflicts between core classes. And that would also avoid future > namespace collisions.
Not using sub-namespaces would require making the classnames overly specific, because there's some names that make sense in different domains. An example would be a `Client` or `Connection`. Best regards Tim Düsterhus

Nick Lockheart

2 years ago
On Wed, 2024-07-24 at 22:02 +0200, Tim Düsterhus wrote:
> > > I think a better solution would be to have one namespace for all > > bundled classes, so that a specific namespace is reserved in > > advance. > > Needing to prefix everything by \PHP or something like this would > provide for a terrible developer experience when using the standard > library.
We're already there. If I want to have a Directory class, I need to put it in a namespace. But then, if I'm using namespaces, I need to put a `\` in front of every built-in class *and* function or else take a performance hit. So we're already where we need to do \isset, \array_key_exists, etc to get the built-in functions without doing a local namespace lookup first. I think there are several things to consider here: 1. Could we have a global setting (maybe php.ini) that makes all built- in functions (not built in classes) directly accessible in any namespace? That is: // php.ini AlwaysUseGlobalFunctions = yes Then: // myclass.php namespace foo; class Bar{ function MyMethod($a,$b){ if(array_key_exists($a,$b)){ // no \ before array_key_exists // do something } } } And with that option set, PHP will know that array_key_exists *is* \array_key_exists, even without the slash, and without checking the foo namespace for an array_key_exists function first? My understanding is that some built-in functions have their own opcode, that doesn't get triggered when those built-in functions are called in a namespace, unless the built-in is called with a `\`. Having all *functions* default to global would make namespaces a lot more user friendly to work with, since we wouldn't have to put backslashes in front of everything. 2. I think built-in classes are nice, but having classes pre-registered in the global namespace can cause a lot of frustration. ie. "GlobIterator::__construct() expects at most 2 arguments, 3 given". Except, my GlobIterator takes exactly three arguments, so why does.... Oh. I see, there's already a GlobIterator registered. I think the sane approach is to have the (user land) developers pull built-in classes into the global namespace when needed with `use`. If I want the built-in GlobIterator, I should specify that with: use \spl\GlobIterator; Then I know there's a GlobIterator class because I just called for it.

Claude Pache

2 years ago
> Le 25 juil. 2024 à 05:22, Nick Lockheart <lists@ageofdream.com> a écrit : > > 1. Could we have a global setting (maybe php.ini) that makes all built- > in functions (not built in classes) directly accessible in any > namespace? That is: > > // php.ini > AlwaysUseGlobalFunctions = yes > > Then: > // myclass.php > namespace foo; > class Bar{ > > function MyMethod($a,$b){ > if(array_key_exists($a,$b)){ // no \ before array_key_exists > // do something > } > } > } > > And with that option set, PHP will know that array_key_exists *is* > \array_key_exists, even without the slash, and without checking the foo > namespace for an array_key_exists function first? > > My understanding is that some built-in functions have their own opcode, > that doesn't get triggered when those built-in functions are called in > a namespace, unless the built-in is called with a `\`. > > Having all *functions* default to global would make namespaces a lot > more user friendly to work with, since we wouldn't have to put > backslashes in front of everything. > >
Hi, For the case of functions (and constants) in the global namespace, there was an RFC on the subject about 4 years ago, which has been declined; see: https://wiki.php.net/rfc/use_global_elements and the discussion threads referenced at the bottom of that page. —Claude

Nick Lockheart

2 years ago
On Sun, 2024-07-28 at 00:48 +0200, Claude Pache wrote:
> > For the case of functions (and constants) in the global namespace, > there was an RFC on the subject about 4 years ago, which has been > declined; see: https://wiki.php.net/rfc/use_global_elements and the > discussion threads referenced at the bottom of that page.
The top of the RFC correctly outlines the problem; a problem that still exists. Maybe the proposed solution wasn't the best approach, but it still remains an issue: Classes that are built-in to PHP are and will cause naming collisions with developer code. I think the C++ approach is simple and elegant: using std::string; The C++ standard library will never collide with user code as you ask for it when you want it.

Nick Lockheart

2 years ago
> On Sun, 2024-07-28 at 00:48 +0200, Claude Pache wrote: > > > > For the case of functions (and constants) in the global namespace, > > there was an RFC on the subject about 4 years ago, which has been > > declined; see: https://wiki.php.net/rfc/use_global_elements and the > > discussion threads referenced at the bottom of that page. >
What about: namespace foo; use global functions; class MyClass{ // do stuff } The `use global functions` directive goes after the namespace declaration, but before any other code. It applies to the entire file, but only to the current file. It tells the parser that, if a function call is found in the file, use the global function. Do not make an NS lookup op code, and if the function is a recognized built-in with a dedicated op code, use the dedicated op code. Methods and classes are unaffected.

Nick Lockheart

2 years ago
> > I think a better solution would be to have one namespace for all > > bundled classes, so that a specific namespace is reserved in > > advance. > > Needing to prefix everything by \PHP or something like this would > provide for a terrible developer experience when using the standard > library. >
What are people's thoughts on requiring a use statement to make built- in classes available in the global namespace?

Bilge

2 years ago
On 27/07/2024 23:30, Nick Lockheart wrote:
> What are people's thoughts on requiring a use statement to make built- > in classes available in the global namespace? >
No.