psr 4 自动加载不会从 class 中自动加载

psr4 autoloader does not autoload from within a class

当我在 index.php 中使用它时自动加载器工作,但是当我在 index.php 中创建一个对象并且这个对象必须创建其他对象(它们都在同一个命名空间中)时,它抛出错误 Uncaught Error: Class 'xxx' not found in (...).

我的 composer.json 看起来像这样:

{
    "autoload": {
        "psr-4": {
            "pizzaCase\": "src",
            "Connection\": "src/Connection/",
            "Elements\": "src/Elements/"
        }
    },
    "require": {
        "cboden/ratchet": "^0.4"
    }
}

我的 index.php 看起来像这样:

<?php
    require_once __DIR__. '/vendor/autoload.php';
    require_once __DIR__."/src/config.php";

    use Connection\Database;
    use Elements\Form;
    use Elements\FormElement;
    use Elements\FormElementRadio;
    
    // Database::init();
    $form = new Form();

    $data["options"] = "soemthing, something else";
    $form->addElement("", "pizza", "", "Choose pizza", "radio", $data);
?>

然后我在 addElement 方法中创建了一个也在 src/Elements/ 命名空间内的对象,但它抛出了上述错误。

我的 addElement 方法的主体如下所示:

<?php
namespace Elements;

    class Form
    {
        public static $leftSize = 3;
        protected $elements = [];
    
        public function addElement($table, $name, $value, $label=false, $type = false, $data = false) 
        {
            $type = ucfirst($type);
            $class = "FormElement{$type}";
    
            //FAILS HERE
            if(class_exists($class))
            {
                //CLASS EXISTS, CREATE OBJECT FROM RESPECTIVE CLASS
                $form = new $class($table, $name, $value, $label, $type, $data);
    
                $this->elements[$name] = $form;
            }
        }
    }

我做错了什么(或遗漏了什么)?为什么自动加载器 可以 从 index.php 自动加载它,但是我创建的对象不能在自动加载器失败的情况下创建其他对象?

可能是因为您的 src 目录有多个命名空间。

通常你会像这样为 src 创建一个命名空间

“psr-4": {
    "PizzaCase\": "src"
}

然后只需使用 PizzaCase\Elements 和 PizzaCase\Connections 作为命名空间

区别不在于代码的位置运行;不同之处在于,失败的代码试图选择class动态加载

在 PHP 中,命名空间本质上是一个 compile-time 特性:在您的任何代码 运行 之前,编译器会查看所有对 class 名称的引用't 以 \ 开头,并在它们前面加上当前命名空间,或者根据您用 use 语句指定的规则。当代码 运行s、当前命名空间和 use 语句根本不可见时。

当您动态指定一个 class 名称时,编译器只会看到一个字符串,而不是 class 名称,因此不用管它。然后当代码 运行s 时,查找的 class 名称被假定为完全指定,而不是相对于当前名称空间或 use 语句。

所以解决方法很简单:在创建动态class名称时指定完整的命名空间:

$class = "Elements\FormElement{$type}";

您还可以使用 magic constant __NAMESPACE__ 让编译器为您替换当前命名空间名称:

$class = __NAMESPACE__ . "\FormElement{$type}";

(不过,这显然不会解释任何 use 语句。)