我在框架中有一个非常复杂的__autoload()函数,可以动态创建类。为了动态创建一个名为AuthActions的类,需要三个类 - 这三个是:fRecordSet,RecordSet和AuthAction(注意那个上没有S)。
我的自动加载器会在它加载的任何类上查找静态方法“init”并尝试运行它。在我的ActiveRecord类中,它尝试使用AuthActions来获取特定活动记录上支持的操作列表。 AuthAction(no S)也在它的init中调用AuthActions,所以基本上加载了Active Record,并尝试加载AuthActions,触发加载其他三个,然后当它完成加载AuthAction仍然在原始自动加载器中时AuthAction尝试调用AuthActions会触发另一次自动加载,因为原始版本尚未完成。
这导致以下有一些echo语句澄清:
尝试加载ActiveRecord
加载AuthAction
试图加载fActiveRecord
通过/var/www/dotink.org/inkwelldemo/inc/lib/flourish加载fActiveRecord ActiveRecord通过/var/www/dotink.org/inkwelldemo/inc/lib加载 试图加载AuthActions
试图加载RecordSet
试图加载fRecordSet
fRecordSet通过/var/www/dotink.org/inkwelldemo/inc/lib/flourish加载 RecordSet通过/var/www/dotink.org/inkwelldemo/inc/lib加载 试图加载AuthAction
通过/var/www/dotink.org/inkwelldemo/models致命错误:第24行的/var/www/dotink.org/inkwelldemo/models/AuthAction.php中找不到“AuthActions”类
这里的问题是随后对__autoload('AuthActions')的调用会成功,因为它需要的三个类现在已经到位了......但它似乎只是因为它已经尝试自动加载'AuthActions ' - 这似乎是硬编入PHP。
在测试中,我发现以下内容将永远循环,没有错误:
function __autoload($class) {
__autoload($class);
}
$foo = new Bar();
虽然下面这个会同样出错:
function __autoload($class) {
$test = new Bar();
}
$foo = new Bar();
这种行为似乎不一致,因为基本上它们应该相同(有点)。如果PHP内部触发自动加载就像用户调用__autoload()一样,我认为我不会有问题(或者如果我做了那么它将是一个问题,它永远循环,这将是一个单独的问题,确定为什么class没有加载来解决依赖关系)。
简而言之,我需要一种基于PHP触发自动加载的递归循环自动加载器的方法......这根本不可能吗?这可能是我特定版本中的错误吗?它似乎在我的测试中影响了5.2.6 - 5.3.2,所以我无法想象这是一个整体的错误。
更新
AuthAction上init方法()的代码如下:
/**
* Initializes the AuthAction model
*
* @param array $config The configuration array
* @return void
*/
static public function init($config) {
// Establish permission definitions and supported actions
$every_permission = 0;
$supported_actions = array();
foreach (AuthActions::build() as $auth_action) {
$action_name = $auth_action->getName();
$action_value = intval($auth_action->getBitValue());
$every_permission = $every_permission | $action_value;
$supported_actions[] = $action_name;
define(self::makeDefinition($action_name), $action_value);
}
define('PERM_ALL', $every_permission);
}
你可以看到它将AuthActions作为一个单独的类调用的地方,并且请注意,这只是因为它是在原始尝试加载它失败时加载的。我显然可以删除这些代码并且它可以工作 - AuthActions的原始加载将成功完成,然后加载所有先决条件类。
也就是说,init()是这个代码最合适的地方,即使我无法使用尚未在init()中加载的相互依赖的类,我仍然希望保留该功能。任何实现该功能的替代方法都会很棒...理想情况下,PHP会有这样的事件,例如,当你说“自动加载”事件被触发时,你可以注册一个回调。这将允许代码在原始自动加载之后运行,并将解决这个看似毫无意义的限制。
现在有了这个说法,任何建议如何在每次加载时自动调用类上的init()都会受到赞赏和欢迎。
答案 0 :(得分:1)
__ autoload方法仅在您尝试使用尚未定义的类/接口时被调用。
因此,您的示例
function __autoload($class) {
$test = new Bar();
}
$foo = new Bar();
您正在尝试加载未被要求的类bar
/ requiered_once因此未定义类,因此它将__autoload方法作为最后的手段调用,然后在自动加载中再次尝试加载该类尚未定义的类。
使用__autoload的正确方法如php站点所示。
<?php
function __autoload($class_name) {
require_once $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
?>
你的所有初始化内容都可以放入__constructor
不能吗?
除非我遗漏了你的问题......
答案 1 :(得分:1)
我想这个
我的自动加载器会寻找静态 在它加载的任何类上的方法“init” 并尝试运行它。
是您问题的关键。你的自动加载器不应该运行任何东西,它应该包括(或以其他方式定义)类而不是别的。
当一个类定义(即在你的静态“init”方法中)时,你试图运行什么样的代码?