http://php.net/manual/en/language.namespaces.php
I recommend we use the following PHP namespace schema in D8 to prevent collisions:
namespace module\dblog
namespace module\dblog\hooks\system
namespace theme\bartik
namespace profile\minimal
The namespace would be declared at the top of each file and then there would be no problem of the same function being declared in multiple modules / themes / profiles. Any prefixing would simply be left off.
For hooks, it is important that they are namespaced by the module that 'invented' them to avoid the problem of multiple modules calling the same hook for different purposes. Hook functions would simply be the name of the hook, e.g. menu() .
Direct calling of functions in a different module can be done like this:
\module\system\flush_caches();
There are probably a lot of functions in the system module that don't belong there and should be in the includes directory.
See also #548470: Use something other than a single underscore for hook namespacing.
| Comment | File | Size | Author |
|---|---|---|---|
| #43 | Namespaces.pdf | 206.88 KB | jbrown |
| #42 | Namespaces.pdf | 206.88 KB | jbrown |
Comments
Comment #1
jbrown commentedTheme hooks would be similar to module hooks, e.g.
Comment #2
jbrown commentedWhen a module implements default theme functions, it would be in a namespace like this:
Comment #3
casey commentedTotally loveable... when its not to much of an performance hit.
Comment #4
donquixote commentedWhat if I want to have 3 different hook implementations in the same file, for hooks that are "invented" by different modules? This will require 3 namespaces within this file, correct? Do we like this?
Maybe this is totally ok, just wanted to mention it.
One problem could be that all following declarations would be in the last of the three namespaces, which could be unintended.
----
About "hooks" - should we say "hook" instead?
----
Do we want a "drupal" namespace as a parent for everything, to avoid clashes with 3rd party libraries? The downside would be a lot more typing..
What will be the namespace for core stuff?
Comment #5
sunWe don't need separate namespaces for module|theme|profile|etc. -- Drupal is treating all of them more and more the same. Profiles are loaded as modules, themes participate in alter hooks, etc. Thus, splitting them up would be wrong; we need to go the opposite direction.
Since almost everything in Drupal is a hook implementation or almost a hook implementation (think of form_id callbacks + subsequently invoked hook_FORMID_* hooks), there's little that would remain as regular non-namespaced function.
Not sure whether I like this idea, but it's probably primarily the syntax that annoys me.
Comment #6
Crell commented1) This is a moot point unless Drupal 8 is going to move to PHP 5.3, and it's too early to know if that's going to be the case.
2) I am tentatively in favor of using namespaces in place of our current magic naming, but there are a lot of knock-on effects to consider.
3) For instance, the use of multiple namespaces per file using the "namespace" keyword like that is very strongly discouraged. The php-internals team nearly didn't even allow it as a syntax it's so discouraged. It only works at all because some projects use a compiler to merge all of their code into one huge PHP file for deployment (a practice I never fully understood and do not encourage).
The preferred syntax for multi-namespace files is:
And note that if a file uses namespaces then NO code may exist outside of a namespace anywhere. That means it has serious implications for how we structure our files. Namespacing classes will also have a significant impact on the registry and autoloading.
4) Remember too the "use" keyword, which makes it possible to alias a class name to whatever you want. That's very powerful and very weird, as it saves typing but also allows you to have a class defined as Foo but you use it as Bar.
I am not even going to start suggesting name layouts at this point as we shouldn't bikeshed that yet until we are all on the same page about the syntax itself, and know if it's even going to be an option.
Comment #7
donquixote commentedA little bit of bikeshedding would help to get an imagination about how this could look like.
The magic naming we have now is a timebomb, if we don't add some disambiguation stuff like "_hook_", as suggested in the other issue. And still then it won't be 100% safe.
Comment #8
sun^^ Not even our code filter is prepared for Foo\Bar() mwuahahaha *SCNR*
Comment #9
jbrown commentedOkay - after reading the comments here is my current vision:
Every file that is part of a module, profile or theme has a namespace declaration at the top, e.g.
We would still have the problem where a theme and module can have the same name and conflict - but this should not be allowed to happen. #371375: Do not allow a module and theme to use the same name.
Hooks would be declared like (namespaced for the module that 'invented' the hook):
Default theme implementations would be like:
Anything not in a module / theme / profile would not be namespaced.
Comment #10
sunI believe you could already test-drive most of what you have in mind in a contributed module as a experimental environment wrapper. Implement hook_module_implements_alter(), add your module everywhere, and invoke/pass-through your own set of defined/registered, namespaced hooks.
Comment #11
Crell commentedYou can't actually write a function name like that.
To make sure we cover all basis, anyone proposing a format (and again this is all just thought experiment for now) please make certain that you cover *all* of the following cases, with code examples:
Scenario:
- Module Cool defines a hook that, in Drupal 7, we'd call hook_cool_awesome(). It is declared via hook_hook_info() to be in the "things" group, which means in D7 it could always live in $module.things.inc.
- Module Cool implements hook_cool_awesome() itself (ie, cool_cool_awesome().)
- Module Sweet implements hook_cool_awesome() (ie, sweet_cool_awesome().)
- Module Sweet implements hook_cool_awesome() on behalf of the Rockin module (ie, rockin_cool_awesome().)
- Module Sweet also offers various API functions.
And now implement it again, given that both modules want to implement their hooks using the lazy-load include file $module.things.inc, because that is more performant.
And remember, no more than one namespace foo; per file. MAYBE we can use namespace {} format, but then all code in that file MUST be in a namespace somewhere.
Please think the above through completely before posting a proposed structure. This is not a simple "oh replace _ with \ and we're done" task. There are a lot of knock-on effects to be considered.
Comment #12
jbrown commentedYes -
function hook\system\menu()doesn't work.So hook implementations would be in a namespace like:
default theme implementations would be like:
Your scenarios:
- this is unaffected - the hook implementation could still be in $module.things.inc.
These functions would be called like:
Global code can be in a file that has namespaces:
I don't think modules, themes or profiles should ever be defining any global code anyhow.
Comment #13
donquixote commentedI assume that if we start using namespaces, we will put all module functions in a namespace, not just hooks. So yes, everything in every php file will be in a namespace.
Comment #14
jbrown commented'module' shouldn't be part of the namespace - see #5
All functions that a module defines would be in the module's namespace.
Files in the 'includes' directory wouldn't have a namespace as they are not modules.
Comment #15
casey commentedYou could leave sub-namespace 'hooks' out...
sweet/cool/awesome()
Comment #16
donquixote commentedwhat if some modules want to have sub-namespaces? In this case the \hook\ would help to disambiguate.
Comment #17
jbrown commentedNo - its necessary. Otherwise a module name might conflict with some other sub-namespace, like sweet\theme. Not that there is a module called 'theme', but you get my point.
Comment #18
casey commentedThe theme namespace could be considered an api which should be unique like modules/themes.
I think it will work if all namespaces (and their sub-namespaces) belong to a certain project (with unique names) and those projects define how these namespaces should be used.
The global namespace belongs to Drupal core which restricts first level sub-namespaces to be projects only (modules/themes/profiles/apis).
Drupal core further restricts modules's sub-namespaces (second level) to always match namespaces of other projects and can be filled with function matching that other projects namespace-definition.
This could be something like this:
I've been brainstorming on this not to long ago: http://groups.drupal.org/node/47490
Which is also one of the reasons I suggested to register all core modules/themes on d.o. #706540: Register all core modules/APIs on drupal.org
Comment #19
jbrown commented@donquixote - I don't think modules should be allowed to invent their own sub-namespaces. They should be standardized.
Comment #20
jbrown commented@casey - you shouldn't totally change your comment after you have submitted it - post a new one.
Comment #21
casey commentedSorry, I know (but it was all in between 5min).
Comment #22
jbrown commentedFor the purpose of this post, 'modules' == 'modules/themes/profiles'. We need a word for these. 'framework' is a 'module' for what is in 'includes'.
#18 - I like the general concept. Oh, and its '\', not '/'.
So, I think the first term of the namespace should be the module that is being implemented.
The second term (optional) is the module that it is interacting with.
If the second term is supplied, any functions in this namespace are hook functions.
The meaning of subsequent terms in the namespace are defined by the module in the second term.
So we could have:
Comment #23
Crell commented#22 sounds almost like you're using it to group related functions, like form callbacks. I'd be EXTREMELY wary of going that far with it. Once you're talking about clustering functionality you're really into classes and objects, not namespaces. The two are very different things (despite claims to the contrary by people who kept trying to use classes as a poor-man's namespace).
I also wouldn't introduce the "Framework" pseudo-module. We already have system for that, and it's already a module. An ugly module that needs to be sliced and diced, sure, but it's a module. :-)
I don't think we can realistically prevent modules from defining their own namespaces. It will happen. We also need to consider classes, which are more what namespaces were aimed at as most of the SuperLongNameClassFrameworks are heavily OO.
There's also 3rd party libraries to consider. For that reason I would recommend a "drupal" top level namespace. That is also more consistent with the recommended PHP standards. (Disclosure: Although the group seems rather dead at this point, I am the Drupal representative to the PHP Standards Working Group.)
Comment #24
jbrown commentedI actually think it would be really excellent if every form was a class.
At the very least (if we are on PHP 5.3) we could have something like:
at the top of every file.
Files in the includes directory would have:
The only time 'drupal' would be seen in a function name would be when calling an API function in a different module, e.g.
Comment #25
jbrown commentedModule's default theme implementations could be considered as the module implementing a hook it has 'invented'.
How about this:
Comment #26
Crell commentedI have no idea what that is supposed to do.
Note: Apparently the codefilter can't handle namespace separators yet... :-)
Comment #27
donquixote commentedA theme implementation, I guess.
The equivalent to
theme_user_list()in module 'user'.I think it would be better to go like this:
Not sure how this would translate to templates.
Comment #28
jbrown commentedLet me further explain #25.
According to sun in #5, modules and themes are increasingly the same thing. So, when a theme implements a theme override, it is really implementing a hook.
The 'inventor' of the hook is the module that declares the theme function in a hook_theme().
Therefore the user module is the inventor of theme_user_list(). When it defines the default implementation it is really implementing its own hook, e.g.
When a theme wishes to override a theme function, its implements the hook, e.g.
Comment #29
donquixote commentedNo, it is not. If themes and modules are the same, this does not at all imply that hooks and theme functions are the same.
The most important difference is that hooks are usually called one time for each module, while for theme functions we usually pick one implementation.
There is absolutely no benefit in trying to unify these two concepts.
Let's try to keep the two concepts separate, and let's design the syntax in a way that makes this separation visible and explicit.
Comment #30
Crell commentedWhat don said. Just because something is called dynamically does not make it a hook. A hook is something that is called with module_invoke_all(). Anything else that is called a hook is a critical documentation bug. Full stop. (Yes, Drupal 7 now has a lot of these critical bugs. We should fix that in Drupal 8, not make it worse.)
Comment #31
jbrown commentedThe other consideration is sub-modules. Extending what is in #24, we could have
This would be at the top of the Hierarchical Select Taxonomy module files.
Comment #32
jbrown commented#29 / #30
If a function is invoked by module_invoke I would consider that function to be hook implementation, e.g. text_field_schema()
What would you call it?
I think it is perfectly reasonable to refer to a theme override function as a hook implementation.
Comment #33
jbrown commentedThe specification of theme() actually refers to the 'hook':
function theme($hook, $variables = array())
Comment #34
Crell commentedI would call "things called by module_invoke() that are referred to as hooks" a critical architectural bug, and fixing that bug is a major requirement for Drupal 8. More properly they are "magic callbacks", and in most cases are a bad idea better implemented with either a real callback or a class.
theme "hook" is also such a critical architectural/documentation bug. We absolutely should not enshrine that bug into the namespace architecture.
Comment #35
jbrown commentedtheme() calls a lot of "magic callbacks":
http://api.drupal.org/api/function/theme/7
You have a better idea of how theme() should be implemented?
Comment #36
Crell commentedtheme()'s implementation isn't bad. There's room for improvement but I'm not suggesting a total gutting of it. But calling theme_table() or theme_page() a "hook" is, quite simply, wrong.
If we're talking about, say, the various callbacks for implementing a Field in Drupal 7 then those do need to be redone as objects, because that's what they are, just with a backward syntax. Calling those hooks is, I think, a documentation bug that is too late to fix now and is going to bite us in Drupal 7.
My point, to get back on track, is that if we're going to bake "hooks" into a namespace implementation then we need to be very careful about only applying it to things that really are hooks because our current fuzzy and gooey use of the word is going to then bite us very hard in a not very comfortable place.
Comment #37
jbrown commentedI'm no longer interested in using PHP namespaces for hooks. I think its a bad idea.
At the top each file we should just have one of the following:
We can use __ for making magic callbacks more robust.
I've submitted a core lightning talk presentation on this for DrupalCon. We should discuss this more then.
Comment #38
Crell commentedI'm not sure that submodules are a good idea either, as from a Drupal perspective there is only a single module space. But yes, this is a perfect topic to discuss in CPH. I'll see you there. :-)
Comment #39
jbrown commentedYes - you are right about the sub-modules!
I just thought of another interesting thing that can be done with namespaces - PHP wrapper functions. http://api.drupal.org/api/group/php_wrappers/7
When we are in namespace drupal, we can simply declare a new substr() or whatever.
When substr() is called from within namespace drupal, \drupal\substr() will be called.
When the native PHP function needs to be called, e.g. inside the wrapper function it can be invoked like \substr()
How cool is that?
Looking forward to discussing namespaces at DrupalCon.
Comment #40
jbrown commentedActually - if we are in namespace drupal\MODULE, then substr() would resolve to \substr() not \drupal\substr().
So, PHP wrapper functions should always be fully qualified.
http://www.php.net/manual/en/language.namespaces.rules.php
Comment #41
wim leersSubscribing! Very interesting, but haven't made up my mind yet what I like and dislike. I need to let this sink in I guess. I do like the overall idea though, of organizing code more rigidly, to make code more legible/findable/maintainable.
Comment #42
jbrown commentedHere is my presentation on this issue.
Comment #43
jbrown commentedThere was an error in the 'Theme implementations' section of my presentation.
Here is the fixed version.
Comment #44
drifter commentedI'm interested in this from a code readability standpoint, and don't care that much about technical purity. Omitting long prefixes from function names is awesome for readability. If we could fix abominations like these:
It would be very much worth it. So, from a simplification point of view, do we really need the \drupal namespace?
\drupal\db_update()seems awfully verbose to me...Comment #45
Crell commentedIf we're going to do namespaces, we should do them in a way that's polite to other PHP code you may be joining with Drupal. That means namespacing our own code so that we don't collide with other libraries.
Comment #46
jbrown commentedSee http://bluedroplet.com/blog/proposal-fixing-php-namespacing-drupal-8
Comment #47
donquixote commentedI like the proposal in #46.
At first I thought hooks should be like
function drupal\\implementor\\hook\\inventor\\hooknamebut hey this is totally not how namespaces work - we would have to declare a namespace
drupal\\..\\inventorthen, which is not desirable.So, with #46 it would become (as a preview for that external page)
function drupal\\implementor\\inventor__hooknamefunction drupal\\implementor\\inventor__hookname__param1__param2of course you would not see the "
drupal\\implementor\\" part.For theme functions, with #46 we would get
function drupal\\inventor\\inventor__theme__themehookname()(where inventor is a module)function drupal\\implementor\\inventor__theme__themehookname()(where implementor is a theme, not a module)On theme('inventor__themehookname'), drupal would have to explode the name to determine the inventor, then look in the inventor namespace, if it does not find anything in the theme namespace. Is this a good thing?
Anyway, the proposal looks quite reasonable to me, and I would like this to move forward.
I suffer from bad paranoia every time I have to come up with a function or module name.
Comment #48
robloachInstead of namespacing by module/theme path, we should namespace by how the system works. We already have segregation of the file system in the file system, having namespaces define them does not help us.
For example: All implementations of hook_node_view(), hook_node_load(), etc, should be part of a Node/Entity namespace. All implementations of hook_help should be part of a Help namespace, etc. Look beyond the modules, themes and files, and think of what it's trying to accomplish.
......Hmmm, maybe not...... Argh, PHP is such an ugly language.
Comment #49
donquixote commented#48: Been there done that - in my head.
More than one namespace per file is very unpleasant to write.
Besides, we want to solve this problem not just for hooks, but for anything that can nameclash.
Comment #50
Josh The Geek commented-1 I don't like the idea of this, because a) it will make coding more confusing, and b) it would make Drupal require PHP 5.3. For shared hosting, I can't get PHP updated, and I would like to be able to update to Drupal 8 when it comes out.
Comment #51
bfroehle commentedIs it unreasonable to expect that a year or 18 months from now most webhosts would have upgraded to PHP 5.3?
Comment #52
donquixote commented@bfroehle,
where did you find this? I guess here,
http://www.php.net/archive/2010.php#id2010-12-16-1
(just so people have a link)
Comment #53
donquixote commented#46, #47:
I wonder if we need container namespaces for modules and themes.
For instance,
drupal\contrib\develordrupal\custom\mymoduleordrupal\some_3rd_party\modulename. This would allow more freedom in naming one's private or site-specific modules.We have to consider that the same module might exist in different container namespaces. For instance, the module might have been created as something site-specific, but then published on drupal.org.
We would need an easy and well-documented way to replace a module
drupal\custom\awesome_home_grownwith the just downloaded versiondrupal\contrib\awesome_just_releasedon an existing site.We would also need a dependency system where one module can replace another.
The home-grown module
drupal\custom\mymenucould declare in its info file that it replacesdrupal\core\menu, and that it is mutually exclusive withdrupal\core\menu.Then another module that explicitly depends on
drupal\core\menuwould be just as happy withdrupal\custom\mymenu.EDIT:
Another consequence: Every time we deal with module or theme names, we would have to say the namespace and the module. This could be a serious pain.
I guess for the start we should simply drop this idea.
Comment #54
catchWe should really remove the 'feature request' and 'support request' categories from the core issue queue, there's no such thing that belongs in the queue.
I don't like the idea of submodules, they don't exist as a concept now so I don't see why we'd want to introduce that on the back of this.
drupal\MODULE feels like enough of a namespace to me, not sure what else we could want from this?
I'm pretty sure that #1058720: Lazy load modules depends on this since currently there is no way to reliably link a menu or theme callback with a module, and without a major change to those APIs I don't see a better way to do this than namespacing.
Comment #55
chx commentedLovely. After writing DBTNG which I was forbid to make readable you want to use something which is even less grep-able?
Edit: for those who dont remember, i wanted to add a comment to every function definition to tell use what it belonged to 'cos it's freaking unreadable.
Edit2: it's more than grep, of course, you get an error about line 545454 in foo.inc you open it and you see
tell me if you can where you are.
Comment #56
Crell commentedchx if you're going to troll, at least troll on topic. Thanks.
Comment #57
chx commentedI am trolling on topic. Namespaces will lead to even more same named functions. And you will not let me comment those either, will you?
Comment #58
Josh The Geek commentedI agree with chx. Drupal code is getting more confusing, but let's at least keep it somewhat readable.
Comment #59
donquixote commentedSo you need to write more powerful grep or ack, also asking for filename or path.
Which brings a valuable new point into the discussion: If we go namespaces, then we should also introduce a consistent and grep-friendly file naming scheme. The goal is that the file can tell us about the module name, so that file name + function name gives a pinpoint grep.
(probably sufficient to keep the existing quasi-standard of modulename.something.inc and modulename.module etc, just need to enforce it even more)
Comment #60
Josh The Geek commentedOne more thing: on a.d.o, how would we search for a function if there is more than one instance of that function?
Comment #61
donquixote commentedI guess, you would search for something like
modulename\\functionname, or just
modulename-functionname, or
drupal\modulename\functionname
Obviously, api.d.o needs some work to fully support this. But that was to be expected.
Comment #62
chx commentedSo you need to write more powerful grep or ack, also asking for filename or path.
short of doing full-file parsing with awk how on earth do you plan to find the "last instance of namespace prior to this function"? say, with grep. Also, once again, it's not just about the grep/ack,it's about the poor user trying to figure out an error.
Comment #63
mikl#62: I think the same thing could be said for classes. It's kinda hard to use grep/ack to figure out what class you're in.
That being said, I think this issue is all concerned with the how of using namespacing in D8, but fails to answer the burning questing is: Why? Changing the central paradigm of Drupal development should not be done lightly.
I don't see how this is an improvement, and just because we can use namespaces, doesn't mean we have to :)
Comment #64
donquixote commented#62:
> short of doing full-file parsing with awk how on earth do you plan to find the "last instance of namespace prior to this function"?
I imagine we will rarely have more than one namespace per file.
So, what exactly do you want to find?
#63:
Why? Because I dream of nameclashes in my sleep.
It's a miracle that it does not already explode somewhere (not that I know of, at least). Although, I remember some bugs that had to be fixed by renaming a function that was mistaken as a hook implementation.
Comment #65
chx commentedOh my if hook naming is your only problem then #548470: Use something other than a single underscore for hook namespacing
Comment #66
catchI want some namespacing of callbacks as well as just hooks - so we know which module particular functions belong to - particularly the menu and theme system. However that could be done as part of #548470: Use something other than a single underscore for hook namespacing and I don't see any particular benefits to using 5.3 namespaces over a convention - one of the main reasons given in the php.net docs for namespacing is avoiding really long function names, and I love really long function names ;)
I also agree that looking through modules and everything being function load() is going to make for a nightmare scenariou (particularly if hooks are a namespace, wouldn't that mean node_load() hook_entity_load() hook_node_load() hook_comment_load() and drupal_load() would all be written as function load()).
Comment #67
donquixote commented#548470: Use something other than a single underscore for hook namespacing
This would make the situation a lot better.
It would not solve the ambiguity of "Does function something_foo_bar() belong to module something_foo or to module something", but it does solve the much more serious ambiguity of hook names.
On the other hand: If at a later day we switch to real namespaces, then the _hook_ separator change will have been a lot of work for nothing.
At some point in time this was what I was thinking. But, thinking further about how namespaces in PHP actually work, I no longer support this.
It turns out (for me) that the proposal in #46 is not so bad after all. With this proposal, namespaces tell us which module a function belongs to. Anything else is done with '__' or, if you want, '_hook_' separator.
We will have exactly one namespace per module, and never more than one namespace per file.
------------
We could probably achieve the same disambiguation with a lot of '__' and '_hook_' all over the place, if we do this not just for hooks, but also for regular functions. If someone could convince me that this is and always will be better than using native namespaces...
-----------
Finally, namespaces will make it easier to integrate 3rd party code.
Comment #68
quicksketchConsidering there is very little action on this issue (not to mention questionable need or desire for it), I'm downgrading to normal. "major" tasks are now preventing development of any new features in Drupal core per the new policy at http://drupal.org/node/1201874.
Comment #69
quicksketchAlso considering I regularly teach classes on Drupal module development, I also want to put in my -1 for this idea. PHP-isms like this are exactly what make people get up and leave in the middle of a class out of frustration. That is assuming that would come to class at all because they hadn't given up on Drupal already. I would much rather see #548470: Use something other than a single underscore for hook namespacing implemented to avoid the accidental hook implementations.
Comment #70
podaroksubscribe
Comment #71
merlinofchaos commentedI have trouble believing that, if properly documented, students would get up and walk about. IMO, this is very clear, assuming we get the actual structure of the hook naming correct:
In fact, I would bet that if you introduced that to someone who didn't know anything about Drupal, it would be *quicker* to teach hooks using this method than it would be using our current magically named method.
Comment #72
merlinofchaos commentedTo answer the questions of why:
1) It reduces ambiguity.
2) It is, IMO, more readable.
3) It encourages module developers to group their hooks together which organizes code.
The __ method for reducing ambiguity is difficult. We use that method in theme implementation names, and I must say, we get some really darn long names. We actually reduce the names, slightly, by eliminating the modulename from the function name because of the namespace. For short modules like 'views' that doesn't mean much, but for longer module names like entity_revision_scheduler that actually can lead to some very long hook names. This doesn't seem like much but I think there's a lot of mental weight there. Imagine:
function entity_revision_scheduler_form_node_form_alter()-- that's getting to be a long enough function name that it's difficult to parse. Adding an extra _ helps a little, butentity_revision_scheduler__form_node_form_alteris still annoying.Comment #73
merlinofchaos commentedOne interesting sidenote:
It's a lot easier to change the name of a module with this syntax.
Comment #74
boombatower commentedWould agree that this looks much clearer and what people are used to since this looks almost the same as object oriented approach.
Comment #75
Crell commentedJust so we're clear: http://us2.php.net/manual/en/language.namespaces.definitionmultiple.php
So using {} namespace syntax directly would be directly against the recommendation from the PHP developers.
Comment #76
merlinofchaos commentedYes, but we would be using namespaces for different purposes than they intend, so their recommendation would be counter to what we're trying to accomplish. I personally don't have a problem with that (and I don't really think anyone thinks that PHP itself is a solid source of style information, since it isn't even consistent with itself.)
Comment #77
Crell commentedI admittedly do not have a response to that. :-)
Comment #78
donquixote commentedIMO we should find a namespace pattern that works for classes, functions AND hooks.
Ideally, also for auto-detected plugin classes.
If we don't do that now, we will have a big mess to clean up in D9.
Let's not pretend this is so difficult. There are some design decisions to make, but there is only a finite space of possibilities that are reasonable and practical.
Namespace per module
From the discussion about class namespaces (#1290658: Move all module-provided classes to PHP namespaces (PSR-0 or similar), and autoload them without the registry [policy, no patch]), I get the idea that most people agree on a namespace-per-module pattern. There can be exceptions, in that some modules might ship cross-namespace third-party libraries, but most of a module's classes can live within the module's own namespace.
IMO, this namespace-per-module should be designed to be the home for classes and for functions. Most of the big frameworks we could look at don't have any significant use of ("floating") functions, but Drupal has, and I don't see them suddenly disappear.
The only issue I see here is the ucfirst/camelcase vs underscore. under_score literal module names look better with functions, whereas ucfirst/camelcase looks better with classes.
For my taste, explicit unmodified module name is preferable. But this can be discussed.
I also think most of us agree that module namespaces should begin with "drupal\" or "Drupal\", and should be followed by something like "module\" or "modules\" etc, to distinguish it from core library classes or 3rd party code.
Possible patterns for namespace-per-module:
Hooks
Whatever we do with hooks, I think it should live within the module's namespace.
On the other hand, they should be distinguishable from regular functions, or regular functions living in arbitrary sub-namespaces.
A sub-namespace could be used to tell about the "inventor" module, but this is at the cost of having to type and read more curly brackets. Not worth it for my taste, but can be discussed.
Possible patterns:
The first one is easiest to type, because we will have only one namespace per file.
It is not 100% safe against hook nameclashes (two modules "inventing" the same hook name with different meaning), but probably good enough. After all, it is probably as likely as two authors making a module with the same name.
It does, however, prevent regular functions from being falsely interpreted as hook implementations. This is the main problem we want to solve.
Auto-detected plugin classes
Whatever we do here, I think it can and should live within the module namespace.
And, auto-detected plugins should be distinguishable from regular classes.
Possible patterns:
-------------
I think this is the design space we should be talking about.
Other than that, I can only think of inconsistent and half-assed solutions.
Esp, trying to have different patterns for classes functions and hooks, will only bring confusion.
Comment #79
donquixote commentedOoook.
Now that we more or less decided on namespaces for module-provided classes, what is left to discuss here is namespaces for module-provided functions.
For those who still think this is a theoretical problem:
#1425182: Fatal error Cannot redeclare user_delete_access() with Drupal-6.24
That's the typical prefix clash, where one module name ("user") is the prefix of another module name ("user_delete"), and thus, just prefixing a function with the module name is not sufficient to prevent a nameclash.
This example is without any hooks. hooks are just a multiplier to the kind of nameclash, but they are not necessary for a nameclash.
Result in the other discussion was a namespace pattern for classes like this:
Drupal\Module\my_module\SomeClass
If we simply use the same pattern for functions, we get
Drupal\Module\my_module\some_function()
For hook implementations, a very simple pattern would be
Drupal\Module\my_module\hook_menu_alter()
The "hook_" prefix within the namespace would indicate a hook implementation.
Looks pretty simple and robust, doesn't it?
Comment #80
robloachNot quite sure how PSR-0 wasn't mentioned here. Might be out of scope for this issue, but thought I'd reference:
#1240138: Adopt PSR-0 namespace convention for core framework classes
Comment #81
donquixote commentedI think the PSR-0 stuff has already been decided.
Maybe we should rather open a new issue specifically about namespaces for functions and hooks?
Comment #82
jbrown commentedThe first step is to put
in every PHP file. This issue already exists: #1393208: Namespace all Drupal PHP code (esp. procedural).
Comment #83
donquixote commentedPlease, we are long beyond that.
Let's not start from zero each 7th post.
Yes, Drupal should the root namespace for everything in core, contrib and in custom drupal-related code. But before we do a patch, let's agree on something complete.
If you simply put "namespace Drupal;" at the beginning of each file, this sounds like a "first step", but it does not help anyone to commit that (imo).
EDIT:
It looks like there is really a lot of valuable work in jbrown's patch in #1393208. Even if we change Drupal to Drupal\Core or something else, we can still benefit from this work.
Comment #84
jbrown commentedDid you actually look at the issue I linked? It does a lot more than just putting a line in every PHP file. It removes any drupal_ prefix from functions and DRUPAL prefix from classes. It also implements the considerable number of fixes for Drupal to be able to function under namespace Drupal.
If / when it is decided that all PHP code in Drupal should be under namespace Drupal then #1393208: Namespace all Drupal PHP code (esp. procedural) is the place to go to implement it. The bulk of the work has already been done. The advantage of this is that people can look at the patch and form an opinion about whether or not it is a good idea.
It is important to develop an overall pattern for how namespaces should be used for Drupal and modules, but it wouldn't make sense to have a massive issue doing it all in one go.
If it is decided that non PSR-0 code should be namespaced, then smallest possible first step to implement it would be what is happening in #1393208: Namespace all Drupal PHP code (esp. procedural).
Comment #85
donquixote commentedA (complete) proposal for module-provided functions and hook implementations can be found here,
#1428592: Proposal: PHP 5.3 Namespaces for module-provided functions and hook implementations.
I think that is better to start a clean discussion.
@jbrown,
I replied in the other issue.
Comment #86
Crell commentedPSR-0 applies only to classes.
Dear god, do we need ANOTHER thread for this? Why? There are about 6 already, most half-duplicating each other. Did you see chx's proposal for namespaced hooks?
That said... I'm not convinced we SHOULD namespace our functions. For one, we're eliminating a lot of them, hopefully. Functions cannot lazy-load. And you also cannot alias/import/"use" functions, which means the actual function name you call then has lots of slashes in it. Do we really want that?
I'd rather just eliminate most functions in favor of properly factored classes, which gets us lazy loading, aliasing, and forces us to decouple things better, which we should be doing anyway.
Comment #87
jbrown commented@Crell at DrupalCon DC you said that we should only use OO where it makes sense to do so. You were right. Moving all of core into classes is not desirable. You've also iterated many times that using OO for modules / hooks makes no sense. non-OO code is not going away.
There would only be a single slash in function calls into other namespaces, e.g.
Core\write_record()ornode\load().Lazy loading classes is not the only reason why namespacing is beneficial.
We are already namespacing our functions, e.g. we prefix them with
drupal_or the module name. Doing this formally using a facility of the language has many advantages:drupal_and some are not.drupal_orhierarchical_select_.taxonomy\select_nodes(). This will result in higher quality and more maintainable code.use Drupal\Module\systemin non-module code.Comment #88
donquixote commented#548470: Use something other than a single underscore for hook namespacing
This is a hijacked thread.
There is plenty of discussion about using "_hook_" or "__" as a separator, until suddenly it is being switched to a PHP 5.3 namespace discussion. I don't like this.
And most of them filled with stuff that is now obsolete. Such as, questioning whether PHP 5.3 is acceptable as a requirement for Drupal 8.
Name clashes are real - even without hooks.
And they make me paranoid, every time I choose a module name.
#1425182: Fatal error Cannot redeclare user_delete_access() with Drupal-6.24
Nameclashes can happen with other modules, with Drupal core, with 3rd party code, and with php native functions.
And, namespaces do not only prevent nameclashes, they also help to identify where a function is defined / belongs to.
Yes, but.
I'd prefer living with functions for a while longer, instead of panic-mode "hey, look, every function in my module is now a static method, hooray." Let module maintainers choose their own speed at which they want to transition to OOP.
We can live with that.
There is some kind of lazy-load for hook implementations and registered callbacks. For the rest, we can use old-school explicit module_load_include(), I think we will survive it.
To call a function within the same module, no slashes are required.
For a function in a different module, the slashes are helpful.
For frequently-used Drupal or contrib functions, it is enough to alias the namespace.
Currently if you see a function named menu_block_foo(), or user_delete_access(), how can you tell for sure which module that is?
With namespaces that would be
Drupal\Module\menu_block\foo().With aliases, it might be
M\menu_block\foo().I agree, this is more "slashy".
Comment #89
jbrown commentedIf you import
Drupal\Module\menu_blockthenbecomes
As you point out, another advantage of namespaces that I didn't mention above is that it removes the ambiguity in hook implementations of where the module name ends and where the hook name begins.
Comment #90
valthebaldIs this issue still relevant?
Comment #91
jbrown commentedWe can re-visit this next time...
Comment #92
ianthomas_ukOOP code was handled in #1290658: Move all module-provided classes to PHP namespaces (PSR-0 or similar), and autoload them without the registry [policy, no patch], procedural has #1393208: Namespace all Drupal PHP code (esp. procedural) (which is probably a won't fix).
Comment #93
donquixote commentedMaybe if we don't go to convert all procedural code, an intermediate thing would be to make sure that everything that takes a callback does also work with namespaced procedural callbacks.
And maybe even allow (but not require) namespaced hook implementations.
This could go into separate issues, of course.
Comment #94
donquixote commentedThis would allow future contrib authors to opt out of the nameclash minefield for procedural code, but we don't have to rewrite all the remaining procedural code in core.