Problem/Motivation
There's a couple of pieces here. First, we've adopted PSR-0 for *core* classes, which has its own specification for how code is laid out on disk. That fact needs to be added to the coding standards.
Second, we need to document how we reference namespaced classes. There's a number of different ways that it could be done, technically speaking. The following are all PHP-syntax-legal:
use Drupal\Subsystem\Foo;
$f = new Foo();
use \Drupal\Subsystem\Foo;
$f = new Foo();
$f = new Drupal\Subsystem\Foo();
$f = new \Drupal\Subsystem\Foo();
$f = new Drupal\Subsystem\Foo();
$f = new Drupal\Subsystem\Foo();
namespace Drupal\Subsystem;
$d = new \DateTime();
namespace Drupal\Subsystem;
use \DateTime;
$d = new DateTime();
Clearly we want to try and standardize...
Proposed resolution
(description of the proposed solution, the rationale behind it, and workarounds for people who cannot use the patch)
Based on the PSR-0 standard, the conventions that Symfony appears to be using, and a desire to not completely invalidate all existing code, I would propose the following:
A file that declares a namespace:
- Must "use" all classes that it will reference that are in a namespace.
- Must "use" all classes that it will reference that are not in a namespace (including PHP-native classes).
- Must not change the name of a class when importing unless not doing so would cause confusion or name collision.
A file that does not declare a namespace (which right now is everything in core except the Symfony directory):
- Must "use" all classes that it will reference that are in a namespace.
- Must not "use" all classes that it will reference that are not in a namespace (including PHP-native classes).
- Must not change the name of a class when importing unless not doing so would cause confusion or name collision.
All files should:
- Always reference a class literal name by its short name (whether because it's in the same namespace or has been imported with "use").
- Always reference a dynamic class name in a string with a fully qualified name, which does NOT begin with a leading \.
- When importing a class with "use", must include a fully qualified name and do NOT include the leading \.
(The lack of a leading \ is recommended by the PHP documentation.)
That is, all code should look like this:
// Foo.php
namespace Drupal*Subsystem;
use DateTime;
use Drupal\Othersystem\Cat;
// Bar is a class in the Drupal\Subsystem namespace in another file.
class Foo {
public function __construct(Bar $b, Cat $c) {
$d = new DateTime();
}
}
// example.module
use Drupal\Subsystem\Foo;
function do_stuff(Foo $f) {
$d = new DateTime();
}
Note that this puts all of the \ silliness up at the top of the file, and also creates a nice index of everything a given file depends on.
When importing multiple classes, if they would cause a name collision then they should both be aliased in the use statement for clarity. The alias should be formed by adding the preceeding namespace as a prefix. That is:
use Foo\Bar\Baz as BarBaz;
use Stuff\Thing\Baz as ThingBaz;
function test() {
$a = new BarBaz(); // This will be Foo\Bar\Baz
$b = new ThingBaz(); // This will be Stuff\Thing\Baz
}
That helps keep clear which one is which, and where it comes from. Aliasing should only be done to avoid collisions of that sort.
Remaining tasks
Convert the above into proper handbook-ese once we agree on it.
API changes
I don't know that this qualifies as an API change per se.
Comments
Comment #1
webchickEvery PHP tutorial I've ever read in my life (such as http://www.php.net/manual/en/language.oop5.basic.php) has used the following syntax for instantiating an object:
So I would reject any of the
$f = new Drupal*Subsystem*Foo();
-type variants on their face for that reason.Looking at PHP.net's documentation for namespaces http://ca.php.net/manual/en/language.namespaces.nested.php shows:
Nowhere is there reference to a
\Foo\bar
syntax, so let's reject that as well.The "use" documentation I couldn't really make heads or tails of http://ca.php.net/manual/en/language.namespaces.importing.php but I think your proposal is inline with the suggestions there.
So in other words, I think the proposed resolution is fine, though I lament the additional complexity this pushes down to module developers. :(
Comment #2
Crell CreditAttribution: Crell commentedComment #3
neclimdulI'm against ruling out the
$f = new Drupal\Subsystem\Foo();
syntax because its handy for one off references and explicitly specifying the namespace where it might otherwise be confusing. Crell has voiced that this can be handled with aliases which if that's that solution need to be discussed here. I think that sometimes that could be useful but breaks the simplicity of a language construct provided to us.I'd like to hear why Symfony doesn't use the leading /. That said, I think its probably fine and a good idea we stay consistent with them. I seem to remember it existing as a under-documented feature in C++ too that existed so you could say "using namespace Foo::std" but also reference "::std" so the same logic probably applies to PHP.
I think the more important we should provide guidelines and and leave some interpretation to the developer to leverage the language. Something like:
1) We don't use leading \'s
2) Only use
namespace
when defining namespace's as it must be the first line of the file(http://www.php.net/manual/en/language.namespaces.definition.php) and expect it has some different semantics.3) Prefer
use
over explicit inline resolution except where it makes the code more clear.4) Notes on aliases which I don't really have any ideas on ATM.
Comment #4
socketwench CreditAttribution: socketwench commentedI'm unsure if anyone has noticed, but the day after webchick's comment, the PHP Nested Namespace documentation page was updated. It now reads:
Where the *s are replaced with backslashes.
Comment #5
Crell CreditAttribution: Crell commentedUm, how is that different than what webchick wrote? (Give or take the \ in her post getting eaten by codefilter...)
Comment #6
neclimdul@Crell it has more then one namespace and clearly shows not using the leading \. I'm not sure it really affects the discussion in anyway though.
Comment #7
jhodgdonCrell: webchick specifically wrote "Nowhere is there reference to a \Foo\bar syntax, so let's reject that as well." , so I am assuming she didn't see the slashes.
Comment #8
socketwench CreditAttribution: socketwench commented@jhodgdon Right. My guess is that the PHP doc page might have been missing the slashes at the time Webchick looked at it. The next day the doc page was updated -- adding the slashes.
Comment #9
webchickSorry. Codefilter did indeed eat my slashes in #1. The page showed the same content as #4 when I read it.
What it did not show though, and still doesn't, is the \MyProject\Sub\Level variant with a leading \. Which is why I'm saying we shouldn't use it.
Comment #10
Crell CreditAttribution: Crell commentedI'm going to make two additional notes here before moving them up into the summary:
1) When in a namespaced file, global functions must be prefixed with \. That is not a Drupal standard; it's a fatal error if you don't. :-) Sucks, but that's PHP for you. (We just ran into this in WSCCI earlier today.)
2) When importing a class, if you DO need to alias it to a new name in order to avoid collision with another imported class, it should always be imported as the preceeding namespace used as a prefix. That is:
use Foo\Bar\Baz as BarBaz;
use Stuff\Thing\Baz as ThingBaz;
That helps keep clear which one is which, and where it comes from. Aliasing should only be done to avoid collisions like that.
3) (Nobody expects the Spanish inquisition!) I grant that some of our epically long files may get a bit clumsy with an imported class all the way at the top of the file (where it has to be) that is then used down around like 3000. I view that as a very good incentive to stop having 3000 line files, which are a terrible idea anyway. It's already impossible to follow those things.
Comment #11
webchickCan you provide a code snippet that demonstrates 1) ?
Comment #12
Crell CreditAttribution: Crell commentedHm. OK, ignore #1. I thought we ran into it, but it was actually something else. My error. (I told you I only had 2 points to make! :-) )
Any objection to moving #2 (aliasing pattern) up into the summary?
Comment #13
neclimdulRan across an example of needing(or at least a logical usage of) the leading \. Documenting it here for discussion: https://github.com/fabpot/Pimple/blob/master/tests/Pimple/Tests/Service.php
Basically, its a class in the Pimple\Test namespace extending a class in the global namespace. It might also be logical(if not necessary) for us to use this in situations like:
Comment #14
catchBumping this to major, would be good to get this resolved before we add any more namespaced code.
Comment #15
Crell CreditAttribution: Crell commentedAccording to lsmith, the reason Symfony doesn't use a leading \ on use statements is that by the time they decided they should standardize that, they seemed to be not using it more than they did. It was a completely arbitrary decision.
Personally I prefer having the leading \ on use statement myself; the only reason to not use it would be consistency with Symfony, but they have different internal coding standards anyway (4 spaces, non-inline braces on functions, etc.) So that shouldn't be a deciding factor either way.
As long as we're consistent it doesn't make a huge difference.
Since there were no objections I will add the aliasing recommendation to the summary.
Comment #16
pounardThe leading slash seems good to me, it definitely wipes out potential conflicts. (namespace A\B\A\B for example could create conflicts if you use A\B\Something within \A\B).
Comment #17
neclimdul@Pounard same reason I'd prefer the leading \ too.
Comment #18
casey CreditAttribution: casey commentedI'd like to suggest the following pattern:
For example:
core/modules/entity/entity/Entity.inc
core/modules/node/entity/NodeEntity.inc
Or:
core/modules/field/field/FieldWidget.inc
core/modules/text/field/TextareaFieldWidget.inc
And a little bit off topic, I think blocks, pages, forms, input filters, etc, should be controller classes too:
core/drupal/page/Page.inc
core/modules/node/page/AdminTypesPage.inc
Comment #19
Crell CreditAttribution: Crell commentedcasey: We're discussing the syntax in this thread, not the organization. The organization is in another thread somewhere. :-) The key there is class loading performance. Let's keep this thread to syntax.
The leading \ or not in a use statement seems to be the only outstanding question. Symfony doesn't use it. PHP core, when it generates a namespace, apparently doesn't either. Should we not use it then, for predictability?
Comment #20
casey CreditAttribution: casey commentedAccording to http://php.net/manual/en/language.namespaces.importing.php:
So yes, seems obvious to me.
Sorry for my previous post. Could you give me directions to that thread please?
Comment #21
neclimdulDangit, that's pretty clear. I guess no on the leading slash which is against my preference. :(
Comment #22
Crell CreditAttribution: Crell commentedBah. Yeah, I guess it's no leading \ then. Blargh. I'll update the summary.
Any other comments? I can't RTBC this myself. :-)
Comment #22.0
Crell CreditAttribution: Crell commentedAdd rules for aliasing.
Comment #23
webchickSure, I'm comfortable with the current proposal. Thanks casey for finding a definitive resource on the leading slash question. Sorry, neclimdul!
Comment #24
catchJust so I don't open this from the commit queue again ;)
Comment #25
pounardYay, this issue is a quick win!
Let's write OO!
Comment #26
catchLet's do this actually.
Comment #27
Crell CreditAttribution: Crell commentedAssigning to myself to integrate into the standards handbook. Mostly copy and paste work, methinks.
Comment #28
Crell CreditAttribution: Crell commentedNamespaces are now documented here: http://drupal.org/node/1353118
Marking this to fixed. Open new issues for any further tweaks to that page, I guess.
Comment #30
webchickSince the bulk of these standards are already established, calling this "normal" now.
But reopening based on discussions in #1321540: Convert DBTNG to namespaces; separate Drupal bits. There's a DX trade-off between the "use" keyword and absolute references to the class.
In Drupal 7, if you want to implement hook_query_alter(), as with every other hook, you go to its api.d.o page, copy the example, paste it into your module, and start hacking.
In Drupal 8, if DBTNG is moved to PSR-0 and we keep the "use" recommendation, this would change to, go to its api.d.o page, copy/paste the example into your module, then figure out where in the bowels of includes/Drupal the AlterableInterface class lies in, then scroll to the top and add a 'use' clause for that, then scroll back down to your pasted code and start hacking.
If we instead used absolute references like Drupal\Database\Query\AlterableInterface in the function signature, we'd retain the same DX as D7.
Additionally, David Rothstein notes (http://drupal.org/node/1321540#comment-5413124):
Thoughts?
Comment #31
pounardI agree with reopening this discussion. I would tend to think that in pure OOP/PSR-0 code following a strict standard seems good (always use the "use" statement) because files will always be small enough to see the use not far; But in procedural code where some module files can be multiple thousands lines, we could use the fully qualified names in there, and use the "use" statement in those files only when we need to use the same class name more than once.
Comment #32
Crell CreditAttribution: Crell commentedI'd be more inclined to use namespacing as another argument to not have multi-thousand-line files, personally. Those are a DX problem all their own.
At the very least for OO code, we should be picky about using use. For procedural code I would rather be picky there as well for consistency, but I can see the argument to be more forgiving. As catch noted in the DBTNGTNG issue, though, a "sometimes do X, sometimes do Y" standard can be really annoying to self-police.
Comment #33
jbrown CreditAttribution: jbrown commentedI think code examples that are designed to be pasted into modules should work without having to modify namespace imports at the top of the page. For this to work all classes / interfaces they refer to must be qualified, e.g. Drupal\Database\QueryAlterableInterface
However, if a file is referring to the same class multiple times, it makes sense to import the class to "optimize" the developer experience of the file. It's really just a shortcut to things that are used frequently.
So I think both should be permitted. It's okay to give developers a bit of flexibility.
On another note, there is a mistake in the standards:
This is not true - it is perfectly fine to have unescaped backslashes in single quotes - I do it all the time and it looks much better. The only exception is if the backslash is to be the last character in the string. In this case it must be a double backslash, otherwise it would be a literal single quote. This situation doesn't arise unless you are composing a qualified name of a namespaced resource via concatenation.
Comment #34
webchickYeah, I would be fine amending the coding standards to just say that things like hook implementations and theme functions should use the fully-namespaced name, else fall back to 'use' (particularly when something's used more than once in a file). That would get rid of most of my DX concerns, I think.
Comment #35
David_Rothstein CreditAttribution: David_Rothstein commentedIf the standard is "only for OO code" or "only for things that aren't hook implementations and theme functions" I think that would be a little confusing. Looking at the patch in #1321540: Convert DBTNG to namespaces; separate Drupal bits, that means places like node.module would not use "use" statements, but various simpletest files would.
How about instead, only use it for code that is already namespaced? In other words, if you have a
namespace XYZ;
statement at the top of your .php file, you should go ahead and use "use" statements also, since you're already living in a world where different rules apply. Because once you're in a namespace, you already have to put things likeuse Exception;
at the top of your file (unless you want to type "\Exception" rather than "Exception" everywhere else, which is weird).So in core, that would basically boil down to using this syntax in OO libraries within the includes/ directory, but using the full class names everywhere else.
Comment #36
jbrown CreditAttribution: jbrown commentedWorks for me!
Comment #37
Crell CreditAttribution: Crell commentedI have to say I'm very much against "not in procedural code" as a standard. That makes it very inconsistent between different files. That forces devs to remember "OK, here, I call this class X, but over here XXY, and over here X, no, wait, what's this class here? I don't know if it's shortened or not, um..." Consistency is important.
Also, when you factor in namespaces class names are going to get *very long*. That's going to make readability much much worse.
The only argument I can see for using a full name (which otherwise completely defeats the purpose of namespaces in the first place) is easy copy/paste of hook implementation signatures. Even there, though, the problems above still apply. It's introducing confusion because you have to remember to sometimes give a full name, sometimes, not, and oh wait what if you do use a class name more than once in a file, now you're typing crazy-long names a lot, which again defeats the whole purpose of namespaces.
-1 from me to not "use" classes anywhere except hook signature type hinting. The easy copy/paste ability there is the only argument I've heard that carries any weight. And even then, we should allow people to be "proper" about it and still put in use if it would make the code shorter/easier to follow.
Comment #38
pounardWhile I agree with Crell, I also have a lot of experience in Java and a bit in C# development: by convention, people almost always uses "import" (for Java) or "using" (for C#) statement (as is "use" for us) but put intentionally the fully qualified names sometime, when they just use the class name once and/or it creates a name conflict (even if in PHP we have the "as" statement for this, sometime just for one usage, what the hell); It's like a commonly agreed convention infringement.
I would keep the "use" as standard, but accept to bypass it in minor cases when it doesn't cause any readability problems.
In the case of the node module query alter hook signature, for instance, I'd definitely let the fully qualified name because it appears only once and we don't really need the use statement whether for readability or DX, standard or not. A rule without exception is not a rule, and I know what I'm talking about I'm french and my native language is all about exceptions ;)
My feeling is that it's OK to break the rules sometime if we feel the readability is better this way: the only pre-condition is we have to agree at review time on a per-case basis.
Comment #39
Crell CreditAttribution: Crell commentedFrench? Dude, English has you SO beat when it comes to exceptions to the rules. :-)
My concern with an exception for "when that seems more readable" is that is very gray, and we're introducing a great place to stall an issue on bikeshedding. We need to have at least some objective guidelines for when it's OK to break the convention or every issue is going to come down to me saying "no, always" and David Rothstien saying "yes, never", and no way to resolve it. :-)
Since copy/paste is the best use case I've heard so far, what about "if a class name is used in a function or method signature only once in a file, it *may* be given in full form at the developer's discretion."
Remember also that classes may get reorganized. If so, you only want to have to update the use statements, which are easy to grep for. You don't want to have to go hunting for the class name elsewhere.
Comment #40
webchick"if a class name is used in a function or method signature only once in a file, it *may* be given in full form at the developer's discretion."
I think I could live with that. I'd like it even better if we appended ", for example if a class is used only once in a file." to it.
Comment #41
Crell CreditAttribution: Crell commentedThat would be redundant, since the "once in a file" is already there. I am specifically calling out signatures in particular because that's where copy/paste matters. In fact it may matter only for hooks, now that I think about it, because that's all you'd be copy/pasting. For a class name in the body of a function/method, you should "use" it properly.
If you are implementing hook_node_insert, hook_node_update, hook_node_delete, and hook_node_form, then you really really should go ahead and "use" the class name. (Assuming that the current efforts to classify Entities succeed for Nodes and eventually get namespaced, which I believe are safe assumptions to make.)
Comment #42
webchickOMG. READING. I should try it sometime.
Comment #43
pounardI mostly agree with the last 4 messages.
Comment #44
catchWorks for me too.
Comment #45
webchickShip it! :)
Probably append a bullet to the end of the '"use"-ing classes' heading?
Comment #46
Crell CreditAttribution: Crell commentedBullet added. Please confirm that it is acceptable all around and then mark this back to fixed if so.
(Note that since this is treated as optional, I will probably leave the short-names in place for the DBTNGTNG patch as I already did the work. :-) )
Comment #47
neclimdulIt probably goes without saying since I voiced this concern earlier but I totally support being more flexible for one off uses of fully qualified namespaces as well. Glad we found a use case and addressed it so quickly before namespaces where heavily adopted!
Comment #48
David_Rothstein CreditAttribution: David_Rothstein commentedAs written, this means that when adding certain new hook implementations to a module, I have to go back and audit some of the other hooks I already have (and possibly change their coding style in response to the mere existence of the new hook). I don't see what benefit that brings in terms of developer experience or code readability, and as coding standards go it doesn't seem like it's either simple or consistent.
I'd like to see more comments on #35.
Comment #49
catchFrom the point of view of a coder rule, I was thinking something like this:
"Fully qualified class names are allowed in function signatures, but not anywhere else."
When we get to the point where entities are all classed, and field API is implementing entity hooks, then it is going to be a lot of entity hook implementations in that file and it seems reasonable to allow a use statement there - even if entity.api.php is using the fully qualified class names, so I'm not sure about making it a strict requirement that you can never put a use statement outside of a namespaced file (although we might possibly want to do that for consistency in core).
Comment #50
Crell CreditAttribution: Crell commentedDavid: To be honest, I don't even know how to respond to #35. You're essentially proposing that we just use _ everywhere instead of \, and end up with ridiculously long class names that are hard to read. Many projects used to do that, including PEAR and Zend. They all abandoned that in favor of proper namespaces as soon as they possibly could because of how utterly painful it was. There's a reason why most of the OO frameworks were pushing hard for language-level namespaces for classes. They all knew from experience just how much life sucked without them.
To not learn from their experience and have to suffer the pain and agony that they went through doesn't strike me as a wise idea.
catch: One thing I've experienced doing the DBTNGTNG reorganization and the WSCCI-Symfony prototype is that classes may well get moved around from one namespace to another. When that happens, anywhere that a full name is used it has to be changed. If those are scattered throughout the file, it's much harder than if I just have to update a few use statements. Strictly speaking you could even alias the class if it's base name is changing, to avoid changing anything else, but I would discourage that as I can see it getting confusing very fast. The fewer places you use a full name, the easier it is to refactor code. That's true regardless of whether the file in question is namespaced or not.
Comment #51
David_Rothstein CreditAttribution: David_Rothstein commentedThat doesn't sound like what I proposed in #35... The proposal would require using the shortened class names + "use" in large parts of the codebase (in practice, probably most of the places that actually refer to such classes).
That said, I'm curious how much pain and agony there really could have been. Saving people from typing a few extra characters doesn't seem like a big deal to me when weighed against other considerations, and in general, our coding standards don't prioritize that - if they did we'd name all our variables like $a, $b, $c :) If the only benefit from namespaces were that less typing is required, I don't think it would be worth adopting; but fortunately there are lots of other benefits you described in #1240138: Adopt PSR-0 namespace convention for core framework classes (easy autoloading, compatibility with other libraries, etc), all of which are compelling regardless of how many characters we ask people to type.
Comment #52
pounardMy guess is we discussing all this as it was a really important detail, but I think it's only a matter of getting the right things close together in one place on the screen (quote from Joel on Software).
While having the strict "use" usage as convention is a good idea, we have, on per-case basis, to cool off about the convention when it makes the code harder to read. When I'm gonna use a class everywhere in the PHP file, I have to do a proper use of the "use" statement because I know that it will allow me more flexibility in term of readability and refactor; Nevertheless if I use my class name only once, I won't disagree breaking the convention if it keeps the right things close together in one place on the screen, because I don't want the next developper to have to scroll the whole file to find out where does it comes from.
Yes, I said it: break the convention, or doing something illegal, we probably should keep those exceptions illegal per the convention but agreed on a review basis and just not writing it into the convention, or just add a small asterisk in the convention saying but it's OK to use a fully qualified name if doesn't make the refactor harder but it clearly keeps the right things close together in one place of the screen.
Comment #53
effulgentsia CreditAttribution: effulgentsia commentedJust to throw another idea into the mix, what do you all think about "using" only up until the subsystem / package name, and having code be explicit in resolving finer resolution than that?
For example, instead of:
we instead standardize on:
Is that the best of both worlds (reduce unnecessary clutter, but keep things clear) or the worst of both worlds (code not blindly copy/pasteable, but still containing ugly slashes)?
Comment #54
Crell CreditAttribution: Crell commentedSymfony does that in some places, I believe. I don't know what its standard is for it off hand. Personally I see that as the worst of both worlds unless you're really comfortable with namespaces, which most Drupal people are not at this point.
Comment #55
pounardThis seems wrong to use relative class name, it's even more confusing.
Comment #56
andremolnar CreditAttribution: andremolnar commentedre: #53
What if at some point someone wants to replace Symfony\Component\HttpFoundation\Request with an API compatible Foo\Bar\Baz\Request?
Comment #57
yched CreditAttribution: yched commentedI guess the standards should mention a special case on *.api.php files:
- classes/interfaces appearing in hook signatures type hinting
- classes/interfaces appearing in the sample functions bodies
Those should probably have their namespaces fully inlined - we can't rely on a bunch of "use" statements at the top of the file ?
(especially since the code in the functions bodies might come from several completely unrelated modules - or completely made up)
Will make copy/paste from existing code less straightforward, though.
Comment #58
pounardI agree with yched about .api.php files.
Comment #59
Crell CreditAttribution: Crell commentedThe coding standards already agree already, at least implicitly: http://drupal.org/node/1353118
Comment #60
jhodgdonSo...
I'm looking at http://drupal.org/node/1353118 and there are no examples in there of how to do API docs for these namespaced classes. It's kind of mentioned at the top, but some examples would really help. And we should possibly get some examples onto the Doxygen reference at http://drupal.org/node/1354 ?
Also, I'm very concerned about how the API module should handle them -- how to display these namespaced classes on api.drupal.org, etc. There's an issue for that:
#1507476: Support namespaces in API module
I am really clueless as to what we would want the API module to do, much less how to do it, so if anyone has suggestions on what we want to happen, please clue me in. :)
Comment #61
hansfn CreditAttribution: hansfn commentedJust a quick question: When using "instanceof" you have to use the class' full name with leading backslash (when you are inside a namespaced file). Should this be mentioned in the namespace documentation or is it too obvious?
Comment #61.0
hansfn CreditAttribution: hansfn commentedClean up comment regarding leading \.
Comment #62
Crell CreditAttribution: Crell commentedhansfn: Not true. instanceof takes a class name directly, in which case it's subject to the same namespacing rules as any other class. In a string, yes, a class name must be fully qualified and include a leading \, which I think is already in the coding standards, no?
Comment #63
hansfn CreditAttribution: hansfn commentedThx for the quick reply, Crell. I'm not knowledgeable on this topic - I'm just posting here based on recent experiments.
By this you mean that if the class name contains backslashes, it doesn't need a leading backslash? My testing indicates, the opposite. Example:
In core/modules/action/lib/Drupal/action/Plugin/views/field/BulkForm.php (which is a namespaced file), you'll find
Removing the leading baskslash here breaks the test. However, in other non-namespaced files, the leading backslash doesn't matter.
The docs I pointed to says When specifying a class name in a string, use its full name including namespace, without leading \. (This isn't relevant for my example above, anyway, is it?)
Comment #64
tim.plunkettThis works:
Comment #65
Crell CreditAttribution: Crell commentedhansfn: What you're running into isn't coding standards, it's just the way the PHP engine handles namespace resolution. #64 is the Drupal-preferred way of handling namespaces.
jhodgdon: Is there a reason this thread is still open nearly a year later? There's only about 14 namespace coding standards issues floating around. Do we still need this one? :-)
Comment #66
jhodgdonCrell: I have no idea, and I don't have time today to read through the comments here to see if there is a reason this thread is still open (something still missing from the namespace standards?). Sorry... my schedule should be better next week but I've been really busy all December and into this week.
Comment #67
hansfn CreditAttribution: hansfn commentedThx, Crell. So the answer to my question was, yes, it's too obvious and not worth mentioning. Sorry about the noise ;-)
Comment #68
jhodgdonOK, I skimmed through this issue. It was closed/fixed sometime before comment #29. Then webchick reopened it in #30, and a proposal was made in #35 for a standards change, which people have not agreed to or completely rejected... As far as I can tell, that is apparently what it is still open for.
Comment #69
David_Rothstein CreditAttribution: David_Rothstein commentedI think the reason for this being open can be summarized by looking at the top of node.module right now in Drupal 8:
Many of these only have a tangential relationship to what the node module actually is doing; they are referred to once in the entire file in some random part of the module's code thousands of lines down from the top. The concern people have raised about this is that this hurts readability and maintainability of the code in the rest of the file, without any real benefit.
I think the specific proposal in #35 will no longer work since namespaced classes are now being used in many more "higher-level" parts of the codebase than they were at the time I wrote that. Reading other comments above, there seem to be two possible solutions that remain:
use Drupal\node\Plugin\Core\Entity\Node
would remain and the others would go away.I'm not sure either of these is a great solution on its own, and both have their problems. In an ideal world, we might do both; I think if node.module were a few hundred lines long instead of a few thousand, and had a single
use Drupal\node\Plugin\Core\Entity\Node
at the top, this would be both usable and sensible.Comment #70
Crell CreditAttribution: Crell commentedThis.
For OO code, I don't think it's an issue. A thousand-line class has a > 50% chance of being a bad design in the first place, regardless of any "use" DX issues, and should be refactored anyway. Eliminating multi-thousand-line procedural files is a noble goal in and of itself. As I'm sure you're tired of hearing from me :-), IMO the preferred way is to convert more of that code to OOP. Not possible for everything yet, of course, but for many things.
Another option is to allow procedural files only to use namespace "use" statements, not class use. Vis, the node.module example above changes to:
That also has the impact of "you have to think harder about such things", but at least reduces the number of "use" statements and inlines some context. I know we previously rejected that when we said the base class name needs to be entirely self-descriptive, and this could result in redundancy, but... Eh. There's no silver bullet here.
(Symfony does that sort of thing all over the place, more than I care for frankly, but at least it's not unprecedented.)
Comment #71
sunI can't remember why and when and for what reasons we rejected or objected to it, but importing namespaces instead of individual classes, as @Crell described in #70, has always been the best proposal from my perspective.
I'd even be tempted to potentially allow developers to scale it down even further by encouraging imports of "top-level"/"component" namespaces; i.e., preferring the primary namespace instead of a deeper one in almost all cases:
Importing individual classes works well in smaller files with a well-defined scope. For larger, de-facto scope-unlimited files, importing entire namespaces might work better (but not necessarily).
In any case, the maximum I'd recommend to do here is to provide a recommendation ("MAY" or possibly "SHOULD" in spec talk), but definitely not a standard (not "MUST"). That is, because I think decision should be based on human, logical sanity - not on pedantic standards. I.e., if it makes more sense to import a namespace, do it. If it's clear that you'll only ever need a single class from another namespace, just import that and be done with it - no reason to only import the namespace.
As a result, I'd recommend the following guideline:
How's that?
Comment #72
Crell CreditAttribution: Crell commentedThe original reason I pushed for never doing partial namespace imports was simplicity, when we had a community of people who I expected to be scared off by \ characters all over the code. That was over a year ago now, though, so I don't know if we're comfortable loosening up yet.
In OOP files, I'd much rather still default to importing individual classes. As above, if that becomes an obscene list in a class file then it probably means your class is wrong anyway and should be refactored.
Re #71, my main concern is the idea of "sub-namespaces", since there's nothing inherent in the language that says that Drupal\Core\Database is the "right" subnamespace to do an import but Drupal\Core\Database\Query is not. We'd have to define an arbitrary number of layers of namespace to import, which would probably start an even bigger bikeshed. :-)
Comment #73
neclimdulBest part about the last couple comments? I think we've identified what we're looking for which is in my opinion "Discuss namespace importing in procedural code" which is not the original or summarized version of this issue. Standards have been setup but we can iterate on them in a new issue with the current state of the community.
Comment #74
Crell CreditAttribution: Crell commentedIs this still an active discussion? I think this conversation has meandered through other issues by now...
Comment #74.0
Crell CreditAttribution: Crell commentedremove * with \
Comment #75
jhodgdonI do not think this is an active discussion, so marking as "fixed".
If it is an active discussion, it should be moved into the Core queue again.