Почему require_once так плохо в использовании?

jQuery Bullseye: http://static.pixeltango.com/jQuery/Bullseye/ также отлично справляется с обнаружением в окне просмотра!

140
задан rink.attendant.6 26 October 2013 в 16:23
поделиться

12 ответов

require_once и include_once оба требуют, чтобы система сохранила журнал того, что уже включалось/требовалось. Каждый *_once вызов означает проверять тот журнал. Таким образом, существует определенно [приблизительно 1 113] дополнительная работа, сделанная там, но достаточно к вреду скорость целого приложения?

... Я действительно сомневаюсь относительно него... Не, если Вы не находитесь на [1 114] действительно старые аппаратные средства или выполнение его партия .

, Если Вы делающие тысячи из *_once, Вы могли бы сделать работу сами более легким способом. Для простых приложений просто удостоверившись Вы только включали его, как только должен быть достаточными, но если Вы все еще добираетесь, переопределяют ошибки, Вы могли что-то вроде этого:

if (!defined('MyIncludeName')) {
    require('MyIncludeName');
    define('MyIncludeName', 1);
}

я буду лично придерживаться с эти *_once операторы, но на глупом миллионе сравнительного теста передачи, Вы видите различие между двумя:

                php                  hhvm
if defined      0.18587779998779     0.046600103378296
require_once    1.2219581604004      3.2908599376678

10-100Г — медленнее с require_once и любопытно, что require_once по-видимому медленнее в [1 111]. Снова, это только относится к Вашему коду, если Вы работаете *_once тысячи времен.

<час>
<?php // test.php

$LIMIT = 1000000;

$start = microtime(true);

for ($i=0; $i<$LIMIT; $i++)
    if (!defined('include.php')) {
        require('include.php');
        define('include.php', 1);
    }

$mid = microtime(true);

for ($i=0; $i<$LIMIT; $i++)
    require_once('include.php');

$end = microtime(true);

printf("if defined\t%s\nrequire_once\t%s\n", $mid-$start, $end-$mid);
<час>
<?php // include.php

// do nothing.
104
ответ дан Oli 26 October 2013 в 16:23
поделиться

Это не имеет никакого отношения к скорости. Это о сбое корректно.

, Если require_once () сбои, Ваш сценарий сделан. Ничто иное не обрабатывается. При использовании include_once (), остальная часть сценария попытается продолжить представлять, таким образом, пользователи потенциально ничего не узнали бы к чему-то, что перестало работать в сценарии.

-3
ответ дан ashchristopher 26 October 2013 в 16:23
поделиться

PEAR2 wiki (когда это существовало) раньше перечислял серьезные основания для отказа весь требовать/включать директивы в пользу автозагрузки луг, по крайней мере, для кода библиотеки. Они привязывают Вас к твердым структурам каталогов, когда альтернативные упаковочные модели как phar находятся на горизонте.

Обновление: Поскольку заархивированная версия сети Wiki является ужасным глазом-gougingly, я скопировал наиболее неопровержимые доводы ниже:

  • include_path требуется для использования (ГРУША) пакета. Это мешает связывать ГРУШЕВЫЙ пакет в рамках другого приложения с его собственным include_path, создавать единственный файл, содержащий необходимые классы, перемещать ГРУШЕВЫЙ пакет в архив phar без обширной модификации исходного кода.
  • , когда верхний уровень require_once смешан с условным выражением require_once, это может привести к коду, который является некэшируемым кэшами кода операции, такими как APC, который будет связан PHP 6.
  • относительный require_once требует, чтобы include_path уже были установлены до правильного значения, лишив возможности использовать пакет без надлежащего include_path
5
ответ дан Steve Clay 26 October 2013 в 16:23
поделиться

Я стал любопытным и проверил ссылку Adam Backstrom на [1 110] Технология Ваша Вселенная . Эта статья описывает одну из причин, которые требуют, должен использоваться вместо require_once. Однако их требования не содержали до моего анализа. Я интересовался бы наблюдением, где я, возможно, ошибочно анализировал решение. Я использовал php 5.2.0 для сравнений.

я начал путем создания 100 заголовочных файлов, которые использовали require_once для включения другого заголовочного файла. Каждый из этих файлов смотрел что-то как:

<?php
// /home/fbarnes/phpperf/hdr0.php
require_once "../phpperf/common_hdr.php";

?>

я создал их с помощью быстрого взлома удара:

for i in /home/fbarnes/phpperf/hdr{00..99}.php; do
  echo "<?php
// $i" > $i
  cat helper.php >> $i;
done

Этот путь я мог легко подкачать между использованием require_once и потребовать когда включая заголовочные файлы. Я тогда создал app.php для загрузки этих ста файлов. Это было похоже:

<?php

// Load all of the php hdrs that were created previously
for($i=0; $i < 100; $i++)
{
  require_once "/home/fbarnes/phpperf/hdr$i.php";
}

// Read the /proc file system to get some simple stats
$pid = getmypid();
$fp = fopen("/proc/$pid/stat", "r");
$line = fread($fp, 2048);
$array = split(" ", $line);

// write out the statistics; on RedHat 4.5 w/ kernel 2.6.9
// 14 is user jiffies; 15 is system jiffies
$cntr = 0;
foreach($array as $elem)
{
  $cntr++;
  echo "stat[$cntr]: $elem\n";
}
fclose($fp);

?>

я контрастировал, require_once заголовки с требуют заголовков, которые использовали сходство с заголовочного файла:

<?php
// /home/fbarnes/phpperf/h/hdr0.php
if(!defined('CommonHdr'))
{
  require "../phpperf/common_hdr.php";
  define('CommonHdr', 1);
}

?>

я не нашел много различия, когда выполнение этого с требует по сравнению с require_once. На самом деле мои начальные тесты, казалось, подразумевали, что require_once был немного быстрее, но я не обязательно верю этому. Я повторил эксперимент с 10 000 входных файлов. Здесь я действительно видел последовательное различие. Я запустил тест многократно, результаты близки, но использующий require_once использует в среднем 30,8 пользовательского мига и 72,6 системного мига; использование требует использования в среднем 39,4 пользовательского мига и 72,0 системного мига. Поэтому кажется, что загрузка немного ниже использует require_once. Однако настенные часы немного увеличены. 10 000 вызовов require_once используют 10,15 секунд для завершения в среднем, и 10,000 требуют, чтобы вызовы использовали 9,84 секунд в среднем.

Следующий шаг должен изучить эти различия. Я использовал strace для анализа системных вызовов, которые делаются.

Прежде, чем открыть файл от require_once следующие системные вызовы сделаны:

time(NULL)                              = 1223772434
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=88, ...}) = 0
time(NULL)                              = 1223772434
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3

Это контрастирует с, потребуйте:

time(NULL)                              = 1223772905
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=146, ...}) = 0
time(NULL)                              = 1223772905
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3

Технология Ваша Вселенная подразумевает, что require_once должен выполнить больше lstat64 вызовов. Однако они оба делают то же количество вызовов lstat64. Возможно, различие - то, что я не выполняю APC для оптимизации кода выше. Однако следующая вещь, которую я сделал, была, сравнивают вывод strace для всех выполнений:

[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out 
  190709 strace_1000r.out
  210707 strace_1000ro.out
  401416 total

Эффективно существует еще приблизительно два системных вызова на заголовочный файл при использовании require_once. Одно различие - то, что require_once имеет дополнительный вызов ко времени () функция:

[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out 
strace_1000r.out:20009
strace_1000ro.out:30008

другой системный вызов является getcwd ():

[fbarnes@myhost phpperf]$ grep -c getcwd strace_1000r.out strace_1000ro.out 
strace_1000r.out:5
strace_1000ro.out:10004

Это называют, потому что я решил к относительному пути, на который ссылаются в hdrXXX файлах. Если я делаю это абсолютной ссылкой, то единственной разницей является дополнительное время (ПУСТОЙ) вызов, выполненный в коде:

[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out 
  190705 strace_1000r.out
  200705 strace_1000ro.out
  391410 total
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20008
strace_1000ro.out:30008

Это, кажется, подразумевает, что Вы могли сократить количество системных вызовов при помощи полных путей, а не относительных путей. Единственной разницей за пределами этого является время (ПУСТЫЕ) вызовы, которые, кажется, используются для того, чтобы оснастить код для сравнения то, что быстрее.

Еще одно примечание - то, что пакет оптимизации APC имеет опцию, названную "apc.include_once_override", который утверждает, что это сокращает количество системных вызовов, сделанных require_once и вызовами include_once (см. документы PHP ).

Извините за длинное сообщение. Я стал любопытным.

64
ответ дан theB 26 October 2013 в 16:23
поделиться

Этот поток заставляет меня съежиться, потому что уже было "решение, отправленное", и это, во всех отношениях, неправильно. Давайте перечислим:

  1. Определяет, действительно дороги в PHP. Вы можете взгляд это или тестировать его сами, но единственный эффективный способ определить глобальную константу в PHP через расширение. (Константы класса являются на самом деле довольно достойной мудрой производительностью, но это - спорный вопрос, из-за 2)

  2. , Если Вы используете require_once() соответственно, то есть, для включения классов, Вам даже не нужно определение; просто проверьте если class_exists('Classname'). Если файл, который Вы включаете, содержит код, т.е. Вы используете его процедурным способом, нет абсолютно никакой причины, которая require_once() должна быть необходимой для Вас; каждый раз, когда Вы включаете файл, Вы предполагаете для создания вызова подпрограммы.

Поэтому некоторое время, много людей действительно использовало class_exists() метод для их включений. Мне не нравится он, потому что это - fugly, но у них было серьезное основание к: require_once() было довольно неэффективно перед некоторыми более свежими версиями PHP. Но это было зафиксировано, и это - моя конкуренция, что дополнительный байт-код, который необходимо было бы скомпилировать для условного выражения и дополнительного вызова метода, безусловно перевесит любую внутреннюю проверку хеш-таблицы.

Теперь, подтверждение: этот материал жесток для тестирования на, потому что он составляет так мало времени выполнения.

Вот вопрос, о котором необходимо думать: включает, как правило, являются дорогими в PHP, потому что каждый раз интерпретатор поражает тот, который это должно переключить назад в режим синтаксического анализа, генерировать коды операций, и затем перейти назад. Если у Вас есть 100 +, включает, это определенно окажет влияние производительности. Причина, почему использование или не использование require_once являются таким важным вопросом, состоит в том, потому что это делает жизнь трудной для кэшей кода операции. объяснение этого может быть найдено здесь, но к чему это сводится, то, что:

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

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

  • Автозагрузка является очень удобной, но медленной по причине, что логика автозагрузки должна быть выполнена каждый раз, когда включать сделано. На практике я нашел, что автозагрузка нескольких специализированных файлов для одного запроса не вызывает слишком много проблемы, но Вы не должны автоматически загружать все файлы, в которых Вы будете нуждаться.

  • , Если Вы имеете, возможно, 10, включает (это очень задняя часть вычисления конверта), весь этот wanking не стоит того: просто оптимизируйте свои запросы базы данных или что-то.

146
ответ дан Edward Z. Yang 26 October 2013 в 16:23
поделиться

Да, это немного более дорого, чем простой, требуют (). Я думаю, что точка - то, если можно сохранить код, организовал достаточно к не douplicate, включает, не используйте * _once () функции, поскольку это сохранит Вас некоторые циклы.

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

0
ответ дан Lucas Oman 26 October 2013 в 16:23
поделиться

Я думаю в ГРУШЕВОЙ документации, существует рекомендация для, требуют, require_once, включают и include_once. Я действительно следую той инструкции. Ваше приложение было бы более четким.

-2
ответ дан Ekkmanz 26 October 2013 в 16:23
поделиться

Мое личное мнение - то, что использование require_once (или include_once) является плохой практикой, потому что require_once проверяет на Вас, если Вы уже включали тот файл, и подавите ошибки двойных включенных файлов, приводящих к фатальным ошибкам (как двойное объявление функций/классов/и т.д.).

необходимо знать, необходимо ли включать файл.

-4
ответ дан Joe Scylla 26 October 2013 в 16:23
поделиться

Вы тестируете, использование включают, альтернатива oli и __ автозагрузка (); и протестируйте его с что-то как установленный APC.

я сомневаюсь, что постоянное использование ускорит вещи.

0
ответ дан Peter Mortensen 26 October 2013 в 16:23
поделиться

Можно ли дать нам какие-либо ссылки на эти методы кодирования, которые говорят для предотвращения его? Насколько я заинтересован, это - полный надуманный вопрос . Я не посмотрел на исходный код сам, но я предположил бы, что единственная разница между include и include_once - то, что include_once добавляет, что имя файла к массиву и проверяет массив каждый раз. Было бы легко сохранить тот массив отсортированным, таким образом искание по нему должно быть O (зарегистрируйте n), и даже среднее великоватое приложение только имело бы несколько дюжин, включает.

20
ответ дан nickf 26 October 2013 в 16:23
поделиться

*_once() статистика функций каждый родительский каталог для обеспечения файла, который Вы включаете, не является тем же как один, это было уже включено. Это - часть причины замедления.

я рекомендую использовать инструмент как Осада для сравнительного тестирования. Можно попробовать все предложенные методологии и сравнить время отклика.

[еще 116] на require_once() в Технология Ваша Вселенная .

5
ответ дан Annika Backstrom 26 October 2013 в 16:23
поделиться

Лучший способ сделать вещи состоит в том, чтобы использовать объектно-ориентированный подход и использование __ автозагрузка () .

6
ответ дан Greg 26 October 2013 в 16:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: