【问题标题】:Composer autoload not loading base class in parent folder作曲家自动加载未在父文件夹中加载基类
【发布时间】:2018-02-27 13:08:20
【问题描述】:

但是,composer 会在同一个文件夹中自动加载同一个基类。

我的错误: 致命错误:第 5 行的 C:\VendorName\www\src\ParentFolder\Enums\MyEnumeration.php 中找不到 Class 'VendorName\ParentFolder\Enums\BasicEnum。

我的枚举.php:

<?php
  namespace VendorName\ParentFolder\Enums;


  abstract class MyEnumeration extends BasicEnum {
      const ConstantOne = 1;
      const ConstantTwo = 2;
      const ConstantThree = 3;
}

和 BasicEnum.php:

<?php
namespace VendorName\ParentFolder;

abstract class BasicEnum {
    private static $constCacheArray = NULL;

    private function __construct() { }

    private static function getConstants() {
        if (self::$constCacheArray == NULL) {
            self::$constCacheArray = [];
        }
        $calledClass = get_called_class();
        if (!array_key_exists($calledClass, self::$constCacheArray)) {
            $reflect = new ReflectionClass($calledClass);
            self::$constCacheArray[$calledClass] = $reflect->getConstants();
        }
        return self::$constCacheArray[$calledClass];
    }

    public static function isValidName($name, $strict = false) {
        $constants = self::getConstants();

        if ($strict) {
            return array_key_exists($name, $constants);
        }

        $keys = array_map('strtolower', array_keys($constants));
        return in_array(strtolower($name), $keys);
    }

    public static function isValidValue($value, $strict = true) {
        $values = array_values(self::getConstants());
        return in_array($value, $values, $strict);
    }
}

我的文件夹结构:

+ VendorName
  + www
    + src
      + ParentFolder
        + Enums
              MyEnumeration.php
          BasicEnum2.php

而且,自动加载是通过以下方式构建的:

composer dump-autoload

使用 composer.json:

{
    "autoload": {
        "psr-4": { "VendorName\\": "src/"}

    }
}

我的 .php 页面:

<h1>Composer Autoload Test</h1>
<p>Trying to load a class where base class is in parent folder.
<p>(Using the PHP.net BasicEnum example).
<br/>
<?php
    require __DIR__ . '/vendor/autoload.php';

    use VendorName\ParentFolder;
    use VendorName\ParentFolder\Enums;



    echo '<br/><br/>';
    if (class_exists('MyEnumeration')) {
        echo 'MyEnumeration exists';
    }
    else {
        echo 'MyEnumeration does NOT exist';   // This line prints out in browser.
    }
    echo '<br/><br/>';

    echo '<br/><br/>';
    if (class_exists('VendorName\ParentFolder\Enums\MyEnumeration')) {  // This line blows up because BaseEnum is not found in MyEnumeration.php.
        echo 'VendorName\ParentFolder\Enums\MyEnumeration exists';
    }
    else {
        echo 'VendorName\ParentFolder\Enums\MyEnumeration does NOT exist';
    }
    echo '<br/><br/>';


    echo '<br/><br/>';
    if (defined('VendorName\ParentFolder\Enums\MyEnumeration::ConstantOne')) {
        echo 'VendorName\ParentFolder\Enums\MyEnumeration::ConstantOne exists';
    }
    else {
        echo 'VendorName\ParentFolder\Enums\MyEnumeration::ConstantOne does NOT exist';
    }
    echo '<br/><br/>';  


    echo 'NotExist:' . (MyEnumeration::isValidName('NotExist') ? 'true' : 'false') . '<br/>';
    echo 'ConstantOne:' . (MyEnumeration::isValidName('ConstantOne') ? 'true' : 'false') . '<br/>';
    echo 'ConstantTwo:' . (MyEnumeration::isValidName('ConstantTwo') ? 'true' : 'false') . '<br/>';
    echo 'ConstantThree:' . (MyEnumeration::isValidName('ConstantThree') ? 'true' : 'false') . '<br/>';

?>

最后,我必须使用命名空间完全限定 MyEnumeration,否则即使我有一个“use”语句并使用 composer autoload,它也找不到。

【问题讨论】:

  • 你的文件夹结构让我有点不知所措。你的composer.json 在哪个目录?
  • (另外,“BasicEnum2.php”只是一个错字吗?)
  • composer.json 与“src”文件夹位于同一文件夹中。
  • 是的,BasicEnum2.php 是一个错字。

标签: php composer-php autoload


【解决方案1】:

您的 MyEnumeration 类位于命名空间 VendorName\ParentFolder\Enums 中。因此它无法在上面的命名空间\VendorName\ParentFolder 中找到BasicEnum 作为符号。您可以在子类中绝对指定它:

abstract class MyEnumeration extends \VendorName\ParentFolder\BasicEnum {

您还需要在 BasicEnum 中为 ReflectionClass 指明全局命名空间:

$reflect = new \ReflectionClass($calledClass);

还请注意,您 can't just import everything from a namespace 使用 use。您需要use 特定课程。例如,在您的 php 页面中,指定:

use VendorName\ParentFolder\Enums\MyEnumeration;

...允许在没有限定符的情况下使用MyEnumeration

【讨论】:

  • 啊,NOW 'use' 语句文档在最后一个标记是别名的地方是有意义的。它 - 是 - 类名。我在想最后一个子命名空间。这一定与为什么 class_exists 需要完全限定的类名有关?如果是这样,我错过了自动加载器的意义。我以为它说它会在 src 下的任何地方加载一个没有完全限定名的类名。
  • > $reflect = new \ReflectionClass($callClass); - 不知道这是哪里。 BasicEnum 来自 PHP.Net 文档。
  • BasicEnum 类中有一行代码使用ReflectionClass 没有范围限定符,即$reflect = new ReflectionClass($calledClass);(注意缺少反斜杠。)我猜你的代码从 php.net 获得的还没有在命名空间中?由于您现在已将该代码放入命名空间中,因此您需要反斜杠来“返回”全局范围并找到 ReflectionClass 类。否则它将尝试查找不存在的 \VendorName\ParentFolder\ReflectionClass。
  • 我在这里得到了 BasicEnum 代码:​​secure.php.net/manual/en/class.splenum.php
  • 这确实修复了我发布的错误。我认为 SO 是每个帖子的单个中断/修复,对吗?希望不要碰运气问为什么 isValidName 的最后四行找不到 MyEnumeration (Class 'MyEnumeration' was not found ...):
【解决方案2】:

看起来你有
文件src\ParentFolder\Enums\BasicEnum2.php
BasicEnum在命名空间VendorName\ParentFolder

但你必须有文件src\ParentFolder\Enums\BasicEnum.php(没有2)
在你的MyEnumeration.php 脚本中你必须有这个使用块:

use VendorName\ParentFolder\BasicEnum;

【讨论】:

  • 这是一个typeO,它是BasicEnum.php。即类名 = 文件名,同样大小写(根据 PSR-4,我是新手)。
  • MyEnumeration.php 中有 use VendorName\ParentFolder\BasicEnum; 吗?
  • 我没有,但马特·吉布森首先回复了我。 :-( 'use' 中的最后一个标记是类名,而不是类的子命名空间。必须再次重新阅读命名空间文档(并且,让我清楚它在其他语言中的工作方式;-) 似乎 'use' 应该是该命名空间中任何类的简写。现在,我对每个自动加载感到困惑,说任何类都已加载。如果我必须“使用”每个类有什么意义?
  • @PHPDev75 命名空间和自动加载器只是按照惯例在这里真正相关。自动加载器使您不必在 PHP 中手动 include 文件(并使代码更容易在 Composer 等系统中重用)。命名空间用于分隔代码,以便如果 编写BasicEnum 类,它不会与其他人的BasicEnum 类发生冲突,因为您将每个人都将它们放在您的特定命名空间中。 PSR-4 中自动加载与命名空间的关系实际上只是一个聪明的 hack,可以轻松编写一个可以快速找到任意类的自动加载器类。
  • @MattGibson 那么,如果我在 MyNamespace1 中有 110 个青少年班级,我必须“使用”所有 11 个青少年吗?我想,我可以编写自己的自动加载器来为我做这件事,但我想肯定有人已经做到了,因为这就是它在其他语言中的工作方式——包括命名空间,该命名空间中的每个类都是可解析的。
猜你喜欢
  • 2013-02-02
  • 2018-03-30
  • 2019-02-15
  • 2014-08-15
  • 2021-12-18
  • 2013-12-09
  • 2017-01-14
  • 2016-08-13
相关资源
最近更新 更多