命名空間解決類別/函數/常數命名衝突,支援程式碼模組化組織。PHP 5.3 引入,現為現代專案(Composer、PSR-4、框架)標準基礎設施。本文系統整理定義語法、導入機制、解析規則與實務模式。
<?php
// 檔案頂部第一行(除 declare 外)
namespace App\Models;
class User { /* ... */ }
function helper() { /* ... */ }
const STATUS_ACTIVE = 1;
規則: 命名空間宣告必須是檔案第一個 PHP 敘述(前面只能有 declare),不能有 HTML、空白、BOM。
<?php
namespace App\Http\Controllers\Api\v1;
class UserController { /* ... */ }
對應目錄結構:App/Http/Controllers/Api/v1/UserController.php(PSR-4 標準)。
<?php
namespace ProjectA {
class Config { /* ... */ }
}
namespace ProjectB {
class Config { /* ... */ }
}
namespace { // 全域空間
$a = new ProjectA\Config();
$b = new ProjectB\Config();
}
| 方式 | 語法 | 解析規則 | 範例 |
|---|---|---|---|
| 非限定名稱 | ClassName | 當前命名空間 + 名稱 | 當前 App\Models → App\Models\User |
| 限定名稱 | Sub\ClassName | 當前命名空間 + 相對路徑 | 當前 App\Models → App\Models\Sub\User |
| 完全限定名稱 | \ClassName | 全域絕對路徑 | \App\Models\User 固定解析 |
<?php
namespace App\Models;
use App\Services\EmailService; // 導入
$user = new User(); // 非限定 → App\Models\User
$service = new EmailService(); // 導入別名 → App\Services\EmailService
$validator = new \App\Validators\UserValidator(); // 完全限定
$helper = new Helpers\ArrayHelper(); // 限定 → App\Models\Helpers\ArrayHelper
<?php
namespace App\Controllers;
use App\Models\User; // 導入類別
use App\Models\{User, Post, Comment}; // 群組導入 (PHP 7.0+)
use App\Services\EmailService as Mailer; // 別名
use function App\Helpers\formatDate; // 導入函數 (PHP 5.6+)
use const App\Config\MAX_UPLOAD_SIZE; // 導入常數 (PHP 5.6+)
// 使用
$user = new User();
$mailer = new Mailer();
$date = formatDate('now');
$max = MAX_UPLOAD_SIZE;
<?php
namespace App;
$className = 'Models\User';
$obj = new $className(); // 解析為 App\Models\User
$className = '\App\Models\User'; // 完全限定也可
$obj = new $className();
// 函數/常數
$func = 'Helpers\formatDate';
$func(); // App\Helpers\formatDate
$const = 'Config\MAX_SIZE';
echo constant($const); // 或 constant('\App\Config\MAX_SIZE')
注意: 動態存取時,非限定/限定名稱視為相對當前命名空間。建議動態情境使用完全限定名稱。
<?php
namespace App\Models;
echo __NAMESPACE__; // "App\Models"
// namespace 關鍵字:相當於類別中的 self
namespace\Helper::staticMethod(); // App\Models\Helper::staticMethod()
$obj = new namespace\Sub\ClassName(); // App\Models\Sub\ClassName
$const = namespace\CONSTANT; // App\Models\CONSTANT
// 全域空間使用 namespace 關鍵字
namespace {
namespace\SomeClass(); // 全域 \SomeClass
}
\A\B → A\Buse C\D as E; new E() → new C\D()new C() 在 A\B → A\B\C<?php
namespace A\B;
use C\D as E;
new E(); // 導入 → C\D
new \E(); // 完全限定 → E (全域)
new C\D(); // 限定 → A\B\C\D
new \C\D(); // 完全限定 → C\D
foo(); // 1. A\B\foo() 2. 全域 foo()
new Foo(); // 1. A\B\Foo 2. 自動載入 A\B\Foo
<?php
namespace MyProject;
function fopen() { /* 覆寫內建 */ }
$f = \fopen('file.txt', 'r'); // 呼叫全域 fopen
class Exception extends \Exception { /* 自訂例外 */ }
throw new \Exception('msg'); // 拋出內建 Exception
// composer.json
{
"autoload": {
"psr-4": {
"App\\": "src/",
"Domain\\": "domain/src/"
}
}
}
// 目錄結構
src/
├── Models/
│ └── User.php // namespace App\Models; class User
├── Services/
│ └── EmailService.php // namespace App\Services; class EmailService
└── Controllers/
└── UserController.php // namespace App\Controllers; class UserController
// 執行 composer dump-autoload 產生 vendor/autoload.php
require_once __DIR__ . '/vendor/autoload.php';
// 直接使用
use App\Models\User;
use App\Services\EmailService;
src/
├── Domain/
│ ├── User/
│ │ ├── User.php // 實體
│ │ ├── UserId.php // 值物件
│ │ └── UserRepository.php // 介面
│ └── Order/
├── Application/
│ └── UseCases/
├── Infrastructure/
│ ├── Persistence/
│ │ └── DoctrineUserRepository.php
│ └── External/
└── Presentation/
└── Http/
└── Controllers/
namespace App\Contracts;
interface UserRepositoryInterface { /* ... */ }
namespace App\Infrastructure\Persistence;
use App\Contracts\UserRepositoryInterface;
class EloquentUserRepository implements UserRepositoryInterface { /* ... */ }
| 錯誤 | 後果 | 修正 |
|---|---|---|
| 命名空間前有輸出 | Fatal error | 確保 |
| use 導入函數/常數未加前綴 | 解析為類別 | use function ..., use const ... |
| 動態實例化用相對名稱 | 解析錯誤 | 使用完全限定名稱字串 |
| 同名類別未用別名 | 衝突 | use A\User as AUser; use B\User as BUser; |
| 導入後仍用完全限定 | 多餘冗長 | 導入後用短名稱 |
<?php
// 簡易 PSR-4 載入器
class Autoloader {
private array $prefixes = [];
public function addNamespace(string $prefix, string $baseDir): void {
$prefix = rtrim($prefix, '\\') . '\\';
$baseDir = rtrim($baseDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
$this->prefixes[$prefix] = $baseDir;
}
public function register(): void {
spl_autoload_register([$this, 'loadClass']);
}
public function loadClass(string $class): void {
foreach ($this->prefixes as $prefix => $baseDir) {
if (str_starts_with($class, $prefix)) {
$relativeClass = substr($class, strlen($prefix));
$file = $baseDir . str_replace('\\', DIRECTORY_SEPARATOR, $relativeClass) . '.php';
if (file_exists($file)) {
require_once $file;
return;
}
}
}
}
}
$loader = new Autoloader();
$loader->addNamespace('App', __DIR__ . '/src');
$loader->addNamespace('Domain', __DIR__ . '/domain/src');
$loader->register();
命名空間是現代 PHP 專案架構的骨幹。遵循 PSR-4、善用導入別名、理解解析規則、配合自動載入,能構建清晰、無衝突、可擴展的程式碼庫。