PHP __autoload()可以来自同一个类的另一个__autoload()中的一个类吗?

时间:2010-07-16 00:59:41

标签: php dynamic autoload

好吧,这是一个艰难的...我想,我觉得答案根本就是没有,但在这种情况下,我想要一些替代方案的答案。

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

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

这导致以下有一些echo语句澄清:

  

尝试加载ActiveRecord
  试图加载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

加载AuthAction      

致命错误:第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()都会受到赞赏和欢迎。

2 个答案:

答案 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”方法中)时,你试图运行什么样的代码?