Alles, was ich über bessere PHP-Codierungspraktiken lese, sagt immer wieder, dass ich es nicht benutze require_once
wegen der Geschwindigkeit .
Warum ist das?
Was ist der richtige / bessere Weg, um das Gleiche zu tun require_once
? Wenn es darauf ankommt, verwende ich PHP 5.
php
performance
require-once
Uberfuzzy
quelle
quelle
Antworten:
require_once
undinclude_once
beide erfordern, dass das System ein Protokoll darüber führt, was bereits enthalten / erforderlich ist. Jeder*_once
Anruf bedeutet, dieses Protokoll zu überprüfen. So gibt es auf jeden Fall einige zusätzliche Arbeit dort getan , aber genug , um die Geschwindigkeit der gesamten App benachteiligt wurde ?... Ich bezweifle es wirklich ... Nicht, wenn Sie nicht auf wirklich alter Hardware sind oder viel tun .
Wenn Sie sind Tausende tun
*_once
, könnten Sie die Arbeit selbst in einer leichteren Art und Weise tun. Für einfache Apps sollte es ausreichen , nur sicherzustellen, dass Sie sie nur einmal eingefügt haben. Wenn Sie jedoch immer noch Fehler bei der Neudefinition erhalten, können Sie Folgendes tun:Ich werde mich persönlich an die
*_once
Aussagen halten, aber beim albernen Millionen-Pass-Benchmark können Sie einen Unterschied zwischen den beiden feststellen:10-100 × langsamer mit
require_once
und es ist merkwürdig, dassrequire_once
es scheinbar langsamer isthhvm
. Auch dies ist für Ihren Code nur relevant, wenn Sie*_once
tausende Male ausgeführt werden.quelle
Dieser Thread lässt mich zusammenzucken, weil bereits eine "Lösung veröffentlicht" wurde und er in jeder Hinsicht falsch ist. Lassen Sie uns aufzählen:
Definitionen sind in PHP sehr teuer. Sie können es nachschlagen oder selbst testen, aber die einzige effiziente Möglichkeit, eine globale Konstante in PHP zu definieren, ist eine Erweiterung. (Klassenkonstanten sind in Bezug auf die Leistung eigentlich ziemlich anständig, aber dies ist wegen 2 ein strittiger Punkt.)
Wenn Sie
require_once()
entsprechend verwenden, dh für die Aufnahme von Klassen, benötigen Sie nicht einmal eine Definition. Überprüfen Sie einfach, obclass_exists('Classname')
. Wenn die Datei, die Sie einschließen, Code enthält, dh Sie sie prozedural verwenden, gibt es absolut keinen Grund,require_once()
der für Sie erforderlich sein sollte. Jedes Mal, wenn Sie die Datei einschließen, wird angenommen, dass Sie einen Unterprogrammaufruf ausführen.Für eine Weile verwendeten viele Leute die
class_exists()
Methode für ihre Einschlüsse. Ich mag es nicht, weil es flüchtig ist, aber sie hatten guten Grund dazu:require_once()
war vor einigen der neueren Versionen von PHP ziemlich ineffizient. Aber das wurde behoben, und ich bin der Meinung, dass der zusätzliche Bytecode, den Sie für die Bedingung kompilieren müssten, und der zusätzliche Methodenaufruf jede interne Hashtabellenprüfung bei weitem überwiegen würden.Nun ein Eingeständnis: Dieses Zeug ist schwer zu testen, weil es so wenig Zeit für die Ausführung ausmacht.
Hier ist die Frage, über die Sie nachdenken sollten: Includes sind in PHP in der Regel teuer, da der Interpreter jedes Mal, wenn er einen trifft, wieder in den Analysemodus wechseln, die Opcodes generieren und dann zurückspringen muss. Wenn Sie über 100 Includes verfügen, hat dies definitiv Auswirkungen auf die Leistung. Der Grund, warum die Verwendung oder Nichtverwendung von require_once eine so wichtige Frage ist, liegt darin, dass es Opcode-Caches das Leben schwer macht. Eine Erklärung dafür finden Sie hier, aber worauf es ankommt, ist Folgendes:
Wenn Sie während der Analysezeit genau wissen, welche Include-Dateien Sie für die gesamte Lebensdauer der Anforderung benötigen, übernehmen die Dateien
require()
ganz am Anfang und der Opcode-Cache alles andere für Sie.Wenn Sie keinen Opcode-Cache ausführen, befinden Sie sich an einem schwierigen Ort. Das Einfügen aller Ihrer Includes in eine Datei (tun Sie dies nicht während der Entwicklung, sondern nur in der Produktion) kann sicherlich dazu beitragen, die Zeit zu analysieren, aber es ist mühsam, dies zu tun, und Sie müssen genau wissen, was Sie während des Vorgangs einschließen Anfrage.
Autoload ist sehr praktisch, aber langsam, da die Autoload-Logik jedes Mal ausgeführt werden muss, wenn ein Include durchgeführt wird. In der Praxis habe ich festgestellt, dass das automatische Laden mehrerer spezialisierter Dateien für eine Anforderung kein allzu großes Problem darstellt. Sie sollten jedoch nicht alle benötigten Dateien automatisch laden.
Wenn Sie vielleicht 10 enthält (dies ist eine sehr Rückseite des Umschlags Berechnung), all dies Wichsen ist es nicht wert: nur Ihre Datenbankabfragen oder etwas optimieren.
quelle
define()
,require_once()
unddefined()
alle nehmen etwa 1-2 Mikrosekunden je auf meinem Rechner.Ich wurde neugierig und überprüfte Adam Backstroms Link zu Tech Your Universe . Dieser Artikel beschreibt einen der Gründe, warum require anstelle von require_once verwendet werden sollte. Ihre Behauptungen hielten meiner Analyse jedoch nicht stand. Es würde mich interessieren, wo ich die Lösung möglicherweise falsch analysiert habe. Ich habe PHP 5.2.0 für Vergleiche verwendet.
Ich begann damit, 100 Header-Dateien zu erstellen, die require_once verwendeten, um eine weitere Header-Datei einzuschließen. Jede dieser Dateien sah ungefähr so aus:
Ich habe diese mit einem schnellen Bash-Hack erstellt:
Auf diese Weise konnte ich leicht zwischen require_once und require wechseln, wenn ich die Header-Dateien einbezog. Ich habe dann eine app.php erstellt, um die hundert Dateien zu laden. Das sah so aus:
Ich habe die Header require_once den Headern require_ gegenübergestellt, die eine Header-Datei verwendet haben, die wie folgt aussieht:
Ich habe keinen großen Unterschied festgestellt, als ich dies mit require vs. require_once ausgeführt habe. Tatsächlich schienen meine ersten Tests zu implizieren, dass require_once etwas schneller war, aber ich glaube das nicht unbedingt. Ich habe das Experiment mit 10000 Eingabedateien wiederholt. Hier habe ich einen konsequenten Unterschied gesehen. Ich habe den Test mehrmals ausgeführt. Die Ergebnisse sind nahe beieinander, aber bei Verwendung von require_once werden durchschnittlich 30,8 Benutzer-Jiffies und 72,6 System-Jiffies verwendet. Die Verwendung erfordert durchschnittlich 39,4 Benutzer-Jiffies und 72,0 System-Jiffies. Daher scheint die Last mit require_once etwas geringer zu sein. Die Wanduhrzeit ist jedoch leicht erhöht. Die 10.000 erforderlichen Anrufe benötigen durchschnittlich 10,15 Sekunden, und die 10.000 erforderlichen Anrufe benötigen durchschnittlich 9,84 Sekunden.
Der nächste Schritt besteht darin, diese Unterschiede zu untersuchen. Ich habe strace verwendet , um die Systemaufrufe zu analysieren, die gerade getätigt werden.
Vor dem Öffnen einer Datei aus require_once werden folgende Systemaufrufe ausgeführt:
Dies steht im Gegensatz zu erfordern:
Tech Your Universe impliziert, dass require_once mehr lstat64-Aufrufe tätigen sollte. Beide führen jedoch die gleiche Anzahl von lstat64-Aufrufen durch. Möglicherweise besteht der Unterschied darin, dass ich APC nicht ausführe, um den obigen Code zu optimieren. Als nächstes verglich ich jedoch die Strace-Ausgabe für die gesamten Läufe:
Tatsächlich gibt es bei Verwendung von require_once ungefähr zwei weitere Systemaufrufe pro Header-Datei. Ein Unterschied besteht darin, dass require_once einen zusätzlichen Aufruf der Funktion time () hat:
Der andere Systemaufruf ist getcwd ():
Dies wird aufgerufen, weil ich mich für einen relativen Pfad entschieden habe, auf den in den hdrXXX-Dateien verwiesen wird. Wenn ich dies zu einer absoluten Referenz mache, ist der einzige Unterschied der zusätzliche Zeitaufruf (NULL) im Code:
Dies scheint zu implizieren, dass Sie die Anzahl der Systemaufrufe reduzieren können, indem Sie absolute Pfade anstelle relativer Pfade verwenden. Der einzige Unterschied besteht in den Zeitaufrufen (NULL), die anscheinend zur Instrumentierung des Codes verwendet werden, um zu vergleichen, was schneller ist.
Ein weiterer Hinweis ist, dass das APC-Optimierungspaket eine Option namens "apc.include_once_override" enthält, die behauptet, dass es die Anzahl der Systemaufrufe reduziert, die von den Aufrufen require_once und include_once ausgeführt werden (siehe PHP-Dokumentation ).
quelle
Können Sie uns Links zu diesen Codierungspraktiken geben, um dies zu vermeiden? Für mich ist das kein Problem . Ich habe mir den Quellcode nicht selbst angesehen, aber ich würde mir vorstellen, dass der einzige Unterschied zwischen
include
und darininclude_once
besteht, dassinclude_once
dieser Dateiname einem Array hinzugefügt und das Array jedes Mal überprüft wird. Es wäre einfach, dieses Array sortiert zu halten, daher sollte die Suche darüber O (log n) sein, und selbst eine mittelgroße Anwendung würde nur ein paar Dutzend Includes enthalten.quelle
Eine bessere Möglichkeit besteht darin, einen objektorientierten Ansatz zu verwenden und __autoload () zu verwenden .
quelle
__autoload()
wird nicht empfohlen und es könnte in Zukunft veraltet sein, sollten Siespl_autoload_register(...)
heutzutage verwenden ... PS2: Verstehen Sie mich nicht falsch, ich verwende manchmal Autoload-Funktionen; )Es ist nicht die Funktion zu verwenden, die schlecht ist. Es ist ein falsches Verständnis, wie und wann es in einer gesamten Codebasis verwendet werden soll. Ich werde diesem möglicherweise missverstandenen Begriff nur etwas mehr Kontext hinzufügen:
Die Leute sollten nicht denken, dass require_once eine langsame Funktion ist. Sie müssen Ihren Code auf die eine oder andere Weise einfügen. Die Geschwindigkeit von
require_once()
vs.require()
ist nicht das Problem. Es geht um die Leistung, die Einschränkungen behindert, die sich aus der blinden Verwendung ergeben können. Wenn es ohne Berücksichtigung des Kontexts allgemein verwendet wird, kann dies zu großer Speicherverschwendung oder verschwenderischem Code führen.Was ich gesehen habe, ist wirklich schlecht, wenn riesige monolithische Frameworks
require_once()
auf die falsche Weise verwendet werden, insbesondere in einer komplexen objektorientierten Umgebung (OO).Nehmen Sie das Beispiel der Verwendung
require_once()
an der Spitze jeder Klasse, wie es in vielen Bibliotheken zu sehen ist:Die
User
Klasse ist also so konzipiert, dass alle drei anderen Klassen verwendet werden. Meinetwegen!Aber was ist nun, wenn ein Besucher die Website durchsucht und nicht einmal angemeldet ist und das Framework geladen wird:
require_once("includes/user.php");
für jede einzelne Anfrage.Es enthält 1 + 3 unnötige Klassen, die während dieser speziellen Anfrage niemals verwendet werden. Auf diese Weise verbrauchen aufgeblähte Frameworks 40 MB pro Anforderung im Gegensatz zu 5 MB oder weniger.
Die andere Möglichkeit, es zu missbrauchen, besteht darin, dass eine Klasse von vielen anderen wiederverwendet wird! Angenommen, Sie haben ungefähr 50 Klassen, die
helper
Funktionen verwenden. Um sicherzustellenhelpers
, dass diese Klassen beim Laden verfügbar sind, erhalten Sie:Hier ist an sich nichts falsch. Wenn jedoch eine Seitenanforderung 15 ähnliche Klassen enthält. Sie laufen
require_once
15 Mal oder für ein schönes Bild:Die Verwendung von require_once () wirkt sich technisch auf die Leistung aus, wenn diese Funktion 14 Mal ausgeführt wird, zusätzlich dazu, dass diese unnötigen Zeilen analysiert werden müssen. Mit nur 10 anderen häufig verwendeten Klassen mit diesem ähnlichen Problem könnten mehr als 100 Zeilen eines solchen sinnlosen sich wiederholenden Codes berücksichtigt werden.
Damit lohnt es sich wahrscheinlich, stattdessen
require("includes/helpers.php");
am Bootstrap Ihrer Anwendung oder Ihres Frameworks zu arbeiten. Da jedoch alles relativ ist, hängt alles davon ab, ob das Gewichthelpers
im Verhältnis zur Nutzungshäufigkeit der Klasse es wert ist, 15 bis 100 Zeilen zu sparenrequire_once()
. Aber wenn die Wahrscheinlichkeit, dass diehelpers
Datei bei einer bestimmten Anfrage nicht verwendet wird, keine ist,require
sollte sie auf jeden Fall in Ihrer Hauptklasse sein. Nachdemrequire_once
in jeder Klasse wird separat eine Verschwendung von Ressourcen.Die
require_once
Funktion ist bei Bedarf nützlich, sollte jedoch nicht als monolithische Lösung angesehen werden, die überall zum Laden aller Klassen verwendet werden kann.quelle
Das PEAR2-Wiki (sofern vorhanden) listete gute Gründe auf, um alle erforderlichen / eingeschlossenen Anweisungen zugunsten des automatischen Ladens aufzugeben , zumindest für den Bibliothekscode. Diese binden Sie an starre Verzeichnisstrukturen, wenn alternative Verpackungsmodelle wie Phar in Sicht sind.
Update: Da die im Web archivierte Version des Wikis augenfällig hässlich ist, habe ich die überzeugendsten Gründe unten kopiert:
quelle
Die
*_once()
Funktionen stat jedes übergeordnete Verzeichnis, um sicherzustellen, dass die Datei, die Sie einschließen, nicht mit der bereits enthaltenen übereinstimmt. Das ist ein Teil des Grundes für die Verlangsamung.Ich empfehle die Verwendung eines Tools wie Siege für das Benchmarking. Sie können alle vorgeschlagenen Methoden ausprobieren und die Antwortzeiten vergleichen.
Mehr
require_once()
dazu bei Tech Your Universe .quelle
Selbst wenn
require_once
undinclude_once
sind langsamer alsrequire
undinclude
(oder was auch immer Alternativen existieren könnten), sind wir über die kleinste Ebene der Mikro-Optimierung hier sprechen. Ihre Zeit wird viel besser damit verbracht, diese schlecht geschriebene Schleifen- oder Datenbankabfrage zu optimieren, als sich um so etwas zu kümmernrequire_once
.Nun könnte man ein Argument vorbringen, das
require_once
schlechte Codierungspraktiken zulässt, weil Sie nicht darauf achten müssen, Ihre Includes sauber und organisiert zu halten, aber das hat nichts mit der Funktion selbst und insbesondere nicht mit ihrer Geschwindigkeit zu tun .Natürlich ist das automatische Laden aus Gründen der Code-Sauberkeit und der Wartungsfreundlichkeit besser, aber ich möchte klarstellen, dass dies nichts mit Geschwindigkeit zu tun hat .
quelle
Sie testen mit include die Alternative von oli und __autoload (); und testen Sie es mit etwas wie APC installiert.
Ich bezweifle, dass die Verwendung von Konstanten die Dinge beschleunigen wird.
quelle
Ja, es ist etwas teurer als einfach erforderlich (). Ich denke, der Punkt ist, wenn Sie Ihren Code so organisiert halten können, dass keine Includes dupliziert werden, verwenden Sie nicht die Funktionen * _once (), da Sie dadurch einige Zyklen sparen.
Die Verwendung der Funktionen _once () wird Ihre Anwendung jedoch nicht beenden. Verwenden Sie es im Grunde genommen nicht als Ausrede, um Ihre Includes nicht organisieren zu müssen . In einigen Fällen ist die Verwendung immer noch unvermeidlich und keine große Sache.
quelle
Ich denke, in der PEAR-Dokumentation gibt es eine Empfehlung für require, require_once, include und include_once. Ich folge dieser Richtlinie. Ihre Bewerbung wäre klarer.
quelle
Es hat nichts mit Geschwindigkeit zu tun. Es geht darum, anmutig zu scheitern.
Wenn require_once () fehlschlägt, ist Ihr Skript fertig. Sonst wird nichts verarbeitet. Wenn Sie include_once () verwenden, versucht der Rest Ihres Skripts, das Rendern fortzusetzen, sodass Ihre Benutzer möglicherweise nicht wissen, was in Ihrem Skript fehlgeschlagen ist.
quelle
Meine persönliche Meinung ist, dass die Verwendung von require_once (oder include_once) eine schlechte Praxis ist, da require_once für Sie prüft, ob Sie diese Datei bereits aufgenommen haben, und Fehler von doppelt eingeschlossenen Dateien unterdrückt, die zu schwerwiegenden Fehlern führen (wie doppelte Deklaration von Funktionen / Klassen / etc.) .
Sie sollten wissen, ob Sie eine Datei einfügen müssen.
quelle