2010-07-16 2 views
0

ОК, это тяжело ... Я думаю, и у меня есть чувство, что ответ просто нет, но в этом случае мне бы хотелось получить ответы на альтернативы.Может ли PHP __autoload() использовать класс из другого __autoload() того же класса?

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

Мой автозагрузчик будет искать статический метод «init» для любого класса, который он загружает, и попытаться его запустить. В моем классе ActiveRecord он пытается использовать AuthActions, чтобы получить список поддерживаемых действий для определенной активной записи. AuthAction (no S) также вызывает AuthActions внутри его init, поэтому в основном загружается Active Record и пытается загрузить AuthActions, запуская загрузку остальных трех, а затем, когда он заканчивает загрузку AuthAction, все еще в исходном автозагрузчике AuthAction пытается позвонить AuthActions, который запускает еще одну автозагрузку, поскольку исходный файл еще не завершен.

Это приводит к тому, после чего имеет некоторое эхо заявления уточнить:

Attempting to load ActiveRecord
Attempting to load fActiveRecord
fActiveRecord loaded via /var/www/dotink.org/inkwelldemo/inc/lib/flourish
ActiveRecord loaded via /var/www/dotink.org/inkwelldemo/inc/lib
Attempting to load AuthActions
Attempting to load RecordSet
Attempting to load fRecordSet
fRecordSet loaded via /var/www/dotink.org/inkwelldemo/inc/lib/flourish
RecordSet loaded via /var/www/dotink.org/inkwelldemo/inc/lib
Attempting to load AuthAction
AuthAction loaded via /var/www/dotink.org/inkwelldemo/models

Fatal error: Class 'AuthActions' not found in /var/www/dotink.org/inkwelldemo/models/AuthAction.php on line 24

Проблема здесь заключается в том, что последующий вызов __autoload («AuthActions») будет преуспевать, потому что три класса он требует теперь на месте ... но, по-видимому, он умирает только от посылки, что он уже пытается автозагрузить «AuthActions» - это, кажется, hardwrit в PHP.

В тестировании этого я нашел следующий цикл навсегда без ошибок:

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

$foo = new Bar(); 

Хотя это один ниже будет ошибка аналогично:

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

$foo = new Bar(); 

Такое поведение кажется несовместимым как по существу они должны составлять то же самое (kinda). Если PHP внутренне инициировал автозагрузку, действовал как пользовательский вызов __autoload(), я не думаю, что у меня возникла бы проблема (или если бы я сделал то, то это была бы проблема его циклизации навсегда, что было бы отдельной проблемой для определения того, почему класс не загружался для разрешения зависимостей).

Короче говоря, мне нужен способ либо рекурсивно зациклировать автозагрузчик, как на основе автозагружаемых PHP-файлов ... это просто невозможно? Возможно, это ошибка в моей конкретной версии? Кажется, это влияет на 5.2.6 - 5.3.2 в моих тестах, поэтому я не могу себе представить, что это ошибка.

Update:

Код метода 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() для класса при каждом его загрузке, приветствуются и приветствуются.

ответ

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

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

+0

Возможно, вы захотите проверить реализации SPL для __autoload, чтобы лучше понять, как он предназначен для использования. Вы можете выполнить довольно красивую загрузку файлов, если будете следовать структуре/структуре стиля/структуре стиля Zend и пространству имен или использованию 5.3 и механике пространства имен. http://us2.php.net/manual/en/function.spl-autoload.php – tsgrasser

+0

SPL не делает ничего, кроме создания стека автозагрузчиков из того, что я знаю. Mine делает что-то совсем другое, но независимо от того, проблема не решена автозагрузчиками SPL, так как каждый автозагрузчик будет по-прежнему обрабатываться с такой же резкой смертью при любых таких попытках загрузить тот же самый класс, который загружается в настоящий момент. – 2010-07-16 08:05:56

+0

Могу ли я также добавить к оригинальному плакату ozatomic, примеры, которые я предоставил, - это просто показать, как поведение отличается в зависимости от того, запущена ли автозагрузка внутри, независимо от того, вызвана ли она пользователем. Это касается только моей проблемы, поскольку мне нужно, чтобы она выполнялась во второй раз. Я не просто пытаюсь загрузить тот же класс навсегда, я понимаю, что это не то, как используется автозагрузчик. – 2010-07-16 08:08:03

1

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

My autoloader will look for a static method "init" on any class it loads and try to run that.

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

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

+0

Brenton, я отредактировал исходный вопрос, чтобы включить код init и еще несколько абзацев, чтобы уточнить, что я ищу в своем решении. Я ценю вашу точку зрения, что автозагрузчик не должен ничего запускать, однако я не могу придумать другого способа, чтобы кратко убедиться, что метод вызван в классе после его загрузки. – 2010-07-16 08:23:56