【问题标题】:Composer: Troubleshooting autoloadingComposer:自动加载故障排除
【发布时间】:2018-01-14 08:45:28
【问题描述】:

我提交这个问题是因为我一直在搜索 Composer 中的自动加载故障排除主题,但似乎找不到任何简单的内容。我将几个类添加到库中,然后在项目中引用它们。该项目找不到类。以下是相关事实:

• 我已经在项目中使用该库有一段时间了。

• 我仔细检查了代码文件中库中类的命名空间声明:

namespace \Library\Package\Subpackage;
class Widget { ...

• 我仔细检查了为库和实例化命名的 use 语句:

use \Library\Package\Subpackage as Subpackage;
$e = new Subpackage\Widget();

• 出于笑容,我更改了别名:

use \Library\Package\Subpackage\Widget as Widget;
$e = new Widget();

• 为了获得更多笑容,我尝试了直接参考:

$e = new \Library\Package\Subpackage\Widget();

• 我还确保composer update 并确保文件确实存在于正确的路径中:

composer update
find . -name Widget.php
./vendor/organization/library/Package/Subpackage/Widget.php

• 作为健全性检查,我在同一个库中添加了对另一个项目的引用,但在不同的子包中。

$f = new \Library\Package2\Widget2(); // this works fine

• 作为最后的手段,我将引用单独放在一个 PHP 文件中并运行它。

require_once __DIR__.'/vendor/autoload.php';
$e = new \Library\Package\Subpackage\Widget();

• 对于致命一击,我编写了一个单元测试来检查库的vendor 文件夹中的每个文件:

class AutoloadTest extends \PHPUnit\Framework\TestCase
{
    public function classDataProvider()
    {
        $data = array();
        $path = realpath('organization/library/Package/');
        $directory_iterator = new \RecursiveDirectoryIterator($path);
        $iterator_iterator = new \RecursiveIteratorIterator($directory_iterator);
        foreach ($iterator_iterator as $iterator_result) {
            $real_path = $iterator_result->getRealPath();
            if (substr($real_path, -4, 4) != '.php') {
                continue;
            }
            $split = explode('organization/library/Package/', $real_path);
            $processed_path = substr($split[1], 0, -4);
            $class_fqname = sprintf('\Library\%s', str_replace("/", '\\', $processed_path));
            $data[]  = array($class_fqname);
        }

        return $data;
    }

    public function test($class_name)
    {
        $assertion = class_exists($class_name) || trait_exists($class_name) || interface_exists($class_name);
        $this->assertTrue($assertion, "$class_name is not recognized as a class, trait or interface.");
    }
}

我的问题是:

  1. 最有可能的罪魁祸首是什么?
  2. 我可以用 Composer 做什么来获取有关它正在尝试的路径的跟踪信息?有没有办法给 Composer 提供一条路径并让它告诉我它是否可以解决它?

【问题讨论】:

  • 等等,我很困惑。您“已经在项目中使用该库一段时间了”并且...它刚刚停止工作?此外,您应该澄清这些要点中哪些有效,哪些无效。
  • 我在一个库中添加了几个类,然后在已经使用该库的项目中引用了它们。我可以参考旧课程,但不能参考新课程。除了带有“这很好用”的注释之外,所有的要点都失败了。
  • 库使用的自动加载器是什么?
  • 我认为你的意思是来自图书馆的 composer.json 的声明? "autoload": { "classmap": ["Html/"] }
  • 嗯,你确定吗?这意味着它只是在 Html 文件夹中自动加载文件,你在任何地方都没有提到,所以看起来很奇怪。无论如何,根据您添加文件的方式,classmap autoloader 可能只需要使用composer dump-autoload 进行更新

标签: composer-php


【解决方案1】:

多余的反斜杠。

namespace \Library\Package\Subpackage;
          ^ oops!

删除这个反斜杠解决了这个问题。

最终,我编写的单元测试帮助我找到并解决了问题。所以对于我的问题的第二部分,我提供了我写的测试类。提供程序接收要扫描的路径和文件所属的名称空间对。它扫描给定的路径并找到该命名空间中的类。测试检查断言每个限定类名称对应于一个类、特征或接口。 (当然,需要一个自动加载器来加载类。)

abstract class AutoloadTestBase extends \PHPUnit\Framework\TestCase
{
    public function pathProvider()
    {
        $data = array();
        foreach ($this->directories() as $directory_specification) {
            list($path, $namespace) = $directory_specification;
            if (empty($path)) {
                continue;
            }

            $directory_iterator = new \RecursiveDirectoryIterator($path);
            $iterator_iterator = new \RecursiveIteratorIterator($directory_iterator);
            foreach ($iterator_iterator as $iterator_result) {
                $real_path = $iterator_result->getRealPath();

                $split1 = explode($path.'/', $real_path);
                if (count($split1) < 2) {
                    continue;
                }

                $success = preg_match('/^(.+)\.php$/', $split1[1], $split2);
                if (!$success || substr($split2[1], 0, 5) == 'Tests') {
                    continue;
                }
                $class_fqname = sprintf('%s\%s', $namespace, str_replace("/", '\\', $split2[1]));
                $data[] = array($class_fqname);
            }
        }
        return $data;
    }

    /**
     * @dataProvider pathProvider
     */
    public function test($class_name)
    {
        $assertion = class_exists($class_name) || trait_exists($class_name) || interface_exists($class_name);
        $this->assertTrue($assertion, "$class_name is not recognized as a class, trait or interface.");
    }
}

class AutoloadTest extends AutoloadTestBase
{
    protected function directories()
    {
      return array(
        array('Package1/Subpackage1','\Library1\Package1\Subpackage1'),
        array('vendor/organization2/package2/Subpackage2','\Library2\Package2\Subpackage2')
      );
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-07
    • 2013-11-20
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-15
    相关资源
    最近更新 更多