After tons of other namespace discussions, here is a workable proposal for namespaces in module-provided procedural code and hook implementations.

UPDATE May 2012:
As namespaces have already been decided for OOP code with PSR-0, we should use the same namespaces here.
To see the original proposal, check the history.

PHP 5.3 Namespaces and PSR-0 for module-provided classes is discussed elsewhere,
#1290658: Move all module-provided classes to PHP namespaces (PSR-0 or similar), and autoload them without the registry [policy, no patch]
We follow the patterns discussed there, and do the logical thing for functions and hooks.

Short summary

Drupal\\my_module\\foo() (regular function)
Drupal\\my_module\\hook_inventor_bar() (hook implementation, for a hook invented by "inventor" module)

Motivation

There are several issues with the current situation.

  • Module names are not prefix-free. One module can be named "menu", another "menu_block" or "menu_editor". One module can be named "node", another "node_access". This does lead to plenty of ambiguities, and is just asking for trouble.
  • Hook implementations look no different from regular functions.
  • Bugs due to magic name overlaps are hard to spot.
  • There is no "guaranteed free space" for new hook or function names. Every newly introduced function or hook name can result in a nameclash or a magic name overlap.
  • Even if we are successful with avoiding name clashes and overlaps, this is paid with preemptive paranoia. Such as, using uncommon words for module names, or omitting the underscores.
  • Module-prefixed function names can become really long.

Procedural code might slowly fade out in the future, and OOP code is already planned to be namespaced. However, this is rather a long-term thing, we should not put our hopes on that.

Goals:

  • Avoid name clashes and overlaps between modules.
  • Avoid name clashes and overlaps with non-Drupal code and native PHP identifiers.
  • Give every module "guaranteed free space" for inventing hook and function names.
  • Avoid too many curly brackets -> no more than one namespace per file.
  • Make regular functions clearly distinguishable from magic named functions (hook and theme implementations).
  • Make it easier to grep for hook implementations and invocations.

Functions

The namespace for a module-provided function foo() will be like
Drupal\my_module\foo()

The function can be in the *.module file or any other *.inc file within the module directory.

Hook implementations

I propose this simple syntax for hook implementations.
Drupal\my_module\hook_views_plugins()

Theme implementations

I'd say, we postpone that. There can be very interesting solutions for theme implementations, but they would only distract us here.

Invoking a hook

This would be similar to what we have today,
module_implements('hook_menu')
module_invoke_all('hook_menu')
module_invoke('my_module', 'hook_menu')
(whether the "hook_" should be part of the hook name argument, can be discussed. I think it does make things more clear)

Extended proposal

hook inventors? -> to be discussed
The original proposal does not care which module has "invented" a hook. The inventor should ideally be part of the hook name, but this is not a technical requirement.
It will still be possible that two modules invent the same hook. This does make it difficult for any module to invent a new hook, because that name could already be taken.

An alternative could be
"Drupal\\{$implementor}\\{$inventor}_hook_{$suffix}"
with
module_implements("{$inventor}_hook_$suffix");
This would make a "_hook_" a reserved substring in all functions in a module's top-level namespace.

automatic file inclusion?
Modules can give hints about which files should be included before we look for hook implementations.
For instance, a module might say that we always have to include every module's [module].registry.inc, before we look for hook_menu() implementations. This can be defined via a hook, or via the info file.

subnamespace hooks
Alternatively, we could put hooks into subnamespaces to indicate which include files should be included.
Example: Drupal\Module\my_module\registry\hook_menu() always implemented in [module path]/[module name].registry.inc

How module files will look like

A typical module file will just have one namespace definition at the top, followed by regular code.

namespace Drupal\Module\my_module;

function hook_menu() {
  ..
}

function foo() {
  ..
}

Benefits

Compared to the current situation, we avoid nameclashes like in
#1425182: Fatal error Cannot redeclare user_delete_access() with Drupal-6.24
both in hooks and in regular functions.

Compared to other proposals, we have
- Only one namespace per class. No nasty curly brackets.
- One can easily grep for "hook_something", to find all implementations of that hook.
- The keyword "hook" does stick in the eye. hook implementations are clearly distinguishable from regular functions.
- A reserved substring "hook_" or "_hook_" is safer than a reserved substring of just "__".

CommentFileSizeAuthor
#4 modulenamespaces.patch830 bytesrobloach

Comments

donquixote’s picture

Issue summary: View changes

subnamespace registry always in *.registry.inc

donquixote’s picture

Issue summary: View changes

Should "hook_" be part of the hook name argument in module_invoke ?

jbrown’s picture

I am very supportive of this proposal. It is very similar to my original proposal 13 months ago: http://bluedroplet.com/blog/proposal-fixing-php-namespacing-drupal-8

This issue depends on #1393208: Namespace all Drupal PHP code (esp. procedural).

Themes and profiles are really modules. I think they should be in the Drupal\Module namespace.

Adding the hook_ prefix to hook implementations should be in a separate issue. These namespacing issues are already huge and need to be as small as possible.

All three parts of the extended proposal should be removed from this proposal. They can be created as separate issues later.

I list some further benefits of namespacing here: http://drupal.org/node/867772#comment-5558780

The other advantage of namespacing modules is that it removes the ambiguity in hook implementations of where the module name ends and the hook name begins.

The most time-consuming part of creating namespacing patches is finding all the places in the code that need to be updated, but can't be updated by automated means (primarily dynamic function invocation). Fortunately I have discovered all of these places in drupal core. They can be seen in the namespace-fixes.patch.txt files in #1393208: Namespace all Drupal PHP code (esp. procedural).

donquixote’s picture

It is very similar to my original proposal 13 months ago: http://bluedroplet.com/blog/proposal-fixing-php-namespacing-drupal-8

It would be interesting to identify the differences to your proposal, and decide which one is preferable, and why. I do find a few, but atm have no time to write them down :)

Themes and profiles are really modules. I think they should be in the Drupal\Module namespace.

It looks like the PSR-0 folks have made this decision for us: Now a module is directly in Drupal\$modulename.
Also, now the Drupal root namespace is capitalized (as are most other parts of a namespace, except for the module name).

donquixote’s picture

Here is a summary of differences to other proposals.
I think the issue worth discussing is whether we need the inventor as part of the hook name. I can see convincing arguments why we would need it.

Changes due to PSR-0 for classes.

The discussions about PSR-0 autoloading for module-provided classes have brought a few decisions, that are relevant for us:

  • The root namespace for Drupal is now "Drupal" instead of "drupal".
  • The namespace for a specific module is likely to be "Drupal\$module", instead of "Drupal\Module\$module". The module name is still lowercase. It would be awkward, if procedural code would live in a different namespace than classes.

Differences to the older proposal by jbrown

http://bluedroplet.com/blog/proposal-fixing-php-namespacing-drupal-8

"hook_" instead of "__"
In the older proposal, "__" was a reserved substring for function names, only to be used in hook implementations. In the new proposal, we do instead have "hook_" as a reserved prefix. This is a lot safer, and allows to use "__" for other purposes. It also allows grepping for "hook" or "hook_" to find anything that could be a hook implementation or a hook invocation.

Inventor - does it matter?
In the older proposal, every hook name did start with the inventor module's name. In the newer proposal, we do not care about the inventor. The newer proposal does result in simpler hook names, but it also re-introduces the risk of multiple modules inventing the same hook.
This is to be discussed.

Theme implementations
Atm, we do not care about these.

Differences to other proposals with namespaces

One major characteristic of this proposal is that we need no sub-namespaces for hook implementations. Any procedural code provided by a module does live in the same namespace. This way, we avoid having too many curly brackets.

robloach’s picture

StatusFileSize
new830 bytes

What you are talking about are two different things. Using PSR-0 for autoloading object-oriented module code and adding namespaces to our .module procedural code are two different actionable items, both of which we could implement without harming the other. As long as we keep away from namespace conflicts, then we'll be fine.

I foresee having PSR-0 autoloading for module-provided classes with something like the attached .patch... This one obviously won't work because at this point of the bootstrap we don't have drupal_get_path(), but that's easily fixable. Would be nice to get #1321540: Convert DBTNG to namespaces; separate Drupal bits in first before we consider that stuff.

robloach’s picture

Issue summary: View changes

remove <?php as filter doesn't understand namespaces.

donquixote’s picture

@Rob Loach,

Using PSR-0 for autoloading object-oriented module code and adding namespaces to our .module procedural code are two different actionable items, both of which we could implement without harming the other.

Exactly :)
Except that it would feel awkward, if procedural would use different module namespaces than object-oriented code.

There has been recently a lot of work/talk about namespaces for module-provided classes.
#1290658: Move all module-provided classes to PHP namespaces (PSR-0 or similar), and autoload them without the registry [policy, no patch]
#1400748: Proposal for unified namespace organization
Procedural code has been considered "off topic" in these discussions, even though the decisions made there will affect procedural code, if it is going to have the same namespaces as module-provided classes.

Personally, I would have preferred a decision about namespace-per-module that does explicitly mention procedural code. Also, I am still not convinced why we absolutely need PSR-0 in all this, and why we absolutely need the Symfony class loader. However, as a majority of people strongly support PSR-0 + Symfony, I see little value in challenging that any more.

Now that namespaces for classes are discussed elsewhere, this issue is meant to be solely about namespaces for procedural and hooks.

I foresee having PSR-0 autoloading for module-provided classes with something like the attached .patch...

Yes, something like this.
There are implementation details that make me doubt that the Symfony class loader + individual namespace registration is really the best option. However, this issue is probably the worst place to discuss that.
All we need to know here is, every module gets a namespace, and we should use that for procedural and hooks (imo).

donquixote’s picture

Issue summary: View changes

Let this show up in search results for "procedural"

donquixote’s picture

Issue summary: View changes

The inventor problem is more important than I originally thought.
Add summary of motivation and goal.

donquixote’s picture

Issue summary: View changes

Use same namespaces as for PSR-0 OOP code.

mgifford’s picture

@RobLoach any reason not to toss your patch to the bots?

robloach’s picture

@mgifford Drupal already has that patch :-) . For hooks, a better route would be to go through the EventSubscriber and register your hooks/events through your module's Bundle. I think that's #1825124: Provide an Drupal\EventSubscriber override that uses natural weights, but I could be wrong. I probably am wrong, but you can see other examples of Bundle use in other core modules.

mgifford’s picture

Thanks @RobLoach. I'm just always looking for a way to help nudge problems towards solutions.

Crell’s picture

Version: 8.x-dev » 9.x-dev

Changing hooks in this way would be out of scope for Drupal 8 at this point.

Crell’s picture

Issue summary: View changes

Short summary at the top.

kristiaanvandeneynde’s picture

About the hook inventors: "{$inventor}_hook_$suffix" implements the same issues that were already reported in #2016003: Prevent potential naming collisions caused by the hook naming pattern and #548470: Use something other than a single underscore for hook namespacing.

As long as a single string contains multiple variables, separated by any separator -whether that be an underscore, an in-between word like '_hook_' or 'Talula_Does_The_Hula_From_Hawaii'- you simply cannot guarantee that at some point someone won't cause a naming collision.

The key is that we avoid to have a separator in between two variable parts of the hook name.

donquixote’s picture

I think the sensible solution would be:
- Keep the existing pattern as the default, to avoid having to rewrite big parts of core and popular contrib modules.
- Allow arbitrary callbacks to be registered as hook implementations. Especially, allow namespaced hook implementations.
- Look for Drupal\MODULE\hook_HOOKNAME() in addition to the old-school pattern.

This would provide a new consistent and safe pattern, but avoids too much work.
I am not sure this is possible in D7 though.. some existing implementations of hook_module_implements_alter() or custom hook invocations might hard-depend on the existing hook naming pattern.

catch’s picture

Status: Active » Closed (duplicate)

I don't think we have any need for procedural functions in modules in 8.x, other than hooks. Anything that's left can be converted to classes and deprecated.

Hooks have a lot more discussion in #548470: Use something other than a single underscore for hook namespacing.

So marking as duplicate.

Version: 9.x-dev » 9.0.x-dev

The 9.0.x branch will open for development soon, and the placeholder 9.x branch should no longer be used. Only issues that require a new major version should be filed against 9.0.x (for example, removing deprecated code or updating dependency major versions). New developments and disruptive changes that are allowed in a minor version should be filed against 8.9.x, and significant new features will be moved to 9.1.x at committer discretion. For more information see the Allowed changes during the Drupal 8 and 9 release cycles and the Drupal 9.0.0 release plan.