When building small PHP scripts, everything seems simple - you write a few classes and functions, and they work fine. But as projects grow, especially in large-scale applications or when working with third-party libraries, name collisions become a real problem.

This is where namespaces come into play. Namespaces help organize and structure code, avoiding conflicts and improving readability.


What are Namespaces?

Think of a namespace as a container or folder for your code. Just like your operating system organizes files into directories to avoid conflicts, PHP organizes classes, functions, and constants into namespaces.

For example:

namespace App\Controllers;

class UserController
{
    public function index()
    {
        echo "User Controller";
    }
}

Here, the UserController class belongs to the namespace App\Controllers. This prevents clashes with another UserController that might exist elsewhere in your project or in an external library.


Why use Namespaces?

Namespaces solve several problems:

- Avoiding Name Collisions

  • Without namespaces, two classes with the same name would cause a fatal error.
  • Example: User class in your project vs. User class in a third-party package.

- Better Code Organization

  • Namespaces act like logical "folders" in code.
  • You can group classes by functionality: Controllers, Models, Services, etc.

- Improved Autoloading

  • With standards like PSR-4, namespaces map directly to directory structures, making autoloading seamless.

- Readability & Maintainability

  • It's easier to understand where a class belongs in the project structure.

Declaring a Namespace

Declaring a namespace is simple. At the top of your PHP file:

namespace MyApp\Models;

class Product
{
    public function __construct()
    {
        echo "Product model initialized.";
    }
}

Now, this class is uniquely identified as:

MyApp\Models\Product

Using Namespaced Classes

If you want to use this class elsewhere, you have two options:

- Full Qualified Name (FQN)

require 'Product.php';

$product = new \MyApp\Models\Product();

Here, we use the backslash (\) to reference the global namespace and then specify the full namespace path.

- Import with use Keyword

require 'Product.php';

use MyApp\Models\Product;

$product = new Product();

This is cleaner and preferred in larger applications.


Sub-namespaces

Namespaces can be nested, like folders:

namespace MyApp\Services\Mail;

class Mailer
{
    public function send($message)
    {
        echo "Sending: $message";
    }
}

Now, this class is fully qualified as:

MyApp\Services\Mail\Mailer

Grouping Imports

Group use declarations can reduce repetitive code:

use MyApp\Models\{User, Product, Order};

$user = new User();
$product = new Product();
$order = new Order();

This avoids writing multiple use lines.


Global Namespace

By default, PHP code resides in the global namespace (no namespace declared).

For example:

class Logger
{
    public function log($msg)
    {
        echo $msg;
    }
}

If you want to explicitly refer to this global class from within a namespace, use a leading backslash:

namespace MyApp;

$logger = new \Logger();
// refers to global Logger class

Namespaces and Functions/Constants

Namespaces are not limited to classes - you can also namespace functions and constants:

namespace MyApp\Utils;

function formatDate($date) {
    return date('Y-m-d', strtotime($date));
}

const VERSION = '1.0.0';

// Usage
echo \MyApp\Utils\formatDate('now');
echo \MyApp\Utils\VERSION;

Autoloading with Namespaces (PSR-4)

Namespaces are especially powerful with autoloading.

Following PSR-4 standard:

- Namespace maps to directory structure.

- Example.

Namespace: App\Controllers

Directory: src/Controllers/

Composer's autoload section in composer.json:

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

This way, you don’t need to manually require files - autoloading resolves them automatically.


Common Mistakes with Namespaces

  • Namespace must be the first statement in a file (except for declare).
  • One file, one namespace (though multiple are technically allowed, it's bad practice).
  • Case-sensitive file systems: On Linux, namespace folder structure must match exactly.
  • Forgetting the leading \ when calling global functions or classes.

Real-World Example

Imagine two libraries define a class named PDF. Without namespaces, you'd have a conflict.

// Library 1
namespace Lib\PDF;
class PDF {}

// Library 2
namespace Vendor\PDF;
class PDF {}

Now you can use both in the same project:

use Lib\PDF\PDF as LibPDF;
use Vendor\PDF\PDF as VendorPDF;

$doc1 = new LibPDF();
$doc2 = new VendorPDF();

Aliases (as) solve naming conflicts elegantly.


Source: Orkhan Alishov's notes