Both quicksketch and webchick have asked me about this before. I'm sure others have voiced concerns too. This is a write up of what our current PSR-0 system uses, and possible alternatives...
PSR-0?
First I'd like to cover what PSR-0 is. It's pretty much saying that a class's namespace matches its directory structure. PSR-0 is not a class loader, or any implementation, it's just a practice. MyStuff\MyClass should be at MyStuff/MyClass.php
, somewhere. Is it the right thing for us? Read on...
1. Current System
Drupal 8 currently uses PSR-0 on each module's lib directory. This means that Drupal\mymodule\MyClass is loaded at mymodule/lib/Drupal/mymodule/MyClass.php
. It's PSR-0 as the namespace matches to the directory structure (1:1). Simple. Easy. /lib
is registered with Drupal/mymodule
.
- Pros
- Biggest bang for our buck when we started the PSR-0 Initiative
- Already a huge amount of class loaders available
- Most PHP projects out there already are using this approach
- Cons
- Developers have to make three nested directories when making a module (
mymodule/lib/Drupal/mymodule
)
- Developers have to make three nested directories when making a module (
2. Move away from PSR-0 (Re-Invent the Wheel)
If we were to move away from PSR-0, we could have Drupal\mymodule\MyClass registered at mymodule/lib/MyClass.php
.
- Pros
- Contrib developers only have to make one directory (lib) instead of three (lib/Drupal/mymodule).
- Cons
- No longer PSR-0, since the namespace does not match the directory structure
- Since it's not PSR-0, we'd break any class loader that expects PSR-0
- We'd have to implement our own versions of all the classloaders that use PSR-0
3. Remove the lib directory
Move lib up a directory so that Drupal\mymodule\MyClass is loaded at modules/mymodule/Drupal/mymodule/MyClass.php.
- Pros
- One less sub-directory to create
- Easiest
- Cons
- Doesn't actualy gain us anything
4. Register the namespace to the directory itself
Move the .module
files to where Drupal\mymodule resides.
modules/Drupal/mymodule/mymodule.module
modules/Drupal/mymodule/MyClass.php
- Pros
- Module classes now live in the same directory as the module
- Is still PSR-0 so we wouldn't need to re-implement the loaders
- Symfony uses this approach with their components by using Composer's target-dir, but unfortunately Drupal 8 won't get this far
- Cons
- We don't have control over where users install modules
- Classes in same directory as functional code?
- Broken namespaces when the module has a dash in the name
5. Remove both "lib" and "Drupal"
Remove the "Drupal" prefix in the namespace and move lib up a directory. Register just the module name as the namespace instead of Drupal\my_module
. This means that my_module\MyClass is loaded at modules/my_module/my_module/MyClass.php
. Could even take it one step further and PascalCase the module names. MyModule/MyClass is found at modules/my_module/MyModule/MyClass.php
.
- Pros
- Might make it a bit more familiar for people
- Still PSR-0
- PascalCasing the module name makes for pretty namespaces
- Cons
- Might conflict with third-party namespaces (symfony module conflicting with Symfony namespace)
6. Remove "lib" and "Drupal" namespace prefix, and register the module's parent directory
Register the module's parent directory as the namespace for the module. This would make it so that my_module/MyClass is found at modules/my_module/MyClass.php
.
- Pros
- One less directory than #5
- Cons
- Result in broken namespaces when the module has dashes in them
- Module name must match namespace
- Requires one module per folder, by design
7. Package-Oriented Autoloader
Beau Simensen pointed me to Package-Oriented Autoloader proposal in the PHP-FIG, which is pretty much PSR-0 without the leading vendor prefix being required in the file system. Allows adding code in src instead of requiring it to be at the top level.
Very nice, and definitely would love to see the proposal grow.
Conclusion
All in all, lib/Drupal/my_module
was what we went with because the solution was already done for us. PSR-0 has complete documentation, a plethora of loaders already written for us, and it's all working and tested. Most of the PHP world that deals with loading classes also use it and it was the most bang for our buck. I'd really love for people to understand why we went with PSR-0, and what the benefits/cons to that are.
But, it's always good to see different solutions and alternative methods! There are a couple of different contrib classes that bring this to Drupal 7 and below too: ClassLoader, xautoload, etc. This isn't anything that limits us in Drupal 8 either, we can port the xautoload to Drupal 8 and have alternative means of class loading in contrib. The sky is the limit! Is there a #8 solution that you'd like to see?