PHP Namespaces
debt(d3/e3/b5/t5)
Closest to 'default linter catches the common case' (d3). The detection_hints list phpcs, phpstan, and composer — phpcs with PSR-4 sniffs and phpstan will flag missing or mismatched namespace declarations in routine CI runs without specialist configuration. Misuse (no namespace, wrong namespace path) is caught by these widely-used default tools.
Closest to 'simple parameterised fix' (e3). The quick_fix is to align namespace to PSR-4 directory structure and configure composer.json autoload — this is a small mechanical change per file, but renaming a namespace may require updating use statements across several files depending on scope. Not a single-line swap, but not a deep refactor either.
Closest to 'persistent productivity tax' (b5). Namespaces apply across web, cli, and queue-worker contexts (all PHP contexts). Poor namespace choices — deeply nested namespaces, mixing namespaced and non-namespaced code — slow down many work streams and make autoloading fragile across the project, but the codebase's overall shape is not dictated by them the way an ORM or service-mesh choice would be.
Closest to 'notable trap' (t5). The misconception is that namespaces automatically prevent all class name conflicts — they don't; two classes with identical fully-qualified names in different files still conflict, and uniqueness is enforced by Composer autoloading, not namespaces themselves. The leading-backslash-for-global-namespace gotcha (\Exception vs Exception) is an additional documented trap most PHP developers hit at least once.
Also Known As
TL;DR
Explanation
PHP namespaces (5.3+) encapsulate classes, interfaces, traits, functions, and constants into named scopes using namespace App\Controller. The fully qualified class name (FQCN) like App\Controller\HomeController maps directly to a file path under PSR-4. Use statements (use App\Service\UserService) alias FCQNs for cleaner code. The global namespace is accessed with a leading backslash (\Exception). Namespaces are essential for composer autoloading and preventing collisions between third-party packages.
Common Misconception
Why It Matters
Common Mistakes
- Mixing namespaced and non-namespaced code in the same project — it creates unpredictable autoloading behaviour.
- Forgetting that the global namespace requires a leading backslash inside a namespace (\Exception, not Exception).
- Using deeply nested namespaces (App\Modules\Orders\Domain\Entities\OrderLine) when shallower ones suffice.
- Not aliasing long namespace imports with use — leads to unreadable fully-qualified class names inline.
Code Examples
// No namespace — class name collisions in large projects:
class Logger {} // Conflicts with any other Logger class
class Request {} // Conflicts with framework's Request class
// With namespaces — no collision:
namespace App\Logging;
class Logger {} // App\Logging\Logger
namespace Vendor\Http;
class Request {} // Vendor\Http\Request — distinct
<?php
// File: src/Domain/Order/OrderService.php
declare(strict_types=1);
namespace App\Domain\Order;
use App\Domain\User\User; // import from another namespace
use App\Infrastructure\Mailer;
use DateTimeImmutable; // global namespace class
use InvalidArgumentException as InvalidArg; // alias
class OrderService {
public function place(User $user, array $items): Order {
if (empty($items)) {
throw new InvalidArg('Items cannot be empty');
}
return new Order($user, $items, new DateTimeImmutable());
}
}