PSR-0与PSR-4

PHP自动加载的背景

  在开发过程中,我们如果想引入外部的class,通常都会使用require或者include方法,其实这个在小规模的开发中没多大问题,但是万一开发规模大了起来,那样子就会有很多require/include语句,这样子非常不优雅,同时如果遗漏引入,或者重复引入,那也是一个麻烦事,require_once的代价很大,暂且不提。

PHP自动加载函数

程序员应该是懒惰的,我们不愿意这么做,所以有了更伟大的实践-自动加载,什么是自动加载,粗俗说,我需要你,我再引入你,而不是一开始就require/include进来,那怎么实现自动加载呢?就是用__autoload这个函数啦,下面是一个例子:

function __autoload($classname) {
    $filename = "./". $classname .".php";
    include_once($filename);
}

也就是当我们尝试去使用一个不存在此文件中的class时,就会调用这个函数,拼接filename并且用include_once引入进来,是不是觉得很舒服,解放我们双手,---但是官网文档已经明确说明这个特性在PHP7.2之后被弃用并且不鼓励使用了,为什么要弃用呢?--原因在这儿:

__autoload是全局函数所以只能定义一次?所以这个理由和上面弃用有什么相关联呢?

先再看看我们上面给的加载例子,再拼接文件名那块,对的,问题之一,我们在实际开发时候,类名和实际磁盘文件映射规则可能不相同,那我们是不是要再一个__autoload函数里面写完所有的映射规则,这样子映射规则多了,可能你的一个__autoload函数就十分庞大不美观了


弃用它代表更优秀的会顶替它,没错,就是SPL Autoload了,SPL全称Standard PHP Lobrary,是PHP5引入的一个扩展库,在这里我们就说spl_autoload_register这个注册函数吧,它接手了__autoload函数的工作并且完成的更加出色。详细文档还是建议参考官方文档,请戳这里,主要职责就是将自己写的自动加载函数注册到SPL __autoload函数队列中,当我们找不到class时候就会去调用这个队列,一个一个调用自动加载函数直到找到class为止

function my_autoloader($class) {
    include 'classes/' . $class . '.class.php';
}

spl_autoload_register('my_autoloader');

接下来要进入我们的正题了,在这里我假设你是明白PHP的命名空间了,如果不清楚还是请戳官方文档

PSRs规范

大家应该了解PSRs的规范吧,这里简单说一下,这伟大的PSR规范是PHP-FIG组织撰写的,FIG 是 Framework Interoperability Group(框架可互用性小组)的缩写,由几位开源框架的开发者成立于 2009 年,虽然不是 “官方” 组织,但也代表了PHP社区中一个类似官方的力量。FIG的官方网址请戳这里,他为千千万万的PHP开发者规范了编码规范和这里要说的自动加载规范,等,大大降低我们因为代码风格不同而焦头烂额风险!


PSR-0

SR0目前已经被PSR4替代,它被标记为弃用,这两个都是关于自动加载的标准
PSR0强制性要求以下几点:
1、一个完全限定类名的namespace和class必须符合这样的结构:“\<Vendor Name>\(<Namespace>\)*<Class Name>”;
2、每个命名空间必须有一个顶层的命名空间;
3、每个命名空间可以有多个子命名空间;
4、当从文件系统中加载时,每个namespace的分隔符要转换成操作系统路径分隔符;
5、在类名中,每个下划线(_)符号要转换成操作系统路径分隔符,在namespace中,下划线(_)符号是没有(特殊)意义的。
6、当从文件系统中载入时,合格的namespace和class一定是以 .php 结尾的

7、verdor name,namespaces,class名可以由大小写字母组合而成(大小写敏感的)

看不懂吗?咱们以laravel源码举例子

假设有\Symfony\Core\Request命名空间
规定为什么需要有顶级命名空间可以查看composer的自动加载源码,说明白其实是PSR0标准只负责顶级命名空间之后的映射关系,而顶层命名空间/Symfony应该关联到哪个目录,那就是用户或者框架自己定义的了;

又假设我们的命名空间是\Symfony\Core\Request_A,就会映射到我们就应该把它映射到\Symfony\Core\Request\a这样的目录,这是为了兼容PHP5之前没有命名空间的情况

  public static $prefixesPsr0 = array (
        'P' => 
        array (
            'Prophecy\\' => 
            array (
                0 => __DIR__ . '/..' . '/phpspec/prophecy/src',
            ),
            'Parsedown' => 
            array (
                0 => __DIR__ . '/..' . '/erusev/parsedown',
            ),
        ),
)

以上是composer自动加载PSR-0的一小片段代码,

i、我们假设有一个命名空间"\parsedown\a\b"他先截取命名空间第一个字母去遍历比较给出的数组,

ii、找到以p开头的两个顶层命名空间与\parsedown\a\b得到parsedown这个顶层命名空间,

iii、于是在映射数组得出映射目录

__DIR__ . '/..' . '/erusev/parsedown',

iv、查看

__DIR__ . '/..' . '/erusev/parsedown/parsedown/a/b.php是否存在
 
 

以上便是composer兼容PSR-0的规范大概,具体可以查看源码


PSR-4

PSR4的规范

1、术语「类」是一个泛称;它包含类,接口,traits 以及其他类似的结构;

2、完全限定类名应该类似如下范例:
\<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>
i、完全限定类名必须有一个顶级命名空间(Vendor Name);
ii、完全限定类名可以有多个子命名空间;
iii、完全限定类名应该有一个终止类名;
iv、下划线在完全限定类名中是没有特殊含义的;
v、字母在完全限定类名中可以是任何大小写的组合;
vi、所有类名必须以大小写敏感的方式引用;

3、当从完全限定类名载入文件时:
i、在完全限定类名中,连续的一个或几个子命名空间构成的命名空间前缀(不包括顶级命名空间的分隔符),至少对应着至少一个基础目录。
ii、在「命名空间前缀」后的连续子命名空间名称对应一个「基础目录」下的子目录,其中的命名 空间分隔符表示目录分隔符。子目录名称必须和子命名空间名大小写匹配;
iii、终止类名对应一个以 .php 结尾的文件。文件名必须和终止类名大小写匹配;

4、自动载入器的实现不可抛出任何异常,不可引发任何等级的错误;也不应返回值;

先说一下他和PSR-0的区别,这里离可以看出在类名的_是没有任何其他意义,同时PSR-4的规范比较干净,目录不会那么深,这里比较难以理解,我们可以看以下composer自动加载PSR-4的片段代码

 public static $prefixLengthsPsr4 = array (
        'p' => 
        array (
            'phpDocumentor\\Reflection\\' => 25,
        ),
);

public static $prefixDirsPsr4 = array (
        'phpDocumentor\\Reflection\\' => 
        array (
            0 => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src',
            1 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src',
            2 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src',
        ),
);

PSR-4比PSR-0多了一个数组,一开始是一样的:

i、我们假设有一个命名空间"\phpDocumentor\Reflection\b"他先截取命名空间第一个字母去遍历比较给出的数组,

ii、找到以p开头的顶层命名空间\phpDocumentor\Reflection\,

iii、返回的数字25代表的是这个顶层命名空间长度为25,

iv、接着再去遍历第二个数组得到三个目录映射

v、一一对比,这里的25派上用场了,比如__DIR__  /../phpDocumentor/reflection-common/src/  +  substr('phpDocumentor/Reflection/b.php',25)


说到这里大致意思都清楚了,如果哪位仁兄对以上有不同看法,恳切指出,共同进步!^_^

猜你喜欢

转载自blog.csdn.net/m0_37752084/article/details/79597846