Common convention for namespaces in PHP is to start with
Vendor\Package, capitalized (
CamelCase ) with “vendor” and “package” analogous to the composer package name.
There is a bad habit I see often, probably coming from the ZF1 and Pear days, where every word in the class name is a new sub namespace (and a new subdirectory), or child classes are moved into a namespace with the name of the parent class. All this is leading to deeply nested namespaces and class names that have no meaning without their namespace.
Examples from Zend Framework 1 (pseudo namespaces):
Zend_Db_Table_Row_Abstractan abstract base class for
Zend_Db_Table_Row, representing a database table row. There are also
Zend_Pdf_FileParser_Font_OpenType_TrueTypea parser for true type font files. The class extends
And a current example from Magento 2:
Magento\Catalog\Model\Product\Option\Type\File\Validator– A validator for product options of the type “file”
This makes a very confusing directory structure, deeply nested, and with classes that belong together not necessarily next to each other.
├── Option │ ├── Converter.php │ ├── ReadHandler.php │ ├── Repository.php │ ├── SaveHandler.php │ ├── Type │ │ ├── Date.php │ │ ├── DefaultType.php │ │ ├── Factory.php │ │ ├── File │ │ │ ├── ValidateFactory.php │ │ │ ├── ValidatorFile.php │ │ │ ├── ValidatorInfo.php │ │ │ └── Validator.php │ │ ├── File.php │ │ ├── Select.php │ │ └── Text.php │ ├── Type.php │ ├── UrlBuilder.php │ ├── Validator │ │ ├── DefaultValidator.php │ │ ├── File.php │ │ ├── Pool.php │ │ ├── Select.php │ │ └── Text.php │ └── Value.php ├── Option.php
The other extreme is no sub namespaces at all, leaving all class files in one directory (or even all classes in one file)
This is perfectly fine for a small package with about a dozen classes, but not if it gets bigger.
Since I prefer having many small classes over a few big ones, I have to find a middle ground. Otherwise the code base will look complex at first glance where it actually is not, just because the parts are shuffled without sensible arrangement.
But what is wrong with the examples above?
- Unnecessary deep nesting Take the Zend_Db classes: Databases, tables, rows and columns (and more) make up a database schema and are tightly coupled with each other. You won’t have tables without rows and rows without tables. So if all these classes logically belong together, why should I look for them in different directories? If I browse the code in the IDE or on Github I want to be able to navigate quickly between classes that belong together. And if it is unfamiliar code, I want to quickly grasp which classes belong together. This is easier if they are in the same place, for example like this:
RelationalDbSchema ├── Database.php ├── Table.php ├── Row.php ├── Column.php
With the PDF file parser classes it is similar, although they have another problem: overuse of inheritance. That aside, a better structure could look like this:
FileParser ├── BaseFileParser.php ├── FontFileParser.php ├── OpenTypeFontFileParser.php ├── TrueTypeFontFileParser.php
- Hard to find classes Most IDEs have a feature to search for classes by name, for example for code completion. Now if you have 50 classes called “File” or “Validation” in different namespaces used for entirely different things, you are making it hard to find the right one. However, if there is one single “FileOptionValidation” class, I can find and use it with just a few keystrokes.
So here are some rules I came up with that work well for me so far:
Keep classes organized
- Keep namespace depth as flat as possible. This makes it easier to navigate the code.
- Start with zero, i.e.
Vendor\Package\Class, and only introduce sub namespaces if there is need for it (see below).
- If the number of classes in a namespace is too big to find your way in it, think(!) about breaking it apart 1 10 or even 50 classes or interfaces in a namespace are still okay, if they really belong together
- Think of each sub namespace as a separate component and keep coupling between the components small. This will help you organize the namespaces in a sensible way.
- The class name should always be descriptive enough to work without the namespace (i.e.
Product\Repository). This will help to quickly find the right classes. Also you can let your IDE import them automatically and you won’t need to define aliases all the time.
- Avoid namespaces that contain both, classes and sub-namespaces. This is the least important rule, but I think it can be a useful guideline to keep the distance between classes that belong together low. An exception can be a class that serves as single entry point for the whole package that has sub-namespaces. This will reside as only class at the top level next to the sub-namespaces to make it obvious that this is where you start using the package.
Reddit user LtAramaki makes an interesting point:
I can see you seem to equate “namespace” and “package”, but they really aren’t the same thing
I have thought about it and could not find arguments against a class like
Vendor\Packageas single entry point for the package. I will consider this in the future.
I mostly stick to the “one class per file” convention and PSR-4, i.e. namespaces mapped to directories. The reasons are practical: autoloader compatibility and the “principle of least astonishment”.
“Private classes” inside another class file are a rare exception and only if they are not used anywhere outside that “parent” class.
How do you organize your namespaces?
- In the first version of this article I wrote “If the number of classes in a namespace reaches 5, think(!) about breaking it apart“. But giving hard numbers like that might result in misconceptions. For small packages I found it a good rule of thumb, but following it literally in a larger package will lead to exactly the namespace cluttering I want to avoid. ↩