Question

I've seen a bunch of examples using PSR to do autoloading with namespaces. Maybe this is a dumb question, but why isn't this bad practice? Doesn't that defeat the purpose of having namespaces?

For example, say you have two libraries, FormBuilder and MySweetForms, and both have a Form class. Locations are at:

lib/FormBuilder/Core/Form.php and lib/MySweetForms/Form.php

If you autoload based on the namespaces those Form classes are in, aren't you going to run into the exact problem that namespaces are meant to prevent: ambiguous identifiers of classes and methods?

Won't it fail when you successfully locate another class in the MySweetForms namespace, say AjaxFileField, that relies on \MySweetForms\Form, but it finds the FormBuilder's implementation of the Form class?

Was it helpful?

Solution

Because of namespaces, the autoloading won't find the FormBuilder's implementation of the Form class when it's looking for the MySweetForms implementation, provided the autoloader and the two libraries follow best (or close to best) practices and are implemented correctly.

If the MySweetForms/AjaxFileField.php file defines a class inside the MySweetForms namespace as shown:

namespace MySweetForms;

class AjaxFileField
{
    public function doFormStuff()
    {
        $form = new Form();
    }
}

Then the reference to the Form class inside AjaxFileField is really a short-hand for the fully qualified class name MySweetForms\Form.

When the autoloader is invoked to load the class, it will be asked to load the class based on it's fully qualified name. A PSR-0 autoloader would translate the MySweetForms\Form classname into the MySweetForms/Form.php path, and (provided it was told to look in the lib directory) it would find it's way to the correct file. If that file was missing, the autoloader would ultimately fail. Similarly, if that file defined a Form class but neglected to supply a namespace the actual class (MySweetForms\Form) would not exist (instead, a global class Form would) -- that doesn't match the fully qualified name of the class referred to in the AjaxFileField class, so an error would occur.

Note that if the code had included $form = new \FormBuilder\Core\Form(); instead the class name would already be fully qualified, and the autoloader would be asked to load the FormBuilder\Core\Form class (and would expect it to be in the FormBuilder/Core/Form.php file).

If we had used $form = new \Form(); we would be referring to the Form class in the global namespace and the autoloader would be asked to find Form (it would look in the Form.php file directly inside the lib folder at this point).

The key is to recognize that there are not, really, two Form classes -- there is one class with a fully qualified name of FormBuilder\Core\Form and one with a fully qualified name of MySweetForms\Form -- and a properly implemented autoloader will expect them in completely different locations, and will not try to load one file in place of the other.

The combination of namespaces and the PSR style of organizing files into directories based on their namespaces makes it very easy to re-use common words without causing conflicts, and to predictably map fully qualified class names to the corresponding files.

The resolution of class names to fully qualified class names is key to this, and is discussed in the PHP manual (the namespace FAQ has a couple of points about it: http://www.php.net/manual/en/language.namespaces.faq.php). The PSR-0 standard itself is also a useful reference: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top