DEV Community


Posted on • Updated on

PS4 class auto loading and namespaces in PHP

Learning link:
ps4 link:

The benefits of namespaces and PS4 Class Autoloading

The benefit of namespaces is to be able to organize code into libraries and other organizational schemes without the names of your classes colliding with other classes of the same name. Before PHP version 5.3 we used to use class names that had namespaces built into the class names to avoid name collisions. This lead to overly verbose and cumbersome class names like "MyOrganization_MyLibrary_Models_Foo" Which looked really screwed up when you had code with a whole bunch of classes with long names like that.

The benefit of autoloading is to remove the clumsy arrangements in how all of your code must be required or included in your runtime execution. The autoloading techniques lead to lazy loading which means that you don't ever load code unless you actually use it in the execution of your program. While the subject of lazy vs eager loading is var more nuanced than to imply that lazy loading is inherently better, it allows us to create large scale applications without having to build in manual loading schemes which are clumsy and fraught with inefficient use of "require_once" and "load_once".

To conclude, autoloading lets us use the "use" statement in our code without having to coordinate the manual requiring and loading of the file that code is contained in. "Namespaces" are how we abstract each article of code according to how its location is organized in the application's virtual tree.

PS4 more info


PSR-4 (and also PSR-0) requires that the class ClassName is stored in a file named ClassName.php. The names are case sensitive and they must match exactly.

The file names in your project are lowercase, the class names are mixed case. The default disk formats on Windows and macOS are case-insensitive on search. This means when a program searches for Employee.php and the file employee.php exists in the directory, the search succeeds and the OS returns the existing file even if the case of its name is not the same as the case of the required file. On Linux-based OSes, the default disk format is case sensitive and a program that searches for Employee.php cannot find employee.php.

Your composer.json file declares the app/ directory as the root directory of the MyDomain namespace that follows the PSR-4 standard. This is enough for the autoloader to find the file app/Models/Employee.php when it needs to load the class MyDomain\Models\Employee.

Because you run it on Ubuntu (which is a Linux-based OS), PHP cannot load the Employee.php file (because it doesn't exist) and the OS doesn't provide it the file employee.php instead.

It seems that you generate the autoloader using composer update -o or composer dump-autoload -o. The -o (short of --classmap-authoritative) tells Composer to scan the directories declared in composer.json (app/) in your case and create a classmap that contains all the classes it can find. A classmap is a list that maps the classnames (with the namespace) to filenames (with directories). This way, the autoloader knows exactly where to find each class and the loading goes faster.

The above two paragraphs explain why you need to regenerate the autoloader after you add a new class.

The correct way to do the job is to follow the PSR-4 requirements. To be more specific, each namespace under MyDomain must be stored in a subdirectory of app/ that has the same name, including the case. Each class must be stored in the correct subdirectory, in a file that has the same name as the class (including the case) and the termination .php (lowercase). For example, the class MyDomain\Models\Employee must stay in the file app/Models/Employee.php.

After you fix the file names you can run composer dump-autoload and forget about it. As long as the class and file names follow PSR-4 the autoloader will find them without regenerating it again.

On the production server you can run composer dump-autoload -o to improve its speed a little. Just don't forget to run it again after each deploy (or, even better, include the command in the deployment script).

Top comments (0)