在 PHP 中使用命名空间和自动加载从变量创建对象

2022-08-30 22:26:07

之后用我自己的评论编辑

我认为问题在于,当PHP解析文件以“编译”时,首先它将类名转换为其完全限定名。因此,索引将转换为控制器\主页\索引。之后,是PHP将变量转换为其值的时间。因此,如果我使用变量作为类名,它不会限定其名称,因为该步骤已经发生。这就是为什么没有找到类。这只是一个猜测,但很可能是这样 Blockquote

结束编辑

我使用来自Symfony2项目的UniversalClassLoader来自动加载我的类,但是我发现了一些我无法解决的奇怪错误。

自动加载的东西工作正常,但后来我遇到了这个问题:

$controller      = new Index(); // It works!

$controller_name = "Controller\\Home\\Index";
$controller2     = new $controller_name(); // It works!

$controller_name = "Index";
$controller3     = new $controller_name(); // Fatal error: Class 'Index' not found

前两种情况工作正常。在第一个中,由于我在脚本的开头使用了“use Controller\Home;”,所以我可以毫无问题地使用“new Index();”。但是,如果我不写“Index”,而是使用像$var = “Index”这样的字符串变量,它就不起作用。我不明白为什么。我需要这个脚本是动态的,这就是为什么我需要一个变量。

谢谢!


其他长尾搜索:

  • 来自变量的 php 完全限定名
  • php 从变量中的别名实例化类


答案 1

有趣的问题。从它的外观来看,没有办法绕过它。php文档似乎明确声明了这一点:

必须使用完全限定名(带命名空间前缀的类名)。

在这种情况下,可能的解决方法是在配置中为控制器定义一个基本命名空间,并按控制器的相对命名空间注册控制器。

假设基本命名空间是,我们将控制器保存在数组中(为了简洁起见):MyApp\Controller\

$controllers = array(
    'foo/bar' => 'MyFooController',
    'baz'     => 'Foo\\MyBarController'
);

// One way how the controllers could be instantiated:

// returns 'MyApp\\Controller\\'
$namespace = $cfg->get('namespaces.controller');

$controller = $namespace.$controllers['baz'];
$controller = new $controller();

答案 2

名称间距意味着 PHP 不仅能够找到具有给定路径的文件(几乎与require_once相同),而且类名实际上也与 name-space 指令匹配。唯一的差异?下划线的斜杠(下面的示例 #2)。

// This may be working because Symfony's autoloader has found a class named Index
$controller      = new Index(); 

// A name-space call so PHP knows where to actually find the file
// Chances are the class name here is Controller_Home_Index
$controller_name = "Controller\\Home\\Index";
$controller2     = new $controller_name();

// Symfony's autloader should have picked this up, but didn't
// It's possible that with this construct Symfony cannot find the class and b/c
// it's not namespaced, PHP has no choice but to fail
$controller_name = "Index";
$controller3     = new $controller_name();

检查你的Symfony项目缓存目录,有一些PHP数组的平面文件也可能帮助你。


推荐