? 一、为什么要用命名空间?
? 问题:名字冲突了怎么办?
想象你在学校点名:
- 老师喊:“小明!”
- 结果全班 5 个“小明”都站起来……
这就叫:重名冲突。
在 PHP 中,如果两个类都叫 User
,就会出错:
class User { } // 用户类
class User { } // 学生类 ❌ 报错!不能重复定义
怎么办?—— 给它们“贴标签”!
?️ 二、什么是命名空间?—— 就像给代码分“部门”
命名空间(Namespace)就是给类、函数、常量起“全名”的方式。
比如:
namespace Admin;
class User { } // 全名是:AdminUser
namespace Student;
class User { } // 全名是:StudentUser
? 三、如何定义命名空间?
✅ 基本语法
<?php
namespace 项目名模块名子模块;
class User { }
function login() { }
const VERSION = '1.0';
? 注意:
- 必须写在文件最开头(
<?php
之后) - 可以多层:
MyAppAdminAuth
- 一个文件一般只定义一个命名空间(推荐)
?️ 四、子命名空间:大楼里的“楼层”和“房间”
就像公司分部门:
namespace MyProjectUser; // 用户部
namespace MyProjectOrder; // 订单部
namespace MyProjectPayment; // 支付部
好处:
- 结构清晰
- 不会重名
- 方便管理
? 文件夹建议对应命名空间:
src/
└── User/
└── UserService.php → namespace MyProjectUser;
? 五、三种引用方式:非限定、限定、完全限定
假设你在 MyProjectOrder
这个“办公室”里。
写法 | 类型 | 含义 | 比喻 |
---|---|---|---|
User::login() | 非限定 | 找 MyProjectOrderUser | “叫小明!”(默认是本部门的) |
UserUser::login() | 限定 | 找 MyProjectOrderUserUser | “叫用户组的小明!” |
MyProjectUserUser::login() | 完全限定 | 绝对路径,从根找 | “总部三楼的小明!” |
✅ 重点区别:
- 非限定:只写名字 → 从当前空间找
- 限定:带路径 → 当前空间 + 路径
- 完全限定:带 `` 开头 → 从最外层开始找
? 六、全局函数/常量怎么调?
如果你覆盖了 PHP 内置函数,想调原始的怎么办?
function strlen($str) { return 0; } // 自己写的
strlen("hello"); // ❌ 调的是自己的
strlen("hello"); // ✅ 调全局的内置函数
✅ 所有全局类、函数、常量都可以加 `` 调用:
DateTime::createFromFormat(...);
Exception("错误");
INI_ALL;
? 七、use 和 别名:给长名字起“小名”
全名太长?可以用 use
简化:
<?php
namespace MyApp;
use MyProjectDatabaseConnection as DB;
use function MyProjectUtilshelper as help;
use const MyProjectConfigHOST as SERVER;
// 使用别名
$db = new DB(); // 相当于 new MyProjectDatabaseConnection
help(); // 相当于 MyProjectUtilshelper()
echo SERVER; // 相当于 MyProjectConfigHOST
? use
必须写在 namespace
之后,其他代码之前。
? 八、动态调用命名空间元素
有时候名字是“变量”,比如:
$className = "MyProjectUserUser";
$obj = new $className(); // ✅ 可以!
$funcName = "MyProjecthelp";
$funcName(); // ✅ 可以!
echo constant("MyProjectVERSION"); // ✅ 读常量
⚠️ 重要规则:
在动态调用中:
"MyProjectUser"
和"MyProjectUser"
效果一样- 开头的 `` 可有可无,因为字符串本身就是完整路径
? 九、__NAMESPACE__
和 namespace
关键字
这是两个“定位工具”,帮你更灵活地写代码。
1. __NAMESPACE__
:GPS 定位器
返回当前命名空间的名字(字符串):
namespace MyProjectOrder;
echo __NAMESPACE__;
// 输出:MyProjectOrder
用途:动态拼类名
$full = __NAMESPACE__ . 'User';
$obj = new $full; // new MyProjectOrderUser
2. namespace
关键字:指南针
用来“从当前空间出发”访问元素,类似 self
:
namespacelogin(); // 调当前空间的 login 函数
namespaceUser::find(1); // 调当前空间的 User 类
$obj = new namespaceOrder(); // 创建当前空间的 Order 对象
$version = namespaceVERSION; // 获取当前空间的常量
? 它让你不用写死全名,更安全、更灵活。
? 十、多个命名空间写在一个文件里?(不推荐)
PHP 允许,但非常不推荐!
✅ 推荐写法(大括号)
<?php
namespace MyProject {
class User { }
}
namespace YourProject {
class User { }
}
namespace { // 全局代码
echo "这是公共代码";
}
❌ 不推荐写法(无括号)
<?php
namespace A;
class User {}
namespace B;
class User {} // 混乱,易出错
? 使用场景:
- 合并文件打包
- 自动加载优化
- 不用于日常开发
?️ 十一、常见错误 & 最佳实践
错误 | 正确做法 |
---|---|
在命名空间外直接写 echo | 放进 namespace { } 或移到外面 |
非静态方法当函数调用 | 要 new 对象 或 加 static |
use 写错位置 | 必须在 namespace 后,其他代码前 |
文件编码问题 | 推荐 UTF-8,可用 declare(encoding='UTF-8'); |
✅ 最佳实践:
- 一个文件一个类,一个命名空间
- 命名空间与文件夹结构一致
- 多用
use
简化长名字 - 动态调用用字符串全名
- 全局函数用 `` 调用
? 总结:一张图看懂命名空间
根空间
├── AdminUser → AdminUser
├── StudentUser → StudentUser
├── MyProjectOrder → 当前空间
├── User → 非限定:User → MyProjectOrderUser
├── PaymentPay → 限定:PaymentPay → MyProjectOrderPaymentPay
└── GlobalFun → 完全限定:绝对路径