Improving Our Use of PHP Namespaces

We were right to do it wrong

Let's step back and think about why we use namespaces, and how to realize their real advantages. I suspect there's a lingering hesitance to embrace their usefulness. For years we've built the appropriate habit of naming our symbols with appropriate specificity to avoid naming collisions. I'm talking about naming your class something like MyCompany_Loader, or something similarly specific to your context. This informal namespacing was a great stop-gap. But once we make the switch to formal namespacing, we should reconsider what impact this should have on our symbol names.

How to properly use PHP namespaces

The specific notion on my mind is that I'm seeing a redundant mix of formal and informal namespacing. Let's start a conversation about this, while it's still somewhat early in the game. At this point (I'm *always* willing to be convinced otherwise), I contend that we should completely eradicate the informal namespacing conventions if we are going to adopt formal namespacing in our apps. Here's a simple example that illustrates the general direction I think we should move in (derived from the Drupal Extension project, a Behat Mink component).

Example (Let's move away from this):

    namespace MyCompany;
    use Drupal\DrupalExtension\Context\DrupalContext;
    class MyCompanyContext extends DrupalContext {}

Proposal (Let's move toward this):

    namespace MyCompany;
    class Context extends \Drupal\Extension\Context {}

Notice a few specific things:

  1. In the first example's use statement, the word Drupal occurs 3 times; 2 can be removed
  2. In the first example's use statement, the word Context occurs twice; 1 can be removed.
  3. In the first example, both "localized" class names had redundant occurrences of the company name. This is specifically what formal namespaces exist to eliminate.

These are essentially equivalent, but the latter removes several redundant components and delivers what namespaces are supposed to bring us. Notice also that I removed a `use` statement and instead used the fully-qualified class name in the code. This is an important part of what I'm proposing. I think it's too simple to advocate for moving all use of namespaces to the top of a file and only use "short names" for symbols in other namespaces. This is particularly important when you are extending a symbol. Code readability is inversely related to how often I need to scroll to the top of the file to figure out which specific version of a symbol is being used.

To Summarize

  1. Don't use redundant name components
  2. Don't be afraid to use fully-qualified names in-context, if appropriate.

The cases where it's not really necessary to use fully-qualified names in-context are when you are only "consuming" a symbol, and not extending it. For example, if you are going to use a Widgetizer library, but not extend it, feel free to use the `use` statement and simplify the use of the symbol throughout the file. The important distinction is that you don't have potentially ambiguous names if you are only pulling in one namespace with that symbol.

Comments

Class aliasing

Instead of extending parent or base classes by referencing the fully-qualified namespace, I would personally suggest to use the aliasing feature of "use" statements. In your example:

    namespace MyCompany;
    use Drupal\DrupalExtension\Context as BaseContext;
    class Context extends BaseContext {}

ctrahey's picture

`use` vs in-context fully-qualified names

Thanks for the comment, tstoeckler. I think the alias feature of namespaces is useful, and you're right that it is underrepresented in the post. As I mull over my thoughts on it's application I'm trying to come to a rule of thumb which explains my attitude. I think it has to do with in-context readability (think line-level context) and the plurality of the use of the name.

For instance when we are extending a class, we are only likely to use that name exactly once in our entire file. Personally, I think it improves understandability to use the fully-qualified name in-context in that case. I have similar disposition toward other single-use cases.

The value of `use` (and then the added value of the alias) comes when you have a plural use of a name, and that name is not likely to have cognitive interference with similar names in your file. For example if you are using another library's "Decorator" class in several places, and you don't have your own "Decorator" class in your local (or semi-local) namespace, this is a fantastic time to use `use`. Further, if you are using sever variants of "Decorator", or perhaps you *do* have a (semi-)local "Decorator" class, aliases are absolutely a great tool to improve readability across the entire file.

use ACME\Framework\Components\Decorator\HtmlWrapper as ACMEHtmlWrapper;
use MyCompany\Decorator\HtmlWrapper as MyCompanyHtmlWrapper;

Don't comment on handbook pages

They get deleted. Instead, open an issue in the issue queue and tag it "coding standards". Note: There's a metric ton of prior discussion on this subject for Drupal 8, and while that doesn't mean we can't change things anymore it does mean you're likely to run into a fair bit of "we've been over this a hundred times already!" resistence.

One of the main impetuses for the current standard (always "use") was simplicity. There was a lot of pushback against \ characters in code when PHP 5.3 came out, so we decided to just avoid them anywhere but in the file headers so as to not confuse people. It also means we have an automatic index of all dependencies at the top of the file. That's nothing to sneeze at.

ctrahey's picture

Thanks

Thanks for the tip.

I do consider the 'use' thing to be a secondary concern and purely about style, so I'm not too concerned with trying to change the community's mind about that. The more compelling change, in my opinion, is the removal of redundant identifiers in names, as I think it reduces the value of segmented namespaces in general by reducing the semantic value of each component.

Already discussed

We already had that discussion, actually. If you find a class with "Drupal" in its name anywhere but the first namespace component, 98.6% chance you should file a bug about it. The ending guideline was "don't be redundant, unless the class shortname is unacceptably ambiguous otherwise, then put in just the little bit you need." And "Drupal" is *almost* never appropriate in a class name.

I wish you'd been around for these discussions in the issue queue over the past year...

ctrahey's picture

Issue created

Thanks, Larry! Now that I'm here at Metal Toad, my participation in the community will be well supported.

I've created an issue for the DrupalExtension in particular, but note in that ticket my reformed opinion on \Drupal\DrupalExtension (due to the project name not being simply 'extension'... brings up interesting other thoughts).

However, I still found a handful of redundancies in the project to discuss. Perhaps I'll patch if the maintainers are positive about the idea.

I haven't scoured Drupal yet, but I did notice that the "Exception" namespace is guilty of several redundancies.

Coding standards, schmoding standards

While I agree that use can be more or less useful depending on circumstance, the Drupal (8) coding standards dictate to always use namespaced classes at the top of the file, even if they are used only once... The point, as far as I know, is that in such a case consistency wins over the added clarity you describe in that particular case.

ctrahey's picture

Hopefully we are early in the trend

I agree about consistency/clarity so long as it's not a stark contrast between the two (in this case it really isn't).

However, I hope we are early enough in the collective conversation about how we (the PHP community, not just the Drupal community) will use namespaces.

Agree

I agree with removing essentially redundant namespacing as it makes thing cleaner, proper use of namespaces, and easier to read. I've been using this approach in some of my side projects and have been pleased with the results.

As for aliasing if just extending and never referencing again it makes more sense not to bother with the alias as you wrote as well.

I work with some code that does not follow this convention and the names get absurdly long and are no better for it + harder to read.

Quite a no-brainer

Am I the only one who thought this was a no-brainer?

I mean, namespaces are there to avoid name conflicts, this allows us to use the best names for the classes without worrying about conflicts.

I am definitely in favor of moving in the way you're describing there. It's a no-brainer.

Thanks for the article! I've

Thanks for the article! I've only used namespaces in a limited fashion in other languages, so it's helpful to see that what I'm encountering in the core isn't a) the only pattern or b) unusual. I look forward to the changes in D8 and would love to follow along with a core issue to remove the redundancy in identifiers.

Add new comment