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


Answers

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

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

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

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

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

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

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

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

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

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

Question

Все, что я читал о лучших методах кодирования PHP, говорит, что не используйте require_once из-за скорости.

Почему это?

Каков правильный / лучший способ сделать то же самое, что и require_once ? Если это имеет значение, я использую PHP5.




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

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




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

Вы должны знать, нужно ли включать файл.




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

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

Подробнее о require_once() в Tech Your Universe .




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




Я думаю, что в документации PEAR есть рекомендация require, require_once, include и include_once. Я следую этому руководству. Ваша заявка будет более понятной.




Он не использует функцию, которая плоха. Это неправильное понимание того, как и когда использовать его, в общей базе кода. Я просто добавлю немного больше контекста к этому, возможно, неправильно понятому понятию:

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

То, что я видел, это очень плохо, когда огромные монолитные рамки используют require_once() во всех неправильных направлениях, особенно в сложной объектно-ориентированной среде.

Возьмите пример использования require_once() в верхней части каждого класса, как показано во многих библиотеках:

require_once("includes/usergroups.php");
require_once("includes/permissions.php");
require_once("includes/revisions.php");
class User{
  //user functions
}

Таким образом, класс User предназначен для использования всех трех других классов. Справедливо! Но что теперь, если посетитель просматривает сайт и даже не входит в систему и загружает фреймворк: require_once("includes/user.php"); для каждого отдельного запроса.

Он включает в себя 1 + 3 ненужных класса, которые он никогда не будет использовать во время этого конкретного запроса. Вот как раздутые рамки заканчиваются использованием 40 МБ за запрос, а не 5 МБ или меньше.

Другие способы, которыми это может быть неправильно использовано, - это когда класс повторно используется многими другими! Скажем, у вас около 50 классов, которые используют helper функции. Чтобы убедиться, что helpers доступны для этих классов, когда они загружены, вы получаете:

require_once("includes/helpers.php");
class MyClass{
  //Helper::functions();//etc..
}

Здесь нет ничего плохого. Однако, если один запрос страницы включает 15 аналогичных классов. Вы выполняете require_once 15 раз, или для хорошего визуального:

require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");

Использование require_once () технически влияет на производительность для выполнения этой функции 14 раз, вместо того, чтобы анализировать эти ненужные строки. Имея всего 10 других высокоприбыльных классов с подобной проблемой, он мог бы учитывать более 100 строк такого довольно бессмысленного повторяющегося кода.

При этом, вероятно, стоит использовать require("includes/helpers.php"); при загрузке вашего приложения или фреймворка. Но поскольку все относительное, все зависит от того, будет ли вес и частота использования класса helpers экономить 15-100 строк require_once() . Но если вероятность того, что файл- helpers не будет использоваться для любого заданного запроса, равно none, тогда require обязательно должно быть в вашем основном классе. Наличие require_once в каждом классе отдельно становится пустой тратой ресурсов.

Функция require_once полезна при необходимости, но ее нельзя рассматривать как монолитное решение для использования везде для загрузки всех классов.