Автозагрузка PHP: предотвращение "не может обновляться <класs>" во всех созвездиях?

Вопрос

Есть ли способ заставить PHP игнорировать повторные объявления классов, а не расширять FATAL ERROR? Или, по крайней мере, выбросить исключение? (я мог бы легко поймать его и продолжить (а также журнал попыток автозагрузки).

Я предполагаю, что нет, и фатальная ошибка - это фатальная ошибка - в конце концов, в девяноста девяти из ста случаев, это разумно разумное поведение - и мне, вероятно, просто придется исправить случаи его запуска в каждом конкретном случае. Но, возможно, кто-то умнее меня понял это.


Если вы спросите себя: "Почему бы вам это сделать?", читайте дальше.

Фон

Я работаю над инструментом, который использует Reflection для агрегирования конкретной информации об используемых функциях и классах. Один из аргументов script является необязательным файлом начальной загрузки, чтобы сделать Reflection более надежным с автозагрузкой (меньше ReflectionExceptions, которое в конечном итоге попадает и запускает эвакуацию возврата, поскольку классы неизвестны в определенном файле).

Теперь загрузочный загрузчик загружает автозагрузчик (а), а script работает по назначению, перемещается через несколько сотен файлов без жалобы, пока я не зацепился:

PHP Неустранимая ошибка: не удается переопределить класс PHPUnit_Framework_Constraint в /usr/share/php/PHPUnit/Framework/Constraint.php в строке 62

У меня есть две проблемы:

Во-первых, я понятия не имею, что вызывает это. Я скорректировал загрузочный файл, который используется, но меняю только "Не могу переопределить" и "Не могу открыть файл", в зависимости от используемого пути включения. Нет промежуточной точки, т.е. Нет точки, где ошибка не возникает. Тем не менее, я все еще расследую. (Этот вопрос не в том, о чем идет речь, хотя.)

Два, что более важно, и приводя к теме этого вопроса, Мне нужен способ поймать его. Я пробовал написать собственный обработчик ошибок, но он, похоже, не хочет работать для Fatal error (несколько разумно, можно утверждать).

В какой-то момент я намерен выпустить этот инструмент в мир с открытым исходным кодом, и это кажется мне совершенно неприемлемым поведением. У меня есть резервная эвристика для классов, которые не существуют - я бы предпочёл, чтобы они объявлялись однажды слишком редко, чем один раз слишком часто, но без чрезмерного использования эвристики, то есть, я хочу предложить возможность использования загрузчика. Без нарушения script. Когда-либо. Даже если это худший автозагрузчик в истории автозагрузчиков.

(Чтобы подчеркнуть: Мне не нужна помощь с автозагрузчиками. Это не тот вопрос, о котором идет речь.)

Ответ 1

Один из лучших вариантов, чтобы избежать Cannot redeclare - это функция class_exists. Вы можете использовать его в автозагрузчике для предотвращения повторной декларации класса. С помощью class_exists вам не нужно ловить ошибку, вы просто предотвращаете ее.

На самом деле существует два вида фатальных ошибок: уловка и не уловка. Класс receclaration не запускает E_RECOVERABLE_ERROR (захватывающий), и вы не можете его обработать.

Итак, ответ на ваш вопрос: "Вы не можете".

Ответ 2

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

spl_autoload_register делает различие между классами, которые он автоматически загружает, с полностью указанным идентификатором класса с расширением имени и классами, которые загружаются из пространства имен с идентификаторами класса, которые не включают пространство имен. Насколько я могу судить, это ошибка.

Мое решение: я тестирую, прежде чем создать экземпляр класса отражения, если идентификатор класса полностью разнесен по именам. Если это не так, я не использую рефлексию. Поскольку вы не возражаете против того, чтобы некоторые классы не загружались, это также может быть решением вашей проблемы.

Ответ 3

Autoload никогда не будет автоматически пытаться загрузить уже загруженный класс. Если у вас есть > 1 класс с тем же именем, возможно, вы ошибаетесь.

Если ваш синтаксический анализ "небезопасного" кода, вы можете захотеть выполнить поиск файла для имени класса, прежде чем пытаться его загрузить, но это следует использовать только в качестве последнего средства, поскольку это огромная трата процессора и, вероятно, просто скрывается действительные ошибки.

Если у вас есть требуемая структура и система автозагрузки, вы можете включить файл один раз в автозагрузку, а затем снова потребовать. Вы можете взломать исправление, обернув класс if( class_exists( <class_name_string> ) { ... <class declaration in here> ... }