Может ли PHP __autoload () класс из другого __autoload () того же класса? - PullRequest
0 голосов
/ 16 июля 2010

Хорошо, это сложный вопрос ... Я думаю, и я чувствую, что ответ просто нет, но в этом случае я хотел бы получить ответы на некоторые альтернативы.

У меня есть очень сложная функция __autoload () в среде, которая может динамически создавать классы. Для динамического создания класса с именем AuthActions требуется три класса - это три: fRecordSet, RecordSet и AuthAction (обратите внимание, что на этом нет S).

Мой автозагрузчик будет искать статический метод "init" в любом загружаемом классе и попытаться запустить его. В моем классе ActiveRecord он пытается использовать AuthActions, чтобы получить список поддерживаемых действий для конкретной активной записи. AuthAction (без S) также вызывает AuthActions в своем init, поэтому в основном загружается 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
Набор записей загружается через /var/www/dotink.org/inkwelldemo/inc/lib
Попытка загрузить AuthAction
AuthAction загружается через /var/www/dotink.org/inkwelldemo/models

Неустранимая ошибка: класс 'AuthActions' не найден в /var/www/dotink.org/inkwelldemo/models/AuthAction.php в строке 24

Проблема здесь в том, что последующий вызов __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 в моих тестах, поэтому я не могу представить, что это общая ошибка.

Обновление:

Код для метода init () в AuthAction приведен ниже:

        /**
     * 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 ]

1 голос
/ 16 июля 2010

Я думаю, что это

Мой автозагрузчик будет искать статический метод "init" в любом загружаемом классе и пытаться запустить его.

- ключ ктвоя проблема.Ваш автозагрузчик не должен ничего запускать, он должен включать (или иным образом определять) класс и ничего больше.

Какой код вы пытаетесь запустить, когда класс определен (т.е. в вашем статическом методе init)?

1 голос
/ 16 июля 2010

__ метод автозагрузки вызывается только тогда, когда вы пытаетесь использовать класс / интерфейс, который еще не определен.

Следовательно, в вашем примере

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 не так ли?

если я не пропустил что-то из твоего вопроса ...

...