A name conflict happens when two things want the same name in the same place. Namespaces prevent most conflicts, but you can still meet one, usually when you import two classes with the same short name.
The problem
<?php
namespace Main;
use App\Logger;
use Vendor\Logger; // Fatal error: the name Logger is already in use
Fatal error: Cannot use Vendor\Logger as Logger because the name is already in use in /path/to/index.php on line 5
Fix 1: an alias
<?php
namespace App { class Mailer { public function who(): string { return "App"; } } }
namespace Vendor { class Mailer { public function who(): string { return "Vendor"; } } }
namespace Main {
use App\Mailer;
use Vendor\Mailer as VendorMailer;
echo (new Mailer())->who() . " " . (new VendorMailer())->who();
}
App Vendor
Fix 2: a fully qualified name
Do not import one of them, and write its full name at the place you use it.
<?php
namespace App { class Cache { public function who(): string { return "App cache"; } } }
namespace Vendor { class Cache { public function who(): string { return "Vendor cache"; } } }
namespace Main {
use App\Cache;
echo (new Cache())->who() . " / " . (new \Vendor\Cache())->who();
}
App cache / Vendor cache
How PHP looks names up
There are three kinds of name:
| Kind | Example | Meaning |
|---|---|---|
| Unqualified | Product | Relative to the current namespace (or an import) |
| Qualified | Shop\Product | Relative to the current namespace |
| Fully qualified | \App\Shop\Product | An absolute name from the global root |
Inside namespace App;, writing Shop\Product means App\Shop\Product.
Functions and constants fall back to global
For functions and constants, PHP tries the current namespace first, then the global one. That is why strlen() works anywhere.
<?php
namespace App;
function strlen(string $s): int
{
return -1; // shadows the global strlen inside this namespace
}
echo strlen("abc") . " " . \strlen("abc");
-1 3
Inside App, a plain strlen() found the namespaced function first. The leading backslash called the real one. This is why defining functions with the same name as built-ins is a bad idea.
For classes, there is no fallback: DateTime inside a namespace does not mean the global DateTime unless you import it or write \DateTime.
Avoid conflicts in the first place
- Give each project one vendor namespace (
MyCompany\orApp\). - Do not name your classes after built-in ones (
Exception,Error,Closure,Iterator). - Use descriptive names (
PaymentLoggerrather thanLogger).
Read the error
use lines import the same short name. Add as to one of them.