PHP 命名空间

Resolving name clashes, sub-namespaces, use aliases, and PSR-4 autoloading.

Intermediate
Key PointsA namespace is a name prefix that prevents collisions; `use` imports an alias.

Why namespaces

Two libraries both define User. Without namespaces one must be renamed. Namespaces prefix the name so App\Models\User and Vendor\User coexist.

PHP
<?php
namespace App\Models;

class User {
    public function hello(): string {
        return "App\\Models\\User";
    }
}

namespace App\Services;

use App\Models\User as UserModel;

class User {
    public function hello(): string {
        return "App\\Services\\User";
    }
}

namespace App;

use App\Models\User;
use App\Services\User as UserService;

echo (new User())->hello(), "\n";
echo (new UserService())->hello(), "\n";
echo User::class, "\n";
Output
App\Models\User
App\Services\User
App\Models\User
Multiple namespace blocks per file are legal, but real projects use one per file (PSR-4). The above is for demonstration only.

Three ways to resolve names

FormMeaningExample
Foo\Bar相对当前命名空间在 App\Models 里指 App\Models\Foo\Bar
\Foo\Bar完全限定,从根开始始终是 Foo\Bar
namespace\Foo显式当前命名空间App\Models\Foo
PHP
<?php
namespace App\Models;

class User {}

// 三种写法指向同一个类
echo User::class, "\n";
echo namespace\User::class, "\n";
echo \App\Models\User::class, "\n";

// 不存在的相对名会去当前命名空间找
echo \strlen("abc"), "\n";     // 全局函数要加反斜杠
Output
App\Models\User
App\Models\User
App\Models\User
3
Functions and constants fall back to the global namespace, so strlen() works unqualified — but a same-named local function shadows it and the fallback costs a lookup.

Forms of use

PHP
<?php
namespace App;

use App\Models\User;                    // 导入类
use App\Models\Post as BlogPost;        // 别名
use function App\Helpers\format;        // 导入函数
use const App\Config\DEBUG;             // 导入常量

echo User::class, "\n";
echo BlogPost::class, "\n";
echo DEBUG ? "调试模式" : "生产模式", "\n";
Output
App\Models\User
App\Models\Post
调试模式

use only affects compile-time name resolution; it does not load anything. Loading is the autoloader's job.

PSR-4 autoloading

PSR-4 in one line: namespace prefix maps to a directory, class name to a file name. App\Models\User → <root>/Models/User.php.

PHP
<?php
spl_autoload_register(function (string $class): void {
    $prefix  = "App\\";
    $baseDir = __DIR__ . "/src/";

    if (!str_starts_with($class, $prefix)) {
        return;
    }

    $relative = substr($class, strlen($prefix));
    $file = $baseDir . str_replace("\\", "/", $relative) . ".php";

    if (is_file($file)) {
        require $file;
    }
});

echo "加载器已注册\n";
Output
加载器已注册

Real projects rely on composer dump-autoload and a single require 'vendor/autoload.php'. Writing it once teaches you what happens underneath.

Common mistakes

  • **namespace must be the first statement** (except declare); prior output is an error
  • **use inside a class** means trait import, not namespace import
  • Two same-named imports —— use A\User; use B\User; is a fatal conflict
  • Class names in strings —— escape backslashes or use User::class

Friends & Partners