PHP Namespaces

As PHP applications grow larger and rely on third-party libraries, naming conflicts become a real problem. Two different packages might define a class called Logger, and including both would cause PHP to complain that the class is already defined. Namespaces solve this by organizing classes, functions, and constants into named groups — similar to how a filesystem uses folders to organize files with the same name. This is the reason every modern PHP framework uses namespaces throughout its codebase.

Declaring a Namespace

A namespace is declared at the very top of a PHP file, before any other code (except the opening PHP tag and comments).

<?php
  namespace App\Models;

  class User {
    public string $name;
    public string $email;

    public function __construct(string $name, string $email) {
      $this->name = $name;
      $this->email = $email;
    }
  }
?>
<?php
  namespace App\Models;

  class Product {
    public string $name;
    public float $price;

    public function __construct(string $name, float $price) {
      $this->name = $name;
      $this->price = $price;
    }
  }
?>

Both files use the same namespace. Classes in the same namespace can reference each other directly without any qualification.

Using a Namespaced Class

To use a class from another namespace, you reference it by its fully qualified name, which includes the namespace path.

<?php
  namespace App\Controllers;

  // Use the fully qualified name
  $user = new \App\Models\User("Alice", "alice@example.com");
  echo $user->name;   // Alice
?>

The leading backslash \ signals that the namespace starts from the global root, not the current namespace.

The use Statement

Writing full namespace paths every time is tedious. The use statement imports a class into the current file so it can be referenced by its short name.

<?php
  namespace App\Controllers;

  use App\Models\User;
  use App\Models\Product;

  $user    = new User("Alice", "alice@example.com");
  $product = new Product("Laptop", 999.99);

  echo $user->name . " bought " . $product->name;
?>

Aliasing with as

If two imported classes share the same short name, use as to give one of them an alias.

<?php
  namespace App;

  use App\Models\User as UserModel;
  use Admin\Models\User as AdminUser;

  $siteUser  = new UserModel("Alice", "alice@example.com");
  $adminUser = new AdminUser("Bob", "bob@admin.com");
?>

Namespacing Functions and Constants

Namespaces apply to functions and constants, not just classes.

<?php
  namespace App\Utils;

  const VERSION = "1.0.0";

  function formatCurrency(float $amount, string $currency = "USD"): string {
    return $currency . " " . number_format($amount, 2);
  }
?>
<?php
  namespace App;

  use function App\Utils\formatCurrency;
  use const App\Utils\VERSION;

  echo VERSION;                      // 1.0.0
  echo formatCurrency(1999.99);      // USD 1,999.99
?>

Autoloading with Composer and PSR-4

Manually including every file with require is impractical in large projects. Composer's autoloader, following the PSR-4 standard, automatically includes the correct file based on the namespace and class name.

The convention maps namespace segments to directory paths. With this configuration in composer.json:

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

The class App\Models\User must be in the file src/Models/User.php, and the class App\Controllers\HomeController must be in src/Controllers/HomeController.php.

project/
├── composer.json
├── src/
│   ├── Models/
│   │   ├── User.php          (namespace App\Models)
│   │   └── Product.php       (namespace App\Models)
│   └── Controllers/
│       └── HomeController.php  (namespace App\Controllers)
└── public/
    └── index.php
<?php
  // public/index.php
  require_once __DIR__ . "/../vendor/autoload.php";   // Load Composer's autoloader

  use App\Models\User;
  use App\Controllers\HomeController;

  $user = new User("Alice", "alice@example.com");
  // Composer automatically includes src/Models/User.php
?>

After updating composer.json, run composer dump-autoload in the terminal to regenerate the autoloader.

Global Namespace

PHP's built-in classes and functions belong to the global namespace. When inside a custom namespace, reference built-in classes with a leading backslash to avoid PHP looking for them inside the current namespace.

<?php
  namespace App\Services;

  class EmailService {
    public function sendEmail(string $to, string $subject): void {
      // \DateTime refers to PHP's built-in DateTime class
      $date = new \DateTime();
      $timestamp = $date->format("Y-m-d H:i:s");

      // \Exception also refers to the global exception
      if (empty($to)) {
        throw new \InvalidArgumentException("Recipient email cannot be empty.");
      }

      echo "Email to $to sent at $timestamp.";
    }
  }
?>

Alternatively, add a use statement for the built-in class: use DateTime; — this is common in codebases that use namespaces throughout.

Key Points

  • Namespaces prevent naming conflicts between classes, functions, and constants in large applications and third-party libraries.
  • Declare a namespace with namespace My\Namespace; at the top of the file, before any other code.
  • Use a class from another namespace with its fully qualified name (e.g., \App\Models\User) or import it with use.
  • The as keyword in a use statement creates an alias for an imported class, function, or constant.
  • PSR-4 autoloading (via Composer) maps namespace segments to directory paths, automatically loading the correct file for any class.
  • PHP's built-in classes live in the global namespace — prefix them with \ (e.g., \DateTime) when inside a custom namespace.

Leave a Comment

Your email address will not be published. Required fields are marked *