Skip to content
Theory · Files, namespaces and Composer · lesson 2 of 7

Namespaces and use

In the previous lesson files became books on shelves. The more books there are, the more often titles repeat: a library will have five books called "Basics". The shelf tells them apart: "Basics" from the Chemistry shelf and "Basics" from the Music shelf are different books.

Classes work the same way. Your project declares a class User, and a package you downloaded declares a User too. PHP won't accept two classes with one name: at the second declaration the script stops with a fatal error, because the name is already taken.

That is why classes have shelves. A namespace is a prefix PHP adds to the name of every class declared in a file.

The full class name

A namespace is declared by the first statement after <?php: the word namespace and the shelf's name. The parts of the name are separated with a backslash \:

PHP
<?php

namespace App\Models;

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

$u = new User('Anna');
echo User::class, "\n"; // App\Models\User
echo get_class($u), "\n"; // App\Models\User

Let's go through it line by line:

  1. namespace App\Models; puts the prefix App\Models\ on everything declared in this file.
  2. That is why class User declares a class with the full name App\Models\User.
  3. Inside the same namespace you can refer to the class by its short name: new User('Anna').
  4. User::class and get_class($u) show the class's real name—the full one.

The short name User is only a convenience for writing. PHP works with the full name everywhere, so App\Models\User and Shop\Auth\User are two different classes, and they don't get in each other's way.

Namespace names are written in PascalCase. The first part is usually the name of the project or the company: App, Monolog, Symfony.

use: a short name

From another namespace you refer to a class by its full name: new \App\Models\User('Anna'). A backslash at the start means "look from the root, not on the current shelf". Writing the full name on every line is tedious, so at the top of the file you put use—a bookmark with a short name:

PHP
<?php

namespace App\Http;

use App\Models\User;
use App\Models\Order as Purchase;

echo User::class, "\n"; // App\Models\User
echo Purchase::class, "\n"; // App\Models\Order

What happens here:

  • use App\Models\User; says that in this file User means App\Models\User;
  • the word as gives the bookmark another name: Purchase means App\Models\Order;
  • bookmarks work only in their own file, and another file needs its own.

A name with as is chosen when two classes from different namespaces have the same name: use Shop\Auth\User as AuthUser;.

Here the picture parts ways with PHP. A real bookmark goes into a book that stands on the shelf. But use does not pull in a file and does not check whether the class exists.

This program has no User or Order classes at all, and the names were printed anyway. The line new User() in it would end with the error Class "App\Models\User" not found.

Functions and constants are different: if the current namespace has none by that name, PHP takes the global one. That is why strlen, count and PHP_INT_MAX work inside namespace App without any use.

Built-in classes: \Exception

PHP's built-in classes—Exception, RuntimeException, InvalidArgumentException—live in the global namespace, at the root. Inside namespace App the short name Exception means App\Exception: PHP looks for the class on the current shelf and does not look into the root.

This is especially sneaky in catch. PHP does not check whether the class in a catch exists; it only compares the thrown object with it. A block with a class that doesn't exist never fires, and there is no error at all:

PHP
<?php

namespace App;

try {
    throw new \InvalidArgumentException('empty name');
} catch (InvalidArgumentException $e) {
    echo 'first', "\n";
} catch (\InvalidArgumentException $e) {
    echo 'second: ', $e->getMessage(), "\n"; // second: empty name
}

Let's go through it step by step:

  1. throw throws an object of the global class \InvalidArgumentException.
  2. The first catch expects App\InvalidArgumentException. No such class exists, and the block is silently skipped.
  3. The second catch names the global class with \ and catches the exception.

There are two ways to fix the first catch: write \InvalidArgumentException, or put the line use InvalidArgumentException; after namespace. Why catch (Exception $e) inside a namespace catches nothing is a common interview question.

Common mistake

A built-in class was created without the backslash:

PHP
<?php

namespace App;

throw new Exception('empty name'); // ✗
TEXT
Fatal error: Uncaught Error: Class "App\Exception" not found

Unlike catch, new requires the class to exist. PHP looks for App\Exception, doesn't find it and throws an Error. The fix is throw new \Exception('empty name'); or the line use Exception; after namespace.

Key points

  • namespace App\Models; adds a prefix to every class in the file: the full class name is App\Models\User.
  • use App\Models\User; is a bookmark with a short name for one file; it does not pull in the class's file.
  • Inside a namespace a class name without \ is looked up on the current shelf, so built-in classes are written as \Exception or imported with use.
  • A catch with a class that doesn't exist silently never fires, while new with such a class throws an Error.