PDA

Vollständige Version anzeigen : require_once vs. autoload


Marco
13.09.2008, 14:47
Hallo,

ich wollte mal fragen, wer von euch eher require_once oder den
autoLoad-Mechanismus benutzt.

Ich wollte schon anfangen alles auf require_once umzuschreiben, als mir klar
wurde, dass ich bei Unittests auch einfach den autoload aktivieren kann.

Ausser ein bisschen mehr Performance sehe ich sonst keinen Vorteil bei
require_once.

Irre ich mich vielleicht?

gruß marco

KingCrunch
13.09.2008, 15:00
Fraktion "require_once".

Ich stütze mich dabei eigentlich immer auf die Aussage aus dem Hanbuch im Abschnitt Zend_Loader (http://download.serienjunkies.org/f-c311e5c30f38a372/rc_Space-2063-Ep23.html)Zend_Loader vs. require_once()

The Zend_Loader methods are best used if the filename you need to load is variable. For example, if it is based on a parameter from user input or method argument. If you are loading a file or a class whose name is constant, there is no benefit to using Zend_Loader over using traditional PHP functions such as require_once().

Ausser ein bisschen mehr Performance sehe ich sonst keinen Vorteil zu require_once.Ich sehe auch den Performance-Vorteil nicht. Eigentlich sollte es nur zu einem Vorteil kommen, wenn oft die selben Klassen geladen werden, also wenn require_once() zu oft fehl schlägt. Der Autoloader reagiert sowieso nur, wenn eine Klasse fehlt. Dann aber wiederum macht er schon eine ganze Menge, was bei der Verwendung vieler unterschiedlicher Klassen zum Tragen kommt. Der Unterschied liegt also darin, dass require_once() immer reagiert, dann aber nativ (in C) und nur auf Dateibasis, während der Autoloader nur reagiert, wenn die Klasse wirklich fehlt, dann aber auf Software-Basis (PHP) und zudem muss erstmal der Klassenbezeichner auf den Dateinamen umgeschrieben werden.

Ab welchen Hit-Miss-Verhältnis der Vorteil von require_once() gegenüber dem Autoloader kippt, ist fraglich. Hinzu kommt noch, dass man mit etwas denken auch sicherlich viele require_once()-Aufrufe einsparen kann. Als Extrembeispiel: Innerhalb eines Kontrollers ist der Aufrufrequire_once('Zend/Controller/Front.php');quatsch, denn ohne Front-Kontroller kommt man garnet bis zum Action-Kontroller. Da gibt es sicherlich noch einiges Optimierbares ;)

Mal abgesehen vom Spruch aus dem Manual ("The Zend_Loader methods are best used if the filename you need to load is variable.") ist es einfach sehr bequem und ein wenig Java-Like den Autoloader zu verwenden. Andere Vorteile sehe ich wiederum nicht ;)

Akido
13.09.2008, 15:02
also ich benutz (eher aus Faulheit) den Autoloader von Zend.
andere Vorteile als Performance sind mir auch nicht bekannt.

Solange die Applikationen eine gewisse Größe nicht überschreiten werd ich auch beim Autoload bleiben.

Marco
13.09.2008, 16:00
Äh, sorry es sollte
"Ausser ein bisschen mehr Performance sehe ich sonst keinen Vorteil bei
require_once" heissen.

Also das require_once immer schneller ist, da keine Verzeichnisstruktur vom Namen
abgeleitet werden muss.

Ich nutz bisher auch immer den Autoloader egal bei welcher Größe. Finde es auch
nicht schön im Code, wenn man immer require_once schreiben muss...

KingCrunch
13.09.2008, 16:08
Also das require_once immer schneller ist, da keine Verzeichnisstruktur vom Namen
abgeleitet werden muss.Das es immer schneller ist, habe ich versucht etwas zu relativieren.
require_once ('My/Class.php');
$class = new My_Class();Die erste Zeile schaut immer nach, ob genannte Datei bereits geladen wurde, die zwei Zeile schaut immer nach, ob die Klasse existiert. Der Autoloader hat hier den kleinen Vorteil, dass es die Prüfung der zweiten Zeile nutzt, um im Zweifelsfall den Autoloader aufzurufen, für alle anderen Fälle spart er sich die erste Zeile.

Ich nutz bisher auch immer den Autoloader egal bei welcher Größe. Finde es auch
nicht schön im Code, wenn man immer require_once schreiben muss...Java-Like eben ;) Die Übersichtlichkeit ist natürlich auch ein Punkt, den ich im anderen Beitrag unterschlagen habe :X

Blackflash
13.09.2008, 18:15
Autoloader, aufgrund folgender Gründe:

Bessere Performance: Lookups, ob Dateien bereits reingeladen wurden, sind bei APC (von anderen Opcode-Caches kann ich nicht sprechen) teuer; die Tatsache, dass exzessive Nutzung von require_once gemacht wird und dass das Transformieren des Klassennamens nur einmal gemacht werden muss, sollte eine eindeutige Tendenz sein.
Schnellere Entwicklungszeit, da man sich nicht mehr um das Laden der Klassen kümmern muss.
Robuster, da die Wahrscheinlichkeit, dass die Applikation aufgrund einer fehlenden require-Anweisung nicht mehr funktioniert, reduziert wird.Es gibt natürlich auch Nachteile an dem Einsatz, aber für mich überwiegen klar die Vorteile.

KingCrunch
13.09.2008, 18:32
OK, der Kampf ist damit eröffnet :D
Bessere Performance: Lookups, ob Dateien bereits reingeladen wurden, sind bei APC (von anderen Opcode-Caches kann ich nicht sprechen) teuer; die Tatsache, dass exzessive Nutzung von require_once gemacht wird und dass das Transformieren des Klassennamens nur einmal gemacht werden muss, sollte eine eindeutige Tendenz sein.Einmal frag ich mich hier, ob die Lookups wirklich ins Gewicht fallen. Zudem erwähnte ich schon, das es sicherlich genug Fälle gibt, in dem ein require_once zwar semantisch notwendig wäre, aber aus Gründen der Logik (A kommt vor B) darauf verzichtet werden kann.
Schnellere Entwicklungszeit, da man sich nicht mehr um das Laden der Klassen kümmern muss.Nen Einzeiler :D
Robuster, da die Wahrscheinlichkeit, dass die Applikation aufgrund einer fehlenden require-Anweisung nicht mehr funktioniert, reduziert wird.Also "nicht mehr" kann man pauschal ausschließen ;) Entweder es funktioniert von vornherein nicht, oder der Fall kann nicht eintreten. Setzt natürlich voraus, dass man seine Anwendung hin und wieder testet :)

ice-breaker
13.09.2008, 20:40
Autoload kann schneller sein muss aber nicht, es funktioniert nach folgendem Muster:

Autoload schaut nach einer Datei einmal wenn die Klasse benötigt wird, damit ist es schneller als wenn jede Datei, die Klasse XYZ nutzt, das require_once sich ansehen muss und schaut ob die refernzierte Datei genau die ist, die schon geparsed wurde.

Sollte man einen Opcode Cache verwenden, dann ist require_once schneller, denn die Opcode Caches sind noch nicht für autoloading optimiert worden, da das wohl ein nicht ganz trivialler Fall ist.

Aber die Performance über die wir sprechen ist ja sowieso nicht soviel, ich fahre da 2 gleisig, einerseits zb mein Bootstrap lasse ich alles manuell includen, weil der Block ist quasi statisch, und in den Controllern lasse ich es dann über Autoloading machen, da dort seltener etwas nachgeladen wird.

Blackflash
13.09.2008, 23:56
Einzeiler oder nicht - auch Kleinvieh macht Mist. Ob ich 10 require-Anweisungen schreiben muss oder keine ist schon ein Unterschied. Außerdem lässt sich der Code viel leichter per Hand debuggen.

Die Lookups fallen ins Gewicht, ansonsten hätte ich keine 100%ige Steigerung an Performance geschafft (es handelte sich um eine Hello World-Anwendung), nachdem ich alle require_once-Anweisungen entfernt hatte. Ich weiß, dass du das "Benchmark" als nicht-repräsentativ abstempeln wirst, aber nichtsdestotrotz hat es mich persönlich überzeugt.

Im Endeffekt ist es mir einfach zu aufwändig require_once zu benutzen und der Performance-Gewinn (den ich "merkwürdigerweise" in meinen Anwendungen erlebe) ist für mich nur ein verstärkender Faktor.

KingCrunch
14.09.2008, 12:48
Einzeiler oder nicht - auch Kleinvieh macht Mist. Ob ich 10 require-Anweisungen schreiben muss oder keine ist schon ein Unterschied. Außerdem lässt sich der Code viel leichter per Hand debuggen.Debuggen, neija, gerade die Fehlermeldungen von require_once und Konsorten sind sehr eindeutig. Aber es geht ja nicht um 10 oder 0 Zeilen, es geht eher um 10 oder 20(+) Zeilen, mindestens die Instanzierung, aber meist will man das Objekt ja noch verwenden ;) Da wird das Kleinvieh noch etwas unbedeutender :)

Marco
14.09.2008, 13:15
K, prima, danke. Jetzt kann ich wieder gut schlafen :)

Ich dachte ja ich brauch die für Unittests und hab schon angefangen "nachzurüsten".
Habe mittlerweile alle require_once wieder gelöscht.

Gott sei Danke!!!


edit: //
Obs jetzt require_once schneller ist als AutoLoad weiss ich jetzt immer noch nicht, ist ja eig.
auch egal. Aber ich meinte in Erinnerung zu haben, das ich mal beim Profiling gesehen habe
das Autoload langsamer in der Summe war. - aber egal - , oder? :D

Blackflash
14.09.2008, 13:34
Zum eigentlich Thema: Weniger Code, weniger Fehlermöglichkeiten. ;-)

Zur Performance: Ich kenne nicht die Ursachen, weshalb der Autoloader bei mir schneller war. Möglicherweise lag es daran, dass ich die gesamten require_*-Anweisungen entfernt habe und im Autoloader lediglich das Format geparst und die gewünschte Datei inkludiert (via include) habe. Die *_once-Funktionen brauchen deutlich länger zum Laden. Im Endeffekt kenne ich allerdings nicht die Hintergründe für dieses Verhalten und möchte ausdrücklich darauf hinweisen, dass das __meine__ Erfahrungen sind.

ice-breaker
14.09.2008, 14:55
Also wie gesagt ist die Performance bei beiden sehr gleich ;)
Autoload ist ohne Opcode Cache schneller, mit Opcode cache wird es jedoch langsamer sein, da das autoloading von APC zB nicht unterstützt wird.

In wieweit ein Opcode cache nun aber noch mit dynamischen includes (keine festen statements sondern mit Variablen) wie der Einbindung der Action-Controller umgehen kann und welche Phänomene da auftreten, weiß ich jedoch nicht, meine Vermutung möchte ich da auch nicht kundtun, da es sich irgendwo im Kopf festsetzen könnte. Schaden kann mit einem Opcode cache an MARKANTEN stellen das manuelle includen nicht, zb in der Bootstrap oder in selbst geschriebenen librarys um die hard dependencies zu laden.

Solange man keine hochfrequentierte Anwendung wie Facebook oder Google hat, denke ich wird der unterschied zwischen Autoload und require_once nichts ausmachen. Sollte man doch eine kleine Serverfarm haben und dann einen Opcode Cache einsetzen (was dringend notwendig ist) sollte man sich über den Sachverhalt von require_once vs autoload mit OpCode Caches nochmal informieren.

Marco
14.09.2008, 15:06
ok, ich hat wahrsh. nen cache am laufen, desw. war require_once schneller

ice-breaker
14.09.2008, 15:12
ok, ich hat wahrsh. nen cache am laufen, desw. war require_once schneller
sehr wahrscheinlich

KingCrunch
14.09.2008, 15:36
Autoload ist ohne Opcode Cache schneller, mit Opcode cache wird es jedoch langsamer sein, da das autoloading von APC zB nicht unterstützt wird.Unabhängig von Cache oder nicht Cache schaut PHP bei Instanzierung nach der Klasse. Findet er sie, passiert nix weiter, findet er sie nicht, wird der Autoloader aufgerufen, der allerdings natürlich auch gecachet wird. Wie Blackflash schon meinte ist dann der einzige Unterschied der Filename-Lookup.

Blackflash
14.09.2008, 16:04
Also wie gesagt ist die Performance bei beiden sehr gleich ;)
Autoload ist ohne Opcode Cache schneller, mit Opcode cache wird es jedoch langsamer sein, da das autoloading von APC zB nicht unterstützt wird.

In diesem Fall nicht, da die ständigen Aufrufe von require_once sehr teuer sind (zumindest meiner Erfahrung mit APC nach). Mal abgesehen von einem (hoffentlich) sprachlichen Fehler: Autoload muss zwingend mit Opcode-Cache schneller sein als ohne, ansonsten hat ein Opcode-Cache keine Daseinsberechtigung.

Allerdings habe ich ein wenig recherchiert und weiß nun, was du damit meinst:


<arnaud_> does autoload have a performance impact when using apc ?
<Rasmus_> it is slow both with and without apc
<Rasmus_> but yes, moreso with apc because anything that is autoloaded is pushed down into the executor
<Rasmus_> so nothing can be cached
<Rasmus_> the script itself is cached of course, but no functions or classes
<Rasmus_> Well, there is no way around that
<Rasmus_> autoload is runtime dependent
<Rasmus_> we have no idea if any autoloaded class should be loaded until the script is executed
<Rasmus_> top-level clean deps would speed things up a lot
<Rasmus_> it's not just autoload
<Rasmus_> it is any sort of class or function declaration that depends on some runtime context
<Rasmus_> if(cond) function foo...
<Rasmus_> if(cond) include file
<Rasmus_> where file has functions and classes
<Rasmus_> or heaven forbid: function foo() { class bar { } }
Quelle: http://pooteeweet.org/blog/538
Wenn eine Inklusion nicht vom Kontext abhängt, dann können z.B. Klassen und Funktionen direkt im Cache abgelegt werden (unter deren Namen). Sollte dies nicht der Fall sein, wird das Skript in Opcode transformiert und beim Autoload wird dann der Opcode des Skripts ausgeführt. Korrigiert mich, wenn ich falsch liegen sollte.

In wieweit ein Opcode cache nun aber noch mit dynamischen includes (keine festen statements sondern mit Variablen) wie der Einbindung der Action-Controller umgehen kann und welche Phänomene da auftreten, weiß ich jedoch nicht, meine Vermutung möchte ich da auch nicht kundtun, da es sich irgendwo im Kopf festsetzen könnte.

s.o., macht also keinen Unterschied zur Funktionsweise mit dem Autoloader.

Schaden kann mit einem Opcode cache an MARKANTEN stellen das manuelle includen nicht, zb in der Bootstrap oder in selbst geschriebenen librarys um die hard dependencies zu laden.

Bei Bibliotheken sind require-Statements angebracht um dem nicht-existierenden Standard zu genügen. ;-)

Solange man keine hochfrequentierte Anwendung wie Facebook oder Google hat, denke ich wird der unterschied zwischen Autoload und require_once nichts ausmachen. Sollte man doch eine kleine Serverfarm haben und dann einen Opcode Cache einsetzen (was dringend notwendig ist) sollte man sich über den Sachverhalt von require_once vs autoload mit OpCode Caches nochmal informieren.

Das muss noch unterstrichen werden, weil in den meisten Fällen sowieso die Datenbank der Flaschenhals ist.


Am schnellsten wird man sein, wenn man immer weiß, welche Klassen man benötigt und diese dann reinlädt. Die Grundlagen dafür sind in meinem Kopf bereits gelegt, aber das funktioniert nur, solange man von variablen Inkludierungen absieht.

Nachtrag: Ich habe endlich herausgefunden, weshalb *_once teurer ist.
[...]
2. Minimize your use of include_once/require_once. If you can clean
up your dependencies and your include tree such that there is no
question of double-inclusion anywhere everything will be much
happier. A redundant include is obviously going to waste useless
cycles, but even if you don't hit the redundant case, the _once
operations are optimized for the non-cached scenario and actually
calls open() on every file which makes sense without an opcode cache
because you are going to need the file opened, but with a cache you
are going to get the opcodes from the cache and this becomes a
useless extra open() syscall. [...]

Quelle: http://news.php.net/php.general/231433

deetee
15.09.2008, 09:10
Ich nutze nur require_once, da ich es einerseits so auch aus anderen Sprachen gewohnt bin, und zum anderen sehe ich so an einer zentralen Stelle im Code, welche Klassen genutzt werden. Das ist auch für andere Teammitglieder eine sehr nützliche Info, falls sich jemand mal in den Code einarbeiten muss, geht das schneller.

Blackflash
15.09.2008, 20:19
Falls man das Schema, nach dem die Klassen- bzw. Dateinamen aufgebaut sind, kennt, dürfte sich der Vorteil nivellieren.

KingCrunch
15.09.2008, 23:30
Falls man das Schema, nach dem die Klassen- bzw. Dateinamen aufgebaut sind, kennt, dürfte sich der Vorteil nivellieren.... was sogar bei Arbeit in Team in Form der API-Doc recht gewöhnlich ist ;) Den "zentrale Stelle"-Aspekt find ich auch nicht so gewichtig.

deetee
17.09.2008, 08:50
Es geht nicht nur darum den Source der Klasse zu finden, sondern sofort einen Überblick zu bekommen, welche Klassen in dieser Datei verwendet werden. Eine IDE wie Eclipse findet den Source dann schon automatisch (über das Kontextmenü), wenn man ihn für eine bestimmte Klasse sehen will.

KingCrunch
17.09.2008, 09:05
Programmiert man in OOP findet Eclise den Source auch so.

Blackflash
17.09.2008, 09:33
Wofür braucht man einen schnellen Überblick darüber, welche Klassen benötigt werden? Zum Verständnis muss ich sowieso in den Code reingehen und einen Überblick brauche ich nur, wenn ich den Teil ausgliedern will und das kommt in dem von mir geschriebenen Code i.d.R. nicht vor.

deetee
17.09.2008, 09:36
Man braucht ihn z.B., wenn man sich in ein Modul (im Sinne von einer Anwendung) einarbeiten möchte/muss und dafür sich evtl. eine Liste aller verwendeten Klassen erstellen möchte oder ein Klassendiagramm grob zeichnen.

Blackflash
17.09.2008, 09:45
Dafür würde ich ein Skript verwenden, welches das automatisch tut. Habe letztens zufälligerweise eines in phpillow (http://kore-nordmann.de/projects/phpillow/index.html) gefunden.
Auch wenn das Argument für mich weniger gewichtig ist, könnte es entscheidend sein, vor allem für Bibliothekn.

KingCrunch
17.09.2008, 10:08
Erinnert mich daran als mir letztens jemand erzählte er hätte mühselig eine Datenliste (wechselnde Trennzeichen) in CSV konvertiert. Als ich meinte "Hmm... Wärn 5 Zeilen Code" hat er sich auch nur gegen Kopf gehauen ;)

Insofern bleib ich dabei (was unerhört blieb, weil deetee mich ja nicht liest): Zu Verknüpfungen zwischen Dateien und Klassen finden sich in der Regel in der API-Doc mehr als ausreichend Informationen. Wenn mans irgendwo in Source reinschreibt, steigert das zwar dort (!) die Übersicht, ist aber völlig unnötig.

Die direkte Vererbung findet sich sowieso im Vererbungsbaum wieder
Verwendungsszenarien lassen sich problemlos per @uses in den Class- bzw Method-/Function-Level-Docblock einbinden. Das hat zudem den Vorteil, dass beim betroffenen Element gleich ein @usedby eingefügt wird, was so einfach über die includes nicht lösbar ist.
Abhängigkeiten der Exceptions werden durch @throws klar erkenntlich.
Für Sonstiges gibt es dann noch @see bzw @link.

Ich bleib dabei: Es mag übersichtlicher sein, wenn man die Abhängigkeiten direkt nachstellt, aber es ist nunmal unnötig und zudem is die API-Doc auch auffällig bequemer ;) Sie hat zudem den Vorteil, dass sie die Abhängigkeiten in beide Richtungen widerspiegelt.

Fazit: Includes haben einige Vorteile, aber die Übersicht gehört nicht unbedingt dazu.


Btw, damit keine Verwirrung auftauchen: Mit "Includes" mein ich alle Ladevorgänge (require(_once) und include(_once)). Wurd mir nur zu doof das jedes mal so auszuformulieren :D

deetee
17.09.2008, 11:06
Dafür würde ich ein Skript verwenden, welches das automatisch tut. Habe letztens zufälligerweise eines in phpillow (http://kore-nordmann.de/projects/phpillow/index.html) gefunden.
Auch wenn das Argument für mich weniger gewichtig ist, könnte es entscheidend sein, vor allem für Bibliothekn.
Ein Skript bemühen ist immer so ne Sache. Außerdem lernt man schneller, wenn man sich die Struktur selbst "hinschmiert" anhand der extends und implements, sowie die includes eben. Anahnd dieser Infos ist schnell eine grobe Struktur erkennbar und man bekommt einen Überblick, Schritt für Schritt und so tief man eben möchte.

Autoloading mag verführerisch klingen, und wer allein arbeitet oder sicher sein kann, dass sein Code/Struktur/Anwendung niemals von Dritten nachvollzogen werden muss, der spart sich mit Autoloading sicher Arbeit.

Aber für Anwendungen, die auch von Dritten irgendwann mal verstanden werden sollten, sei es zwecks Weiterentwicklung, etc., sollte es m.E. zum Coding Standard gehören Klassen einzeln zu inkludieren. Man erleichtert anderen die Einarbeitung und erspart somit Zeit. Und Zeit ist ein wesentlicher Faktor.

Akido
17.09.2008, 11:46
ganz ehrlich?

wenn ich ein Projekt für einen Kunden umsetze, dann achte ich grundsätzlich nicht darauf dass andere da schnell durchsteigen - vor allem die hochqualifizierten **hammer Programmierer mit ihren Dumpingpreisen welche sogar das Urheberrecht übertragen sollten daran kein Problem finden :D... aber das ist eine andere Baustelle!

Ne, ich lösche bei Übergabe (wenn nicht anders vereinbart) die komplette Doku aus der Anwendung. Wenn sich der kunde einen billigeren Programmierer suchen will bitte, dann ists nicht mein Problem.

Und wie Crunch schon geschrieben hat gibts nicht umsonst @uses, @usedby etc...
Sollte also noch jemand mitprogrammieren kann er das alles aus der Doku rauslesen - solange das Projekt nicht abgeschlossen ist ;)