目录
- 命名空间
- 概念?解决了什么问题?
- 定义
- 使用和解析规则
- 其他
- 自动加载
- 概念?解决了什么问题?
- PSR-4
命名空间
概念
命名空间是类似于文件系统的一个虚拟容器,可以用于类(包括抽象类和traits)、接口、函数、常量。
类似于文件系统,可以把类放进一个多层级的命名空间,主要是解决类名的命名冲突问题。
定义命名空间
<?php
namespace haha\hehe\heihei
const CON1 = 10;
function run(){
//....
}
class ClassA{
//....
}
- 用namespace声明一个命名空间,表明接下去的代码属于这个命名空间
- 声明语句必须是文件第一句
- 也可以在后面加个大括号来显式表明这个命名空间范围,这样可以做到一个文件中有多个命名空间,但是非常不建议这样,没必要,没有可读性,一般就是这样使用,也不用大括号
使用命名空间
没有命名空间之前,就是
require('\src\ClassA.php');
new ClassA();
有了命名空间后
//现在都配合自动加载,不require
new \haha\hehe\heihei\ClassA();
如果多次要new一个对象,觉得累赘,可以这样
use haha\hehe\heihei\ClassA; //注意最前面的斜杠可以省略
$obj1 = new ClassA();
$obj2 = new ClassA();
$obj3 = new ClassA();
这叫导入类,还可以给类起别名
use haha\hehe\heihei\ClassA as A; //注意最前面的斜杠可以省略
new A();
命名解析规则
- 解析命名空间跟文件系统的路径解析是一样的,有相对路径和绝对路径两种。
- 绝对路径在命名空间中叫“完全限定名”,文件系统的根目录是\,命名空间也是\,以\开头的就是完全限定名
- 相对路径在命名空间叫“非限定名”(只有类名),“限定名”(有路径,但是不是从\开始),总之不是\开头的
- 绝对路径(完全限定名)的解析没啥的,都从\开始,明明白白
- 非完全限定的,解析的时候就会加上当前命名空间名称
<?php
namespace My\n1amespace
new \app\controller\User(); //完全限定名 很清楚
new User(); //就解析为My\n1amespace\User
new haha\User(); //就解析为My\n1amespace\haha\User
其他
__NAMESPACE__常量
<?php
namespace My\n1amespace{
echo 'inside'.__NAMESPACE__; //My\n1amespace 如果没有命名空间就是''
}
自动加载
概念
如果你需要用一个类,那你得先require,当你用一个类的时候,可能无所谓,当你的类用的多的时候,就很麻烦了。
自动加载1.0,在命名空间出现之前,就有自动加载,与原理就是,你可以告诉php解释器一个函数(用__autoload()或者spl_autoload_register()注册
),当你用一个类,而又没有导入的时候,系统就会运行这个函数。
自动加载2.0,在命名空间出现后,PSR-4规定了一个基于命名空间的统一的自动加载规范
PSR-4
其实问题的核心是,如何从命名空间,得到实际的文件位置?
两点
- 通过自动加载函数 将根命名空间或者较高级别的命名空间 与 目录一一关联
- 从根目录或者特定的目录往下,命名层级与目录层级一一对应
看一个例子就知道
spl_autoload_register(function($class_name){
//命名空间前缀
$prefixe = '\Foo\\Bar';
//基目录
$base_dir = __DIR__.'/src/';
//匹配是否 是在寻找这个命名空间下的类
$len = strlen($prefix);
if(strncmp($prefix,$class_name,$len)!==0){
return ;
}
//将命名空间转换为目录位置
$relative_class = substr($class.$len);
$file = $base_dir . str_replace('\\','/',$relative_class).'.php';
if(file)existst($file)){
require($file);
}
})
参考资料
- php手册
- modern PHP 对应章节