欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于php规范psr4与psr0命名空间的理解

程序员文章站 2022-07-13 23:33:32
...

这几天在看php自动加载相关知识,这里记录一下。

use 命名空间只是防止命名空间的冲突,使用时仍需引入,这一步由自动加载来做。

与psr0不同,psr4不再转换 '_' 为文件分隔符,且 psr4有前缀gainia

以tp5的自动加载为例 Loader.php -> autoload() -> findFile()

/**
     * 查找文件
     * @param $class
     * @return bool
     */
    private static function findFile($class)
    {
        //以$class == 'think\Route' 为例
        if (!empty(self::$map[$class])) {
            // 类库映射
            return self::$map[$class];
        }

        // 查找 PSR-4
        $logicalPathPsr4 = strtr($class, '\\', DS) . EXT;//替换文件分隔符和后缀名

        $first = $class[0];// $first = 't'
        if (isset(self::$prefixLengthsPsr4[$first])) {//$prefixLengthsPsr4 为二维数组,第一维以class首字母区分,第二维以t*前缀区分
            foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) {//遍历t*前缀
                if (0 === strpos($class, $prefix)) {//找到存在于$class的前缀
                    foreach (self::$prefixDirsPsr4[$prefix] as $dir) {//遍历该前缀下的所有文件夹
                        if (is_file($file = $dir . DS . substr($logicalPathPsr4, $length))) {//可以看到剔除掉前缀
                            return $file;
                        }
                    }
                }
            }
        }

        // 查找 PSR-4 fallback dirs
        foreach (self::$fallbackDirsPsr4 as $dir) {
            if (is_file($file = $dir . DS . $logicalPathPsr4)) {
                return $file;
            }
        }

        // 查找 PSR-0
        if (false !== $pos = strrpos($class, '\\')) {//包含/分隔符
            // namespaced class name
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
            . strtr(substr($logicalPathPsr4, $pos + 1), '_', DS);//这里为什么不拼接后缀名???
        } else {//仅包含类文件名
            // PEAR-like class name
            $logicalPathPsr0 = strtr($class, '_', DS) . EXT;//与psr4不同的是,psr0会把类名中的下划线替换成文件分隔符
        }

        if (isset(self::$prefixesPsr0[$first])) {
            foreach (self::$prefixesPsr0[$first] as $prefix => $dirs) {
                if (0 === strpos($class, $prefix)) {
                    foreach ($dirs as $dir) {
                        if (is_file($file = $dir . DS . $logicalPathPsr0)) {//不会剔除掉前缀
                            return $file;
                        }
                    }
                }
            }
        }

        // 查找 PSR-0 fallback dirs
        foreach (self::$fallbackDirsPsr0 as $dir) {
            if (is_file($file = $dir . DS . $logicalPathPsr0)) {
                return $file;
            }
        }

        return self::$map[$class] = false;
    }

可以看到psr0和psr4处理方式很类似,主要区别在于:

psr4 在拼接文件路径时会剔除掉前缀,而 psr0不会剔除。

psr0 会将类名中的 '_' 替换成 文件分隔符。


可以看个psr4例子:

关于php规范psr4与psr0命名空间的理解

以第一个为例, 传入findFile()的$class 为 \Acme\Log\Write\File_Writer , 执行$dir . DS . substr($logicalPathPsr4, $length) 时剔除掉前缀 Acme\Log\Writer , 此时 $dir 为 ./acme-log-writer/lig/ ,拼接结果为 ./acme-log-writer/lib/File_Writer.php

如果是psr0 , 不剔除前缀,且替换下划线为文件分隔符,执行 $dir . DS . $logicalPathPsr0 结果为 ./acme-log-writer/lib/File/Writer.php。

这些差异也导致 psr4的文件路径看起来比较简洁。

相关标签: php psr