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
语句。)
当我在 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
语句。)