Why Namespaces?

As projects grow, class and function name collisions become common. PHP namespaces (since PHP 5.3) provide a way to group related code and avoid naming conflicts — similar to packages in Java or modules in JavaScript.

Declaring a Namespace

  <?php
namespace App\Models;

class User {
    public function __construct(public string $name) {}
}
  

Every PHP file should declare one namespace at the top (after <?php), before any other code.

Using Namespaced Classes

  <?php
use App\Models\User;

$user = new User('Alice');
  

Or reference with the fully qualified name:

  $user = new \App\Models\User('Alice');
  

PSR-4 Autoloading

PSR-4 maps namespaces to directory structures. With Composer, define autoload rules in composer.json:

  {
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}
  

Then run composer dump-autoload. Classes in src/Models/User.php with namespace App\Models load automatically — no manual require statements.

Best Practices

  • Use one class per file, filename matching the class name
  • Follow PSR-4 directory layout: App\Controllers\UserControllersrc/Controllers/UserController.php
  • Prefer use imports over long fully qualified names
  • Group related classes under meaningful namespace segments (App\Services, App\Repositories)

Sub-namespaces and Aliases

  use App\Models\User as UserModel;
use App\Models\Post;

$post = new Post();
$user = new UserModel('Bob');
  

Namespaces are the foundation for Composer, frameworks like Laravel and Symfony, and any maintainable PHP codebase.

Global Namespace and Functions

Functions and constants declared outside any namespace live in the global namespace. Reference them from within a namespace with a leading backslash:

  <?php
namespace App\Services;

function helper() { return 'global'; }

class Mailer {
    public function send(): void {
        \mail('[email protected]', 'Subject', 'Body'); // PHP built-in
    }
}
  

Dynamic Class Loading

Composer’s autoloader resolves classes at runtime. You rarely call require manually:

  // composer.json maps App\ → src/
$user = new \App\Models\User('Alice'); // FQCN always works
  

Common Pitfalls

  • Missing namespace declaration — classes default to the global namespace and may collide with framework classes.
  • Wrong directory layoutApp\Models\User must live at src/Models/User.php, not src/User.php.
  • Forgetting composer dump-autoload after adding new PSR-4 paths.
  • Using use inside functions — place use statements at the top of the file after the namespace declaration.

Practical Exercise

  1. Create a project with composer init and PSR-4 autoloading for App\src/.
  2. Add src/Models/User.php and src/Repositories/UserRepository.php.
  3. Write a script that instantiates the repository without any manual require calls.
  4. Add a sub-namespace App\Services\Email and confirm autoloading still works.

Quick Reference

Syntax Example
Declare namespace App\Models;
Import use App\Models\User;
Alias use App\Models\User as UserModel;
Global \DateTime (leading backslash)
Function NS namespace App\Utils; function helper() {}

When in doubt, run composer dump-autoload -o and verify the class path matches the PSR-4 mapping exactly.