Blog post: Proposal for fixing PHP namespacing in Drupal 8
Collisions with non-Drupal PHP code
In theory, although I have never see this happen, a PHP library that Drupal is utilising could declare a function or class that is already declared in Drupal. This would cause PHP to abort.
PHP 5.3 has a solution - namespaces (http://php.net/manual/en/language.namespaces.php).
Drupal 8 should require PHP 5.3 - it was released 2009-06-30. Drupal 7 requires 5.2 and may just get released this year. When will D8 be released? Probably 2012 or 2013 - by then PHP 5.3 will be 3 or 4 years old.
Every PHP file that is part of Drupal would be in the 'drupal' namespace. This would be declared at the top of every PHP file as follows:
<?php
namespace drupal;Because all of Drupal is in its own namespace, there is no possibility of function or class name collisions.
We are already prefixing many functions with drupal_ - this can simply be dropped from such function declarations.
The new Database API in D7 is not really part of Drupal - it can be used without the rest of Drupal with only a few minor changes. It is a standalone library, and as such it should be in its own namespace:
namespace drupaldb;the db_ prefix could then be dropped from all function declarations in the library.
Modules and themes
Modules and themes (and engines) would have a namespace such as
namespace drupal\taxonomy;namespace drupal\bartik;Function prefixes, such as 'taxonomy_' would be dropped.
However, this makes Drupal code really ugly.
Calling functions not in a module from a module would look like this:
\drupal\set_message();Calling a db function would look like this:
\drupaldb\select('node');Calling an API function in another module would look like:
\drupal\taxonomy\select_nodes();The solution? Namespace importing.
Every PHP file in a module would need to declare which namespaces it needs to access, e.g.
<?php
namespace drupal\node;
use drupal, drupaldb as db;
use drupal\taxonomy;This means the above examples would look like:
drupal\set_message();
db\select('node');
taxonomy\select_nodes();Which is really quite pleasant!
Calling a function that is in the current namespace would not require any prefixing. For example, calling \drupal\node\access_needs_rebuild() from inside namespace 'drupal\node' would be invoked as:
access_needs_rebuild();Namespace importing should not be confused with module dependencies - importing is specified on a per-file basis.
Magic functions (hook implementations)
There are a couple of namespacing issues that can occur with magic functions:
- Ambiguity of where the module name ends and the hook name begins, e.g. views_comment_load() - is the hook 'comment_load' or 'load'?
- Modules can inadvertently implement a hook for some other module.
- Multiple modules can 'invent' the same hook, expecting it to do different things
Solution: use __
Magic functions would take one of the following forms:
INVENTOR__HOOK()
INVENTOR__HOOK__PARAM()
INVENTOR__HOOK__PARAM1__PARAM2() etcINVENTOR is the name of the module that 'invented' the magic function.
HOOK is the name of the hook, e.g. form_alter.
PARAM is for additional parameters, e.g. the name of the form to be altered.
e.g.
system__menu()
block__info()
system__form_alter__search_form()Only magic functions can have __ in their name. Modules, hook names [updated] and parameters are not allowed to have a double underscore. Drupal should not permit any machine name to have a double underscore.
A further advantage of this is that the name of a magic function for a specific hook would be the same in every module that implements the hook. This helps code portability - example hook implementations could be put in place simply by cutting and pasting code.
Theme / process / preprocess implementations
These are also magic functions.
The hook name is 'theme' / 'process' / 'preprocess'.
A module that declares a theme hook in a system__theme() is considered the 'inventor' of the magic function.
theme_user_list($variables)user__theme__list($variables)in both the module that invented it and in themes that are overriding it.
A module / engine / theme could implement a preprocess hook like:
system__preprocess__page()
system__preprocess__links__contextual__node()The second example is for the 'fallback' theme items described here.
Example
The attached node.module has been modified to incorporate this proposal (and a few other code style changes).
| Attachment | Size |
|---|---|
| node.module.namespaced | 124.24 KB |
| Namespaces2.pdf | 33.4 KB |