Все, что я читал о лучших практиках кодирования PHP, говорит, что не используйте require_once
из-за скорости.
Почему это?
Как правильно / лучше сделать то же самое, что и require_once
? Если это имеет значение, я использую PHP 5.
php
performance
require-once
Uberfuzzy
источник
источник
Ответы:
require_once
иinclude_once
оба требуют, чтобы система вела журнал того, что уже было включено / требуется. Каждый*_once
звонок означает проверку этого журнала. Так что , безусловно , некоторые дополнительные работы там делается , но достаточно , чтобы ущерб скорости всего приложения?... Я действительно сомневаюсь в этом ... Нет, если вы не используете действительно старое оборудование или не делаете много .
Если будут делать тысячи
*_once
, вы могли бы сделать работу самостоятельно в более легкой форме. Для простых приложений, только убедившись , что вы включены только он один раз должно хватить , но если вы все еще получаете ошибки переопределять, вы могли бы что - то вроде этого:Я лично буду придерживаться
*_once
утверждений, но на глупом тесте с миллионным проходом вы можете увидеть разницу между ними:В 10-100 раз медленнее,
require_once
и любопытно, чтоrequire_once
, похоже, медленнееhhvm
. Опять же, это относится только к вашему коду, если вы работаете*_once
тысячи раз.источник
Эта тема заставляет меня передергиваться, потому что уже было опубликовано «решение», и это, по сути, неправильно. Давайте перечислим:
Определения действительно дорогие в PHP. Вы можете посмотреть его или протестировать самостоятельно, но единственный эффективный способ определения глобальной константы в PHP - через расширение. (Константы класса на самом деле довольно приличны с точки зрения производительности, но это спорный вопрос из-за 2)
Если вы используете
require_once()
правильно, то есть для включения классов, вам даже не нужно определение; просто проверьте, еслиclass_exists('Classname')
. Если файл, который вы включаете, содержит код, т.е. вы используете его в процедурном порядке, то нет абсолютно никаких причин, которыеrequire_once()
могут вам понадобиться; каждый раз, когда вы включаете файл, вы предполагаете, что выполняете вызов подпрограммы.Так что какое-то время многие люди использовали этот
class_exists()
метод для своих включений. Мне это не нравится, потому что это плохо, но у них были веские причины:require_once()
был довольно неэффективен перед некоторыми из более поздних версий PHP. Но это было исправлено, и я утверждаю, что дополнительный байт-код, который вам нужно будет скомпилировать для условного, и дополнительный вызов метода, намного перевесят любую внутреннюю проверку хеш-таблицы.Теперь, признание: этот материал сложно проверить, потому что он занимает так мало времени выполнения.
Вот вопрос, о котором вы должны подумать: как правило, include в PHP дорогой, потому что каждый раз, когда интерпретатор нажимает на него, он должен переключаться обратно в режим разбора, генерировать коды операций и затем возвращаться назад. Если у вас есть 100+ включений, это определенно повлияет на производительность. Причина, по которой использование или не использование require_once является таким важным вопросом, заключается в том, что это усложняет жизнь для кэшей кода операции. Объяснение этому можно найти здесь, но то , что это сводится к тому, что:
Если во время синтаксического анализа вы точно знаете, какие включаемые файлы вам понадобятся на протяжении всего срока действия запроса,
require()
то в самом начале и кэш кода операции будут обрабатывать все остальное за вас.Если вы не используете кэш кода операции, вы находитесь в затруднительном положении. Включение всех ваших включений в один файл (не делайте этого во время разработки, только в производственной среде), безусловно, может помочь разобрать время, но это трудная задача, а также вам необходимо точно знать, что вы будете включать во время запрос.
Автозагрузка очень удобна, но медленна, потому что логика автозагрузки должна выполняться каждый раз, когда выполняется включение. На практике я обнаружил, что автозагрузка нескольких специализированных файлов для одного запроса не вызывает особых проблем, но вам не следует загружать все нужные вам файлы.
Если у вас есть, может быть, 10 включений (это очень обратная сторона расчета конверта), все это подделка не стоит: просто оптимизируйте запросы к вашей базе данных или что-то в этом роде.
источник
define()
,require_once()
иdefined()
все занимает около 1-2 микросекунд каждый на моей машине.Мне стало любопытно и проверил ссылку Адама Бэкстрома на Tech Your Universe . В этой статье описывается одна из причин, по которой нужно использовать require вместо require_once. Однако их претензии не выдержали моего анализа. Мне было бы интересно узнать, где я мог неправильно проанализировать решение. Я использовал PHP 5.2.0 для сравнения.
Я начал с создания 100 заголовочных файлов, которые использовали require_once для включения другого заголовочного файла. Каждый из этих файлов выглядел примерно так:
Я создал их, используя быстрый взлом Bash:
Таким образом, я мог бы легко переключаться между использованием require_once и require при включении заголовочных файлов. Затем я создал app.php для загрузки ста файлов. Это выглядело так:
Я сравнил заголовки require_once с заголовками require, которые использовали файл заголовка, похожий на:
Я не нашел большой разницы, когда запускал это с require против require_once. На самом деле мои первоначальные тесты подразумевали, что require_once был немного быстрее, но я не обязательно в это верю. Я повторил эксперимент с 10000 входными файлами. Здесь я увидел постоянную разницу. Я запускал тест несколько раз, результаты близки, но при использовании require_once в среднем используется 30,8 пользовательских и 72,6 системных запросов; использование require использует в среднем 39,4 пользовательских и 72,0 системных. Таким образом, кажется, что загрузка немного ниже, используя require_once. Однако время настенных часов немного увеличено. Для 10 000 вызовов require_once в среднем требуется 10,15 секунды, а для 10 000 вызовов требуется в среднем 9,84 секунды.
Следующим шагом является изучение этих различий. Я использовал strace для анализа выполняемых системных вызовов.
Перед открытием файла из require_once выполняются следующие системные вызовы:
Это контрастирует с требованием:
Tech Your Universe подразумевает, что require_once должен делать больше вызовов lstat64. Однако они оба делают одинаковое количество вызовов lstat64. Возможно, разница в том, что я не использую APC для оптимизации кода выше. Однако затем я сравнил вывод strace для всех прогонов:
Фактически при использовании require_once на каждый заголовочный файл приходится примерно еще два системных вызова. Одно отличие состоит в том, что require_once имеет дополнительный вызов функции time ():
Другой системный вызов - getcwd ():
Это вызвано тем, что я решил использовать относительный путь в файлах hdrXXX. Если я сделаю это абсолютной ссылкой, то единственное отличие - это вызов дополнительного времени (NULL), сделанный в коде:
Кажется, это подразумевает, что вы можете уменьшить количество системных вызовов, используя абсолютные пути, а не относительные пути. Единственное отличие от этого - это вызовы времени (NULL), которые, по-видимому, используются для инструментирования кода для сравнения того, что быстрее.
Еще одно замечание: в пакете оптимизации APC есть опция «apc.include_once_override», в которой утверждается, что она уменьшает количество системных вызовов, выполняемых вызовами require_once и include_once (см. Документацию PHP). ).
источник
Можете ли вы дать нам какие-либо ссылки на эти методы кодирования, которые говорят, чтобы избежать этого? Насколько я понимаю, это совершенно не проблема . Я сам не смотрел на исходный код, но представляю, что единственная разница между
include
иinclude_once
заключается в том,include_once
что это имя файла добавляется в массив и проверяет массив каждый раз. Было бы легко сохранить этот массив отсортированным, поэтому поиск по нему должен быть O (log n), и даже приложение среднего размера будет иметь только пару десятков включений.источник
Лучший способ сделать это - использовать объектно-ориентированный подход и использовать __autoload () .
источник
__autoload()
не рекомендуется, и в будущем это может быть устаревшим, вы должны использоватьspl_autoload_register(...)
эти дни ... PS2: не поймите меня неправильно, иногда я использую функцию автозагрузки; )Это не использование функции, которая плоха. Это неверное понимание того, как и когда его использовать, в общей базе кода. Я просто добавлю немного больше контекста к этому, возможно, неправильно понятому понятию:
Люди не должны думать, что require_once - медленная функция. Вы должны включить свой код так или иначе.
require_once()
противrequire()
Скорость не проблема. Речь идет о производительности, препятствующей предостережениям, которые могут привести к тому, что они будут использоваться вслепую. При широком использовании без учета контекста это может привести к огромным потерям памяти или расточительному коду.Что я видел, это действительно плохо, когда огромные монолитные каркасы используют
require_once()
неправильно используют, особенно в сложной объектно-ориентированной (ОО) среде.Возьмите пример использования
require_once()
в верхней части каждого класса, как это видно во многих библиотеках:Так что
User
класс предназначен для использования всех трех других классов. Справедливо!Но что теперь, если посетитель просматривает сайт и даже не вошел в систему, а фреймворк загружается:
require_once("includes/user.php");
для каждого отдельного запроса.Он включает 1 + 3 ненужных класса, которые он никогда не будет использовать во время этого конкретного запроса. Вот как раздутые фреймворки в итоге используют 40 МБ на запрос, а не 5 МБ или меньше.
Другие способы, которыми он может быть использован не по назначению, - это когда класс повторно используется многими другими! Скажем, у вас есть около 50 классов, которые используют
helper
функции. Чтобы убедиться, чтоhelpers
эти классы доступны, когда они загружены, вы получите:В этом нет ничего плохого. Однако, если один запрос страницы включает 15 похожих классов. Вы работаете
require_once
15 раз, или для хорошего визуального:Использование require_once () технически влияет на производительность при запуске этой функции 14 раз, помимо необходимости разбирать эти ненужные строки. Имея всего 10 других широко используемых классов с такой же проблемой, он может содержать более 100 строк такого довольно бессмысленного повторяющегося кода.
При этом, вероятно
require("includes/helpers.php");
, вместо этого стоит использовать при загрузке вашего приложения или фреймворка. Но так как все относительно, все зависит от того,helpers
стоит ли вес в сравнении с частотой использования класса экономить 15-100 строкrequire_once()
. Но если вероятность не использоватьhelpers
файл по какому-либо заданному запросу равна нулю, тоrequire
определенно должна быть в вашем основном классе. Наличиеrequire_once
в каждом классе отдельно становится пустой тратой ресурсов.require_once
Функция полезна , когда необходимо, но это не следует рассматривать как монолитное решение использовать везде для загрузки всех классов.источник
Вики PEAR2 (когда она существовала) использовалась для перечисления веских причин отказа от всех директив require / include в пользу автозагрузки , по крайней мере для библиотечного кода. Они связывают вас с жесткой структурой каталогов, когда альтернативные модели упаковки, такие как phar на горизонте появляются .
Обновление: поскольку веб-архивная версия вики выглядит ужасно уродливо, я скопировал наиболее убедительные причины ниже:
источник
*_once()
Функции стат каждый родительский каталог для обеспечения файл , который вы в том числе не то же самое , как тот , который уже был включен. Это одна из причин замедления.Я рекомендую использовать такой инструмент, как Siege для бенчмаркинга. Вы можете попробовать все предложенные методики и сравнить время отклика.
Больше на
require_once()
это в Технологическом вашей вселенной .источник
Даже если
require_once
иinclude_once
есть медленнее , чемrequire
иinclude
(или все , что может существовать альтернативы), мы говорим о маленьком уровне микро-оптимизации здесь. Ваше время гораздо лучше потрачено на оптимизацию плохо написанного цикла или запроса к базе данных, чем на беспокойство о чем-то подобномrequire_once
.Теперь можно привести аргумент, говорящий о том, что это
require_once
допускает плохую практику кодирования, потому что вам не нужно обращать внимание на то, чтобы ваши включения были чистыми и организованными, но это не имеет ничего общего с самой функцией , особенно с ее скоростью.Очевидно, что автозагрузка лучше для чистоты кода и простоты обслуживания, но я хочу прояснить, что это никак не связано со скоростью .
источник
Вы проверяете, используя include, альтернативу oli и __autoload (); и проверить это с чем-то вроде APC установленным .
Я сомневаюсь, что использование константы ускорит процесс.
источник
Да, это немного дороже, чем обычные старые (). Я думаю, суть в том, что если вы можете сохранить свой код достаточно организованным, чтобы не дублировать включения, не используйте функции * _once (), так как это сэкономит вам несколько циклов.
Но использование функций _once () не убьет ваше приложение. В основном, просто не используйте это как оправдание, чтобы не организовывать ваши включения . В некоторых случаях его использование все еще неизбежно, и это не имеет большого значения.
источник
Я думаю, что в документации PEAR есть рекомендации для require, require_once, include и include_once. Я следую этому руководству. Ваша заявка будет более понятной.
источник
Это не имеет ничего общего со скоростью. Речь идет о изящной неудаче.
Если require_once () не работает, ваш скрипт готов. Больше ничего не обрабатывается. Если вы используете include_once (), остальная часть вашего сценария будет пытаться продолжить рендеринг, так что ваши пользователи потенциально не будут ничего удивляться тому, что не удалось в вашем сценарии.
источник
Мое личное мнение заключается в том, что использование require_once (или include_once) является плохой практикой, потому что require_once проверяет вас, если вы уже включили этот файл, и подавляете ошибки двойных включенных файлов, приводящие к фатальным ошибкам (таким как двойное объявление функций / классов / и т. Д.) ,
Вы должны знать, если вам нужно включить файл.
источник