作曲家PSR-4自动加载工具的实现与PSR-4文档中的示例有什么区别?

时间:2018-09-06 10:26:21

标签: composer-php psr-4

这是作曲家PSR-4自动加载的实现:

localhost:xxxx/something

这是PSR-4文档中的示例:

private function findFileWithExtension($class, $ext)
{
    // PSR-4 lookup
    $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

    $first = $class[0];

    if (isset($this->prefixLengthsPsr4[$first])) {
        $subPath = $class;
        while (false !== $lastPos = strrpos($subPath, '\\')) {
            $subPath = substr($subPath, 0, $lastPos);
            $search = $subPath . '\\';
            if (isset($this->prefixDirsPsr4[$search])) {
                $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                foreach ($this->prefixDirsPsr4[$search] as $dir) {
                    if (file_exists($file = $dir . $pathEnd)) {
                        return $file;
                    }
                }
            }
        }
    }

您会发现Composer的实现还有一个额外的判断,即:

protected function loadMappedFile($prefix, $relative_class)
{
    // are there any base directories for this namespace prefix?
    if (isset($this->prefixes[$prefix]) === false) {
        return false;
    }

    // look through base directories for this namespace prefix
    foreach ($this->prefixes[$prefix] as $base_dir) {

        // replace the namespace prefix with the base directory,
        // replace namespace separators with directory separators
        // in the relative class name, append with .php
        $file = $base_dir
              . str_replace('\\', '/', $relative_class)
              . '.php';

        // if the mapped file exists, require it
        if ($this->requireFile($file)) {
            // yes, we're done
            return $file;
        }
    }

    // never found it
    return false;
}

我不明白为什么要加上这个判断。有人可以告诉我吗?

1 个答案:

答案 0 :(得分:0)

首先,这两个函数是脱离上下文使用的,它们的作用截然不同-即使您比较函数参数,也可以看到它们彼此不对应,因此比较它们没有多大意义。

但是Composer实现中的这一附加条件确保了更精确的名称空间优先于更通用的定义。因为通常程序包通常共享相同的根名称空间。例如,在Yii 2 Framework中:

    具有核心框架的
  • yii2软件包使用yii作为所有类的根名称空间,并且源代码位于vendor/yiisoft/yii2中。
  • yii2-redis扩展名使用yii\redis命名空间,源代码位于vendor/yiisoft/yii2-redis中。

在这种情况下,如果要使用yii\redis\Connection类定义来解析文件,则有两种选择:

  1. vendor/yiisoft/yii2/redis/Connection
  2. vendor/yiisoft/yii2-redis/Connection

第二个是正确的。并且由于Composer实施中的这一附加条件,它将被用作首选,因为yii\redis名称空间的定义比yii名称空间的定义更为精确。这样,您可以提高自动加载器的性能(但是,如果使用优化的自动加载器则无关紧要),使其更具可预测性,并允许您覆盖某些类(对于新实现,您只需要为文件使用更精确的名称空间)即可。