PHP Namespaces
What Is a Namespace?
In simple terms: A namespace is like a folder for names. Two files can both be called report.pdf if they live in different folders; likewise, two classes can both be called Invoice if they live in different namespaces — App\Billing\Invoice and App\Shipping\Invoice. Namespaces prevent name collisions and organize code into logical groups.
Technically: A namespace is declared with the namespace keyword at the top of a file. Classes, interfaces, traits, enums, functions, and constants declared in that file belong to the namespace. Their fully qualified name includes the namespace, separated by backslashes. The use statement imports names so they can be referred to by a shorter name.
Why Namespaces Are Needed
Modern applications combine their own code with dozens of Composer packages. Without namespaces, every class name in every package would have to be globally unique — a Logger class in your project would clash with a Logger class in a library. With namespaces, each vendor has its own space: Monolog\Logger, App\Support\Logger, and so on.
Declaring a Namespace
Normally, each file contains one namespace declaration as its first statement:
<?php
// src/Billing/Invoice.php
declare(strict_types=1);
namespace App\Billing;
final class Invoice
{
public function __construct(public readonly string $number) {}
}
- The
namespacestatement must come before any other code (onlydeclaremay precede it). - The class's full name is now
App\Billing\Invoice. - By convention (PSR-4), the namespace mirrors the folder structure:
App\Billing\Invoicelives insrc/Billing/Invoice.php. This convention allows classes to be loaded automatically (see Autoloading Classes).
Using Names From Other Namespaces
The following example puts several namespaces in one file using the bracketed syntax, so it can be run as a single script. (In real projects, use one namespace per file.)
<?php
namespace App\Billing {
final class Invoice
{
public function type(): string
{
return __CLASS__;
}
}
}
namespace App\Shipping {
final class Invoice
{
public function type(): string
{
return __CLASS__;
}
}
}
namespace {
use App\Billing\Invoice;
use App\Shipping\Invoice as ShippingInvoice;
echo (new Invoice())->type() . "\n";
echo (new ShippingInvoice())->type() . "\n";
echo (new \App\Billing\Invoice())->type() . "\n";
echo Invoice::class . "\n";
}
Output
App\Billing\Invoice
App\Shipping\Invoice
App\Billing\Invoice
App\Billing\Invoice
How It Works
- Two classes named
Invoicecoexist because they are in different namespaces. use App\Billing\Invoice;imports the class: in this file,Invoicenow meansApp\Billing\Invoice.use ... as ShippingInvoiceimports the secondInvoiceunder an alias, avoiding a conflict in this file.- A name beginning with `` is fully qualified and works without any import.
Invoice::classresolves the imported name to its full class name at compile time.- The block
namespace { ... }contains code in the global namespace.
Types of Names
| Name | Example | Resolved As |
|---|---|---|
| Unqualified | Invoice | Imported name, or current namespace + Invoice |
| Qualified | Billing\Invoice | Current namespace + Billing\Invoice (unless the first part is imported) |
| Fully qualified | \App\Billing\Invoice | Exactly as written |
Global Classes Inside a Namespace
Inside a namespace, an unqualified class name always refers to the current namespace — even for PHP's built-in classes:
<?php
namespace App\Orders;
try {
throw new Exception('Payment failed');
} catch (\Error $e) {
echo $e->getMessage() . "\n";
}
Output
Class "App\Orders\Exception" not found
PHP looked for App\Orders\Exception. Built-in classes live in the global namespace, so they must be imported or written with a leading backslash:
use Exception; // option 1: import
throw new \Exception('...'); // option 2: fully qualified
Functions and Constants Fall Back to Global
Functions and constants behave differently: if App\Orders\strlen() does not exist, PHP falls back to the global strlen(). That is why calling strlen(), count(), or using PHP_EOL inside a namespace works without a backslash. Some projects still write \strlen() or import functions (use function strlen;) to skip the fallback lookup, which gives a small performance benefit for certain optimized built-in functions.
Importing Functions and Constants
<?php
namespace App\Support {
const CURRENCY = 'INR';
function money(int $paise): string
{
return '₹' . number_format($paise / 100, 2);
}
}
namespace App\Reports {
use function App\Support\money;
use const App\Support\CURRENCY;
echo money(129900) . ' (' . CURRENCY . ")\n";
}
Output
₹1,299.00 (INR)
use function and use const import namespaced functions and constants, just as use imports classes.
Group Imports
Several names from the same namespace can be imported together:
use App\Billing\{Invoice, InvoiceLine, PaymentStatus};
Useful Namespace Helpers
| Expression | Value |
|---|---|
__NAMESPACE__ | The current namespace as a string (empty in the global namespace) |
ClassName::class | The fully qualified class name |
namespace\helper() | Explicitly refers to helper() in the current namespace |
static::class, get_class($obj) | Full class name of an object at runtime |
Organizing a Project With Namespaces
A typical structure for an application with the root namespace App:
project/
├── composer.json "autoload": { "psr-4": { "App\\": "src/" } }
└── src/
├── Billing/
│ ├── Invoice.php namespace App\Billing; class Invoice
│ └── InvoiceService.php
├── Catalog/
│ ├── Product.php namespace App\Catalog; class Product
│ └── ProductRepository.php
└── Support/
└── Money.php namespace App\Support; class Money
Guidelines
- Use a vendor or project prefix as the root (
App,GoCourse,Acme\Shop). - Group by feature or domain (
Billing,Catalog,Shipping) rather than by technical type alone. - Use
PascalCasefor namespace segments, matching the folder names exactly (paths are case-sensitive on Linux servers). - Put one class per file, with the file named after the class.
Common Mistakes
Forgetting the Backslash for Global Classes
Effect: Class "App 0 ..\Exception" not found or DateTime not found.
Fix: use Exception; or new \Exception().
Code Before the namespace Statement
Effect: Fatal error: the namespace declaration must be the first statement.
Fix: Only <?php and declare(...) may come before it.
Namespace Does Not Match the Folder
Effect: The autoloader cannot find the class.
Fix: Keep namespaces and directories in sync (PSR-4).
Importing Two Classes With the Same Short Name
Effect: Fatal error: "Cannot use ... because the name is already in use".
Fix: Use an alias with as.
Using use Inside Functions
Effect: Syntax error — use imports must be at the top level of the file (the use in closures is unrelated).
Fix: Place imports after the namespace declaration.
Best Practices
- Declare exactly one namespace per file, matching its directory (PSR-4).
- Import classes with
useat the top of the file, sorted alphabetically. - Use aliases only when names collide, and choose descriptive alias names.
- Import or fully qualify global classes inside namespaces.
- Use namespaces to group code by domain or feature.
Official reference: https://www.php.net/manual/en/language.namespaces.php