0

わかりました、これは難しい問題です... 答えは単純にノーだと思いますが、その場合、代替案についていくつかの答えが欲しいです.

クラスを動的に作成できるフレームワークに非常に複雑な __autoload() 関数があります。AuthActions と呼ばれるクラスを動的に作成するには、fRecordSet、RecordSet、および AuthAction の 3 つのクラスが必要です (このクラスには S がないことに注意してください)。

私のオートローダーは、ロードしたクラスで静的メソッド「init」を探し、それを実行しようとします。私の ActiveRecord クラスでは、特定のアクティブ レコードでサポートされているアクションのリストを取得するために、AuthActions を使用しようとします。AuthAction (S なし) もその init 内で AuthActions を呼び出すため、基本的にアクティブ レコードが読み込まれ、AuthActions の読み込みを試み、他の 3 つの読み込みをトリガーします。その後、AuthAction の読み込みが終了すると、元のオートローダー内で AuthAction が呼び出しを試みます。元のオートロードがまだ完了していないため、別のオートロードをトリガーする AuthActions。

これにより、明確にするためにいくつかのエコーステートメントを含む以下が発生します。

ActiveRecord をロード
しようとしています fActiveRecord をロードしようとしています /var/www/dotink.org/inkwelldemo/inc/lib/flourish 経由でロードされた fActiveRecord
/var/www/dotink.org/inkwelldemo/inc/lib 経由でロードされた
ActiveRecordをロード
しようとしています AuthActions をロード
しようとしていますload RecordSet fRecordSetの読み込みを
試みています /var/www/dotink.org/inkwelldemo/inc/lib/flourish RecordSetを /var/www/dotink.org/inkwelldemo/inc/lib 経由
で 読み込みましたvar/www/dotink.org/inkwelldemo/models


致命的なエラー: 24 行目の /var/www/dotink.org/inkwelldemo/models/AuthAction.php にクラス 'AuthActions' が見つかりません

ここでの問題は、 __autoload('AuthActions') への後続の呼び出しが成功することです。これは、必要な 3 つのクラスが配置されているためです...しかし、既に 'AuthActions' を自動ロードしようとしているという前提だけで死ぬようです --これは PHP にハードライトされているようです。

これをテストしたところ、以下がエラーなしで永久にループすることがわかりました。

function __autoload($class) {
  __autoload($class);
}

$foo = new Bar();

以下は同様にエラーになりますが:

function __autoload($class) {
  $test = new Bar();
}

$foo = new Bar();

この動作は、本質的に同じことになるはずなので、一貫性がないようです(ちょっと)。PHP が内部的にトリガーした autoload が __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();

required/requiered_once されていないクラスをロードしようとしてbarいるため、クラスが定義されていないため、最後の手段として __autoload メソッドを呼び出し、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 に答える