Хорошо, это сложный вопрос... Я думаю, и у меня есть чувство, что ответ просто нет, но в этом случае я хотел бы получить ответы на альтернативные варианты.
У меня есть очень сложная функция __autoload() в фреймворке, которая может динамически создавать классы. Для динамического создания класса AuthActions требуются три класса: fRecordSet, RecordSet и AuthAction (обратите внимание, что в нем нет буквы S).
Мой автозагрузчик будет искать статический метод «init» для любого загружаемого класса и пытаться его запустить. В моем классе ActiveRecord он пытается использовать AuthActions, чтобы получить список поддерживаемых действий для конкретной активной записи. AuthAction (без S) также вызывает AuthActions внутри своей инициализации, поэтому в основном 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
RecordSet загружается через /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 в моих тестах, поэтому я не могу представить, что это ошибка в целом.
Обновлять:
Ниже приведен код метода инициализации() для 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() для класса каждый раз, когда он загружается, приветствуются и приветствуются.