Namespaces
A namespace is a naming container for classes, functions, and constants, similar in spirit to a folder for files. Without namespaces, every class in a PHP project — and every class in every third-party library it depends on — shares one single global naming pool. Once a project pulls in a handful of libraries, it becomes almost guaranteed that two of them will each define a class called something generic like Logger, Request, or Collection, and PHP has no way to tell those apart without namespaces. A namespace lets both classes exist under the same short name while remaining completely distinct to PHP, because their full identity includes the namespace they live in.
Declaring a namespace
A namespace is declared with the namespace keyword, and it must be the very first statement in the file — nothing except a leading comment or the opening <?php tag is allowed before it. Everything declared in that file (classes, functions, constants) now belongs to that namespace.
src/Billing/Invoice.php
<?php
namespace App\Billing;
class Invoice
{
public function __construct(public float $amount)
{
}
public function summary(): string
{
return "Invoice for \${$this->amount}";
}
}The class declared here isn't really named Invoice as far as PHP is concerned — its full, unambiguous name is App\Billing\Invoice. Anywhere outside this namespace, referring to plain Invoice will not find it; you need either the full name or a use import, covered next.
Importing with use, and aliasing
Typing the full namespaced name every time would be tedious, so PHP provides use statements near the top of a file (right after the namespace line, if there is one) to import a name and refer to it by its short form for the rest of the file. If two imported names would collide, or you simply want a clearer local name, use ... as ... renames the import for that file only.
Importing and aliasing with use
<?php namespace App\Reports; use App\Billing\Invoice; use App\Billing\Logger as BillingLogger; use App\Audit\Logger as AuditLogger; $invoice = new Invoice(150.00); echo $invoice->summary(), "\n"; $billingLog = new BillingLogger(); $auditLog = new AuditLogger();
Invoice resolves to App\Billing\Invoice because of the first use line. The two Logger classes — one from App\Billing, one from App\Audit — would collide under the same short name Logger, so each is imported under a distinct alias, BillingLogger and AuditLogger. Without the as clause, importing both in the same file would be a fatal "cannot use ... because the name is already in use" error.
Fully-qualified vs relative names
A name that starts with a leading backslash, like \App\Billing\Invoice, is a fully-qualified name: it is resolved from the absolute global root no matter what namespace the current file is in. A name without the leading backslash is relative — PHP resolves it against the current namespace first (unless it was imported with use, or it's a recognized global like strlen() or Exception). This distinction mostly matters when you're referring to something from inside a namespaced file without importing it first.
Fully-qualified access without a use import
<?php
namespace App\Reports;
// No "use" statement for Invoice here.
$invoice = new \App\Billing\Invoice(75.50);
echo $invoice->summary(), "\n";
// PHP's built-in classes and functions are always reachable
// from the global namespace without a leading backslash needed
// in most cases, but it's unambiguous either way:
$now = new \DateTime();
echo $now->format('Y') . "\n";Leaving off the leading backslash and just writing App\Billing\Invoice from inside the App\Reports namespace would actually make PHP look for App\Reports\App\Billing\Invoice, which doesn't exist — relative class names are appended to the current namespace, not resolved from the root. This is a common source of confusion when moving a class-reference line between files that live in different namespaces; a use import at the top of the file sidesteps the whole issue by resolving the name once, explicitly.
How namespaces avoid real collisions
Picture a project that depends on two logging packages: one from a vendor called Acme and one it wrote in-house. Both happen to define a class named Logger. Before namespaces existed, PHP simply could not have two classes both named Logger loaded at once — the second class Logger declaration would be a fatal "cannot redeclare" error. With namespaces, this is a complete non-issue.
Acme/Logging/Logger.php — a vendor package's Logger
<?php
namespace Acme\Logging;
class Logger
{
public function log(string $message): void
{
echo "[Acme] {$message}\n";
}
}App/Logging/Logger.php — a completely different Logger
<?php
namespace App\Logging;
class Logger
{
public function log(string $message): void
{
echo "[App] {$message}\n";
}
}Using both Loggers in the same script
<?php
use Acme\Logging\Logger as VendorLogger;
use App\Logging\Logger as AppLogger;
(new VendorLogger())->log('vendor event');
(new AppLogger())->log('app event');Both classes are named Logger and both would have collided in the global namespace, but Acme\Logging\Logger and App\Logging\Logger are entirely distinct identities as far as PHP is concerned. This is exactly why namespaces matter more as a project grows: it lets library authors pick short, obvious names without needing to worry about clashing with every other library on Packagist.
A quick look ahead: namespaces and file paths
In real projects, namespaces don't float independently of the filesystem — they typically follow a convention called PSR-4, which maps a namespace prefix directly onto a directory. For instance, a class named App\Services\Mailer conventionally lives in a file at src/Services/Mailer.php, where App\ maps to the project's src/ directory. Following this convention consistently is what allows tools (and Composer specifically) to find and load the right file automatically just from seeing a namespaced class name used in code — no manual require needed. That mechanism, autoloading, is its own topic worth covering separately.
The
namespace App\Billing;declaration must be the first statement in a file and applies to everything declared below it.A
use App\Billing\Invoice;statement imports a name for short-form use in the current file only.use ... as ...renames an import, which is how two same-named classes from different namespaces can be used side by side.A leading backslash before a name is a fully-qualified reference resolved from the global root; a name without one is resolved relative to the current namespace.
Namespaces let two libraries each define a class with the same short name without a fatal "cannot redeclare" collision.
By convention (PSR-4), a namespace prefix maps to a directory, e.g.
App\Services\Mailerliving atsrc/Services/Mailer.php.