PSR-4 Autoloading Standard
debt(d3/e2/b3/t3)
Closest to 'default linter catches the common case' (d3) — Composer itself warns about PSR-4 mismatches during dump-autoload, and phpcs/phpstan flag class-not-found issues immediately.
Closest to 'one-line patch' (e1, scored e2) — quick_fix is a composer.json autoload entry plus dump-autoload; slightly more than one line because you may also need to rename files/directories to match.
Closest to 'localised tax' (b3) — applies to project structure conventions and shapes where source files live, but it's a universal PHP standard so it doesn't fight maintainers; it's a mild structural commitment.
Closest to 'minor surprise' (t3) — misconception notes devs assume namespaces alone suffice, but the strict directory-mapping requirement is a documented gotcha most PHP devs learn quickly.
Also Known As
TL;DR
Explanation
PSR-4 defines a mapping from fully qualified class names to file paths: the namespace prefix maps to a base directory, and sub-namespaces map to subdirectories. For example, App\Controller\HomeController maps to src/Controller/HomeController.php. Composer implements PSR-4 autoloading via the autoload section in composer.json, generating an optimised classmap in production. PSR-4 replaced the older PSR-0 and eliminated the double-underscore namespace separator convention.
Common Misconception
Why It Matters
Common Mistakes
- Class namespace not matching directory structure — autoloader cannot find the class.
- Not registering the PSR-4 mapping in composer.json autoload section.
- Using multiple classes per file — PSR-4 requires one class per file, filename matching class name.
- Forgetting to run composer dump-autoload after adding new namespace mappings.
Code Examples
// Namespace doesn't match file path:
// File: src/services/UserService.php
namespace App\Services\User; // Wrong — should match: App\Services
class UserService {}
// Autoloader looks for: src/Services/User/UserService.php
// File is at: src/services/UserService.php
// Result: class not found
// composer.json — map namespace prefix to directory
{
"autoload": {
"psr-4": {
"App\\\\": "src/",
"App\\\\Tests\\\\": "tests/"
}
}
}
// File: src/Domain/Order/OrderService.php
// Class must be: namespace App\\Domain\\Order; class OrderService
// Regenerate autoloader after adding new namespaces
$ composer dump-autoload --optimize
// Dev autoloader includes tests; production excludes them
$ composer dump-autoload --optimize --no-dev