Pragmatism in the real world

Use statements

I was having a discussion on IRC about use statements and whether they improved code readability or not.

The choices

Consider this hypothetical code:

$cache = new \User\Service\Cache();
$mapper = new \User\Mapper\User($cache)
$form = new \User\Form\Registration($mapper);
$form->process($request->getPost());

vs

use User\Service\Cache;
use User\Mapper\User;
use User\Form\Registration;

// other code

$cache = new Cache();
$db = new User($cache)
$form = new Registration($mapper);
$form->process($request->getPost());

The first snippet is completely unambiguous at the expense of verbosity. Those longer class names make it a little hard to quickly parse what it going on. The second is clearly less cluttered, but is at the expense of ambiguity. Exactly what class is User? I would have to go to the top of the file to find out. Should I use aliases? If so, how should I name them?

This is even more interesting in the context of pull requests where the use statement is already in place in the file. As a result the diff you are reviewing doesn’t have the use statement in it, so you have to go a different view to check that the class in use is actually the correct one. If fully qualified class names are used, then the PR’s diff is self-contained and easier to review.

Getting advice

As with a lot of things in programming, there are pros and cons, so I reached out to the people who follow me on Twitter and asked them:

There were a number of interesting responses, including:

There seemed to be consensus around the use of use statements. The main reasons appeared to be the ability to see the class dependencies at the top of the file and improved code readability (less clutter).

Some people also pointed out that you can introduce clarity when importing:

If you consistently name your aliases, then the code is shorter and also just as clear. If we take Brandon’s approach, then the example above becomes:

use User\Service;
use User\Mapper;
use User\Form;

// other code

$cache = new Service\Cache();
$db = new Mapper\User($cache)
$form = new Form\Registration($mapper);
$form->process($request->getPost());

Now the “aliases” are codified by the PHP namespace name and so you aren’t at the mercy of the developer who names the alias. However, the list of use statements is no longer a list of dependent classes, it’s a list of dependent namespaces.

My thoughts

Having thought about all the responses I received and having slept on it, I think that it’s preferable to be able to organise your code and name your classes such that when importing we minimise ambiguity. If we reorganised, we could come up with something like this:

use User\UserCache;
use User\UserMapper;
use User\RegistrationForm;

// other code

$cache = new UserCache();
$db = new UserMapper($cache)
$form = new RegistrationForm($mapper);
$form->process($request->getPost());

We have now flattened our class hierarchy which has resulted in clearer class names. Of course, this is not always possible and in those cases, I think that consistent naming of aliases is the way to go.

Have I missed something obvious? How do you import classes?

8 thoughts on “Use statements

  1. For me, and many other's I'd say, it's pretty common to suffix any classname except the entity itself with the parent namespace. Thus I usually end up with the following classes:

    Module\Entity\User;
    Module\Form\UserForm;
    Module\Mapper\UserMapper;

    And so on… I guess you get the idea. The point behind that is not only the ability to use all those classes without aliasing them, but also because else you have several files open in your IDE, all labeled "User.php", which is simply just confusing.

  2. I had a lot of trouble getting comfortable with namespaces and imports. One rule I kind of learned during my adventures was:

    A class name should always make sense without the namespace.

    So a class name like vendor\Validator\String are confusing, when you import them (and have no alias) and then do $validator = new String();. So in a lot of cases, I try to add the last namespace to the class name: vendor\Validator\StringValidator. Now the name makes sense on its own and you don't need to alias it.

  3. i think the root problem is sub-namespaces should be used strictly sparingly. having 1 namespace per class is an antipattern…(i see a lot of code with too much of that) and adds 0 to the value the class brings in.

  4. I tend to alias the implementation as the name of the interface they implement (as I prefer at that level to deal with the abstraction):

    // UserRepository.php
    <?php
    interface UserRepository
    {
    /* contract here */
    }

    // DbUserRepository.php
    <?php
    namespace Foo\Bar
    class DbUserRepository implements UserRepository
    {
    /* implementation here */
    }

    // SomeOtherClass.php
    <?php
    use \Foo\Bar\DbUserRepository as UserRepository;
    class SomeOtherClass
    {
    /* implementation here */
    }

  5. Using same class name in a client class from different namespaces is usually the exception. The code is nice and clean with use statements. Think of Java, the source of inspiration, they don't use full package name, and when they do, it looks horrible.

  6. I come from Java, and I like use statements for readability. I use Eclipse so I can always drill through to the actual class just like in Java. The actual use statements are collapsed and something I rarely look at.

  7. I like the use statements at the top for the reasons the others have mentioned but there are certain cases where is use them inline.

    One thing I this is important though is that you don't have too many, if a lot start to pile up then I use that as an alert that the class may be getting to complex.

Comments are closed.