PHP включает семантику

Я пытаюсь понять, как интерпретировать конструкцию PHP include, например. является ли это текстовым включением, когда оно оценивается и т. д. Как обычно, документация довольно неформальна и расплывчата.

Судя по экспериментам, это синтаксический сахар. В частности, конструкция

include 'Baz.php'

выражение, которое можно заменить на

eval('?>' . file_get_contents('Baz.php',  FILE_USE_INCLUDE_PATH))

Это правильно? Верна ли эта замена в общем случае или только в моих тестах?

Изменить: как отмечает bwoebi, в целом это неверно, поскольку код evaluated не имеет одинаковых магических констант __DIR__ и __FILE__. Если бы был какой-то способ установить их, мы могли бы смоделировать и это.

Изменить 2: этот вопрос является дубликатом этого: Эквивалент включения с использованием eval. Однако все ответы, по-видимому, опускают точку bwoebi о контексте пути к файлу.


person jameshfisher    schedule 15.05.2014    source источник
comment
Нет, с __DIR__ и __FILE__ вам не повезло. (Я сомневаюсь, что даже runkit будет работать с этими константами времени компиляции)   -  person bwoebi    schedule 15.05.2014


Ответы (2)


Да, это должно быть в целом верно.

Единственные отличия:

  • контекст файла (теперь это eval()'ed code, а не код из этого файла)
  • относительные пути: когда вы включаете файлы в другие каталоги, и они сами используют относительные пути, файл, на который он указывает, теперь может быть больше не найден
  • file_get_contents() не зависит от настройки allow_url_include ini (хотя allow_url_fopen влияет на оба)
person bwoebi    schedule 15.05.2014
comment
@jameshfisher, чтобы обойти это, на самом деле вы могли бы просто использовать chdir() перед eval() здесь. (и сбросить позже) - person bwoebi; 15.05.2014
comment
Я не уверен, что это работает; кажется, что константы __FILE__ и __DIR__ остаются прежними? - person jameshfisher; 15.05.2014
comment
__FILE__ и __DIR__ будут соответствовать файлу и каталогу включенного/требуемого файла. Кроме того, относительные пути работают только в том случае, если вы поместили . (сокращение от текущего каталога) в свой include_path. Обычно небезопасно полагаться на то, что он установлен как таковой. - person Oscar M.; 15.05.2014
comment
@jameshfisher Просто спросил немного, но нет способа переопределить константы времени компиляции. Невозможно. - person bwoebi; 15.05.2014

Другие вещи, которые следует отметить:

  • Это нарушит кэширование кода операции PHP, так как содержимое файла считывается в память в виде текста, а затем анализируется/оценивается, что приводит к значительному снижению производительности, если вы этого не ожидаете. Как упоминалось в этом вопросе.
  • Ошибки синтаксического анализа в коде не будут фатальными для остальной части скрипта, что имеет побочный эффект, позволяя продолжить выполнение скрипта, даже если ожидаемая логика может не произойти. (Это может относиться и к другим типам ошибок).
  • Сообщения об ошибках не будут разрешаться в правильный файл/строку, и поэтому отладка станет затруднительной.
  • Это не будет поддерживать конструкцию _once, которая позволяет включать/требовать файлы только один раз. Это означает, что повторяющиеся объявления классов/функций будут фатальными и/или будут вести себя неожиданно.

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

Лучшая часть использования eval — это восстановление после ошибок (если это можно назвать «лучшей» вещью). Однако, если это преимущество, которым вы пытаетесь воспользоваться, это ваш единственный вариант... К сожалению...

person Mike    schedule 15.05.2014
comment
отчет об ошибках будет содержать только eval()'ed code (как я отметил в своем ответе), но строка по-прежнему верна. Конструкцию _once обычно можно эмулировать в функции. На все остальное согласен. - person bwoebi; 15.05.2014
comment
Строка оператора eval, но будет ли правильной строка, в которой произошла ошибка в eval? Эмуляция — это здорово, но зачем эмулировать все функциональные возможности стандартной библиотеки, если вы можете просто использовать их сами по себе? Эмуляция всех проверок и процедур функции возможна, но не нативна, и поэтому очень неэффективна. Я вижу это как учебное упражнение, но в остальном это непрактично. - person Mike; 15.05.2014