簡體   English   中英

PHP __autoload()是否可以從同一類的另一個__autoload()中獲得一個類?

[英]Can PHP __autoload() a class from within another __autoload() of the same class?

好的,這是一個艱巨的任務...我想,我感覺答案是肯定的,但在那種情況下,我希望找到一些替代方法的答案。

我在一個可以動態創建類的框架中有一個非常復雜的__autoload()函數。 為了動態創建稱為AuthActions的類,需要三個類-這三個類是:fRecordSet,RecordSet和AuthAction(請注意,該類上沒有S)。

我的自動加載器會在加載的任何類上尋找靜態方法“ init”,然后嘗試運行該方法。 在我的ActiveRecord類上,它嘗試使用AuthActions以獲得特定活動記錄上受支持的操作的列表。 AuthAction(無S)也在其init中調用AuthAction,因此基本上會加載Active Record,並嘗試加載AuthAction,觸發其他三個加載,然后在完成加載后仍將AuthAction保留在原始自動加載器中AuthAction嘗試調用AuthActions會觸發另一個自動加載,因為原始自動加載尚未完成。

這將導致以下內容,其中包含一些echo語句以供澄清:

嘗試加載ActiveRecord
嘗試加載fActiveRecord
通過/var/www/dotink.org/inkwelldemo/inc/lib/flourish加載的fActiveRecord
ActiveRecord通過/var/www/dotink.org/inkwelldemo/inc/lib加載
嘗試加載AuthAction
嘗試加載RecordSet
嘗試加載fRecordSet
通過/var/www/dotink.org/inkwelldemo/inc/lib/flourish加載的fRecordSet
通過/var/www/dotink.org/inkwelldemo/inc/lib加載的RecordSet
嘗試加載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()的建議都將受到歡迎。

僅當嘗試使用尚未定義的類/接口時,才調用__autoload方法。

因此,以您的示例

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

$foo = new Bar();

您正在嘗試加載不需要/必需的類bar ,因此未定義該類,因此它最后調用__autoload方法,然后在自動加載中再次嘗試加載未定義的同一類。

使用__autoload的正確方法將在php網站中顯示。

<?php
function __autoload($class_name) {
    require_once $class_name . '.php';
}

$obj  = new MyClass1();
$obj2 = new MyClass2(); 
?>

而且您所有的init東西都可以放在__constructor中嗎?

除非我從您的問題中遺漏了一些東西...

我認為這

我的自動加載器會在加載的任何類上尋找靜態方法“ init”,然后嘗試運行該方法。

是解決您問題的關鍵。 您的自動裝帶器不應運行任何東西,它應包括(或以其他方式定義)該類,而沒有其他任何東西。

定義一個類時(例如,在您的靜態“ init”方法中),您嘗試運行哪種代碼?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM