rfc:namespaces-in-core

PHP RFC: Namespaces in Core

Introduction

Introduce namespaces to user-level symbols to avoid collisions with user defined symbols, decrease breaking changes due to the introduction of new symbols and thus increase future compatibility. A concrete proposal on how to structure the namespaces is proposed as well.

Proposal

This RFC proposes the definition of a standardized namespace structure for PHP internals by utilizing the reserved PHP namespace as the root for all code that is supplied by the PHP Group, and vendor specific root namespaces for symbols that are contributed to the PHP Group from other vendors.

Coding Standard

An important question to answer, if namespaces are to be used by PHP, is how they should be written. PHP has a long history of inconsistency, it therefore makes sense to define this upfront to ensure that any future effort is not going to introduce new inconsistencies.

There are two possible choices:

  1. snake_case
  2. PascalCase (in accordance with class naming)

Arguments for both approaches exist, however, it is after all a purely cosmetic question:

  • php\collections\BTreeMap
  • PHP\Collections\BTreeMap
  • php\locale\LanguageTag
  • PHP\Locale\LanguageTag
  • php\lang\parser\ast\CompilationUnit
  • PHP\Lang\Parser\AST\CompilationUnit
  • vendor\some_ext\sub_ns\ExtClass
  • Vendor\SomeExt\SubNs\ExtClass

Another question in this regard is whether to allow plural forms (e.g. collection vs collections) in namespaces or not.

Structure

User-level code provided directly by the PHP Group goes into the PHP vendor namespace. The vendor namespace itself does not contain any code directly, but instead is split into multiple sub-namespaces. This should ensure that we are not creating a new global namespace where everything that cannot be categorized ends up in.

The sub-namespaces are basically endless, anything that makes sense can go there. It is up to the PHP Group to decide on them. Examples for namespaces are:

  • Collection(s) — could contain optimized collection types like we have them today from the SPL or the DS extension.
  • Core or lang — contains everything that is directly bound to the PHP language itself, and which cannot be removed without breaking the language itself. Examples include primitive types that are directly understood by the parser (e.g. arrays, integers, strings), as well as other basic types and functionality that is directly coupled to the parser (e.g. Countable, Error, Exception, assert()).
  • Crypto — could contain cryptographic abstractions, without exposing the underlying library and technology.
  • IO — could contain a file system abstraction, with a possible sub-namespace for streams.
  • Locale — could contain abstractions to work with different languages without exposing the underlying library or technology.
  • Logging — could contain an abstraction for logging that is extensible by user-level software.
  • OPCache — should be self-explanatory.
  • Parser — could expose the PHP parser to user-level software for their own usage. This could contain further sub-namespaces for tokens, AST, etc.
  • PHAR — should be self-explanatory.
  • Regex — could contain abstractions for regular expressions, without exposing the underlying library or technology.
  • Reflection — should be self-explanatory.
  • Std or util — for tiny self-contained types (e.g. InvalidArgumentException) and functionality where it would be total overkill to create a dedicated namespace for (e.g. UUID). Care must be taken that not everything ends up in this namespace. Basically, anything that requires more than an interface-class-exception combination should not go into this namespace. The situation with single functions is even more complicated. These decisions must be made on a case-by-case basis by the PHP Group. Defining strict rules seems counterproductive.

Extensions which are provided by third-party vendors to the PHP Group for future maintenance and inclusion in the PHP repository go into their own vendor namespace. This should ensure that we can move those extensions to PECL without breaking compatibility on a namespace level. It also clearly communicates that that code is not from the PHP Group directly.

Vendor names must not be random, to ensure that they cannot collide with the names that users choose for their own namespaces. Names of companies or organizations (e.g. MySQL, Oracle, W3C) are always a good choice, because they are protected trademarks and nobody is allowed to actually impersonate them. Widely known software names across programming languages (e.g. curl, PCRE, JSON) are also good choices, as the likelihood of someone using them for their own namespaces is low.

That being said, the decision whether a name is a good root namespace for a vendor or not must be decided on a case-by-case basis by the PHP Group. A search on Packagist for existing users should be the minimum requirement there.

What Goes Where?

This question is actually one that the PHP Group had to ask themselves since modules were introduced to internals. The choice is basically simple, group related things by use-case, reuse, and conceptual cohesion. Hence, this is always something that needs to be decided on a case-by-case basis. The introduction of new namespaces should not be problematic, as long as it is clear that that namespace will contain more than just two classes.

Backward Incompatible Changes

None, this RFC affects future decisions only.

Open Issues

  • Should we avoid abbreviations? Hence:
    • language vs lang
    • standard vs std
    • utility vs util

Future Scope

Optimization of the directory structure of php-src to reflect the namespace structure. This could help to avoid those 1,000+ LOC files, and would aid discoverability as well as mapping of a user-level symbol to its actual position in the php-src repository. An optimized directory structure could look as follows:

/
├── bin/
│   ├── appveyor/...
│   ├── travis/...
│   ├── php
│   ├── php-cgi
│   ├── php-dbg
│   ├── php-ext
│   ├── php-fmt
│   ├── php-fpm
│   ├── php-ize
│   ├── php-pkg
│   ├── php-tst
│   └── ...
├── bld/
│   ├── debug/
│   │   ├── x64/...
│   │   └── x86/...
│   ├── debug-ts/
│   │   ├── x64/...
│   │   └── x86/...
│   ├── release/
│   │   ├── x64/...
│   │   └── x86/...
│   └── release-ts/
│       ├── x64/...
│       └── x86/...
├── doc/
│   ├── building/
│   │   ├── supported-platforms.ad
│   │   ├── unix.ad
│   │   ├── windows.ad
│   │   └── ...
│   ├── guidelines/
│   │   ├── coding-standard-c.ad
│   │   ├── coding-standard-php.ad
│   │   ├── git-rules.ad
│   │   ├── mailing-list-rules.ad
│   │   └── ...
│   ├── stubs/...
│   ├── testing/...
│   └── ...
├── etc/
│   ├── php/
│   │   ├── development.ini
│   │   ├── logo.svg
│   │   └── production.ini
│   └── ...
├── lib/...
├── src/
│   ├── mysql/...
│   ├── php/
│   │   ├── engine/...
│   │   ├── locale/...
│   │   ├── logging/...
│   │   ├── reflection/...
│   │   └── ...
│   ├── postgresql/...
│   ├── sapi/
│   │   ├── apache/...
│   │   ├── cgi/...
│   │   ├── cli/...
│   │   ├── fpm/...
│   │   └── ...
│   ├── win32/...
│   ├── zend/...
│   └── ...
├── tst/...
├── var/...
├── README.ad
└── ...

Proposed Voting Choices

Simple 50%+1 majority votes as it does not affect the language’s functionality.

  1. Allow namespaces in Core? Yes/No
  2. Coding Standard? snake_case/PascalCase
  3. Allow plural nouns in namespaces? Yes/No
  4. Use PHP root namespace for PHP Group and vendor specific ones for others? Yes/No
  5. Use namespace for the language itself (in the future)? Yes/No
  6. Name of the language namespace? core/lang
  7. Use namespace for tiny self-encapsulated things (in the future)? Yes/No
  8. Name of that namespace? std/util

References

rfc/namespaces-in-core.txt · Last modified: 2017/06/04 21:41 by fleshgrinder