php psr4自动加载程序无法从类中自动加载

fbcarpbf  于 2023-02-03  发布在  PHP
关注(0)|答案(2)|浏览(194)

当我在index.php中使用autoloader时,它可以正常工作,但是当我在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;
            }
        }
    }

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

e0bqpujr

e0bqpujr1#

区别不在于代码在哪里运行;不同之处在于,失败的代码试图选择要“动态”加载的类。
在PHP中,名称空间本质上是一个编译时功能:在运行任何代码之前,编译器会查看所有不以\开头的类名引用,并将当前命名空间作为前缀,或者根据您在use语句中指定的规则。当代码运行时,当前命名空间和use语句根本不可见。
当动态指定类名时,编译器只看到字符串,而不是类名,所以不去管它。然后当代码运行时,查找的类名被假定为完全指定的,而不是相对于当前命名空间或use语句。
因此解决方案很简单--在创建动态类名时指定完整的命名空间:

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

你也可以使用magic constant __NAMESPACE__让编译器替你替换 current 命名空间名称(显然,这仍然不能解释任何use语句):

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

或者,如果要在一组特定的类之间进行选择,则可以使用::class语法在编译时基于当前命名空间和任何有效的use语句生成字符串:

$mapTypeToClassName = [
   'Radio' => FormElementRadio::class, // expands to 'Elements\FormElementRadio'
   'Select' => FormElementSelect::class,
   // etc
];
$class = $mapTypeToClassName[$type];
ffdz8vbo

ffdz8vbo2#

这可能是因为src目录有多个名称空间。
通常您只需为src创建一个名称空间,如下所示

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

然后使用PizzaCase\Elements和PizzaCase\Connections作为名称空间

相关问题