PHP命名空间与PSR-4自动加载

1,014 阅读1分钟

目录

  • 命名空间
    • 概念?解决了什么问题?
    • 定义
    • 使用和解析规则
    • 其他
  • 自动加载
    • 概念?解决了什么问题?
    • 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);
    }
})

参考资料


  1. php手册
  2. modern PHP 对应章节