PHP 命名空间
本章将介绍 PHP 命名空间的概念和使用方法。
什么是命名空间?
命名空间是一种封装事物的方法,用于解决类名冲突问题。在大型项目中,不同库可能存在同名类,命名空间可以区分它们。
定义命名空间
基本语法
<?php
// 命名空间必须在文件顶部
namespace MyApp\Models;
class User {
public $name;
}
?>
子命名空间
<?php
namespace MyApp\Models\Auth;
class User {
// 完整类名:MyApp\Models\Auth\User
}
?>
多个命名空间
<?php
namespace MyApp\Models {
class User {
// ...
}
}
namespace MyApp\Controllers {
class UserController {
// ...
}
}
// 全局命名空间
namespace {
class GlobalClass {
// ...
}
}
?>
使用命名空间
完整类名
<?php
// 使用完整类名
$user = new \MyApp\Models\User();
// 调用静态方法
\MyApp\Models\User::find(1);
// 访问常量
echo \MyApp\Config\VERSION;
?>
use 导入
<?php
// 导入类
use MyApp\Models\User;
$user = new User();
// 导入并设置别名
use MyApp\Models\User as UserModel;
use MyApp\Controllers\User as UserController;
$model = new UserModel();
$controller = new UserController();
// 导入多个类
use MyApp\Models\{User, Post, Comment};
// 导入函数(PHP 5.6+)
use function MyApp\Utils\formatDate;
// 导入常量
use const MyApp\Config\VERSION;
?>
use 与命名空间组合
<?php
namespace MyApp\Controllers;
// 导入其他命名空间的类
use MyApp\Models\User;
use MyApp\Services\AuthService;
class UserController {
public function show($id) {
$user = User::find($id);
AuthService::check();
return $user;
}
}
?>
命名空间解析规则
相对命名空间
<?php
namespace MyApp\Controllers\Admin;
// 相对于当前命名空间
$user = new User(); // MyApp\Controllers\Admin\User
// 相对于根命名空间
$user = new \MyApp\Models\User();
// 相对于父命名空间
$user = new ..\Models\User(); // 错误!不支持
// 正确方式
use MyApp\Models\User;
$user = new User();
?>
解析优先级
<?php
namespace MyApp\Controllers;
use MyApp\Models\User;
class UserController {
public function test() {
// 1. 首先查找当前命名空间
// new User() -> MyApp\Controllers\User(如果存在)
// 2. 然后查找 use 导入
// new User() -> MyApp\Models\User(因为 use 导入)
// 3. 最后查找全局命名空间
// new \DateTime() -> 全局 DateTime 类
}
}
?>
自动加载
PSR-4 自动加载
PSR-4 是 PHP 标准推荐的自动加载规范,命名空间与目录结构对应。
项目结构:
src/
Models/
User.php
Post.php
Controllers/
UserController.php
Services/
AuthService.php
<?php
// src/Models/User.php
namespace MyApp\Models;
class User {
// ...
}
?>
<?php
// composer.json
{
"autoload": {
"psr-4": {
"MyApp\\": "src/"
}
}
}
?>
# 生成自动加载文件
composer dump-autoload
<?php
// 使用自动加载
require 'vendor/autoload.php';
use MyApp\Models\User;
use MyApp\Controllers\UserController;
$user = new User();
$controller = new UserController();
?>
自定义自动加载
<?php
spl_autoload_register(function ($class) {
// 将命名空间转换为文件路径
$prefix = 'MyApp\\';
$base_dir = __DIR__ . '/src/';
// 检查是否使用此命名空间前缀
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
return;
}
// 获取相对类名
$relative_class = substr($class, $len);
// 替换命名空间分隔符为目录分隔符
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
// 加载文件
if (file_exists($file)) {
require $file;
}
});
?>
命名空间最佳实践
目录结构
project/
├── src/
│ ├── Controllers/
│ │ └── UserController.php
│ ├── Models/
│ │ └── User.php
│ ├── Services/
│ │ └── UserService.php
│ └── Helpers.php
├── tests/
├── vendor/
└── composer.json
命名规范
<?php
// 命名空间使用 PascalCase
namespace MyApp\Models;
// 类名使用 PascalCase
class UserProfile {}
// 常量使用 UPPER_CASE
const MAX_ITEMS = 100;
// 方法名使用 camelCase
public function getUserById($id) {}
// 变量名使用 camelCase 或 snake_case
$userName = "张三";
$user_name = "张三";
?>
一个文件一个类
<?php
// 推荐:一个文件只定义一个类
// src/Models/User.php
namespace MyApp\Models;
class User {
// ...
}
?>
命名空间与函数
<?php
namespace MyApp\Utils;
// 定义函数
function formatDate($timestamp) {
return date('Y-m-d', $timestamp);
}
// 定义常量
const DATE_FORMAT = 'Y-m-d';
?>
<?php
// 使用命名空间中的函数
use function MyApp\Utils\formatDate;
use const MyApp\Utils\DATE_FORMAT;
echo formatDate(time());
echo DATE_FORMAT;
// 或使用完整名称
echo \MyApp\Utils\formatDate(time());
?>
小结
本章我们学习了:
- 命名空间的定义和使用
- use 导入和别名
- 命名空间解析规则
- PSR-4 自动加载
- 命名空间最佳实践
下一章我们将学习异常处理。