0

好的,这是一个艰难的问题......我想,我觉得答案是否定的,但在这种情况下,我想要一些替代方案的答案。

我在一个可以动态创建类的框架中有一个非常复杂的 __autoload() 函数。为了动态创建一个名为 AuthActions 的类,需要三个类——这三个是:fRecordSet、RecordSet 和 AuthAction(注意那个没有 S)。

我的自动加载器将在它加载的任何类上寻找一个静态方法“init”并尝试运行它。在我的 ActiveRecord 类中,它尝试使用 AuthActions 来获取特定活动记录上支持的操作列表。AuthAction(没有 S)也在它的 init 中调用 AuthActions,所以基本上加载了 Active Record,并尝试加载 AuthActions,触发其他三个的加载,然后当它完成加载 AuthAction 时仍在原始自动加载器中 AuthAction 尝试调用AuthActions 触发另一个自动加载,因为原始的尚未完成。

这会导致以下内容有一些回声语句来澄清:

尝试加载 ActiveRecord
尝试加载 fActiveRecord
fActiveRecord 通过 /var/www/dotink.org/inkwelldemo/inc/lib/flourish
加载 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
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() 的调用一样,我认为我不会有问题(或者如果我这样做了,那将是它永远循环的问题,这将是一个单独的问题,以确定为什么类没有被加载来解决依赖关系)。

简而言之,我需要一种方法来递归循环基于 PHP 触发的自动加载的自动加载器......这根本不可能吗?这可能是我的特定版本中的错误吗?在我的测试中,它似乎影响了 5.2.6 - 5.3.2,所以我无法想象这是一个整体的错误。

更新:

AuthAction 上的 init method() 代码如下:

        /**
     * 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() 的建议都受到赞赏和欢迎。

4

2 回答 2

1

我认为这

我的自动加载器将在它加载的任何类上寻找一个静态方法“init”并尝试运行它。

是你问题的关键。您的自动加载器不应该运行任何东西,它应该包含(或以其他方式定义)类而不是其他任何东西。

当一个类被定义时(即在你的静态“init”方法中),你试图运行什么样的代码?

于 2010-07-16T01:29:47.487 回答
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不是吗?

除非我从你的问题中遗漏了一些东西......

于 2010-07-16T01:16:09.997 回答