php.de

Zurück   php.de > Webentwicklung > Software-Design

Software-Design Diskussionen auf Profi-Niveau: PHP Lösungen auf konzeptioneller Ebene

Antwort
 
LinkBack Themen-Optionen Thema bewerten
Alt 20.04.2010, 22:53  
Benutzer
 
Registriert seit: 20.11.2009
Beiträge: 91
PHP-Kenntnisse:
Fortgeschritten
Tidus befindet sich auf einem aufstrebenden Ast
Standard [Erledigt] __autoload() effizient verwenden

Hallo Zusammen,

lasst euch bitte nicht von vorne rein von dem Titel des Themas abschrecken.
Das Thema __autoload() ist hier schon ziemlich oft besprochen worden, wobei es meist um das Verständnis der Funktion an sich ging.

Bei meinem aktuellen Problem geht es aber nicht um das Verständnis der Funktion, sondern viel mehr, einen Weg zu finden, diese optimal zu verwenden.

Mir ist bewusst, dass es in dieser Richtung schon einige Lösungsansätze gibt. Aber vorerst möchte ich euch mal schildern wie es zu meiner gleich gestellen Fragen kommt.

Also wie viele von euch wissen, ist die __autoload() - Funktion, eine Interzeptor - Funktion, die automatisch aufgerufen wird, sobald ein Objekt einer Klasse mit dem "new"-Operator instanziiert werden soll, diese allerdings noch nicht deklariert ist. __autoload() bekommt also den Namen der aufgerufenen ( noch nicht deklarierten ) Klasse als Parameter und kann nun die entsprechende Klasse nachladen.

Dieses Muster findet man bereits in einigen Frameworks wieder. Viele dieser Lösungen sind sehr ähnlich. So löst das Zend - Framework das Problem so, das die Klassennamen Unterstriche enthalten, diese später durch slashes ersetzt werden und somit einen gültigen Pfad zur entsprechenden Klasse darstellen.

So, oder so ähnlich würde es aussehen:

PHP-Code:

$frontcontroller 
= new Zend_Controller_Front(); 
Aus dieser Klassenbezeichnung wird also:

Zitat:
Zend/Controller/Front.php
Dieser Lösungsansatz, ist mein persönlicher Favorit. Nur gibt es hier eine Sache die mich gewaltig stört. Und zwar ist das die Bezeichnung der Klassen im Code.

Habe ich beispielsweise eine Ordnerstruktur die so aussieht:

Zitat:
/user/admin.php
und:

Zitat:
/user/teacher.php
Könnte ich diese beiden Dateien, oder eher die Klassen, die diese Dateien enthalten, nach Zend - Konventionen in dieser Form nachladen:

PHP-Code:

$admin 
= new User_Admin();

$teacher = new User_Teacher(); 
Diese Schreibweise macht den Code sicherlich nicht unleserlich, aber dennoch nicht sehr schön.

Nach weiteren Überlegungen dachte ich man könnte es folgendermaßen schöner machen:

Eine Instanziierung der Klasse Admin (für dieses Beispiel) würde so aussehen:

PHP-Code:

$user 
= new UserAdmin(); 
Die Unterstriche werden also einfach rausgelassen und der Klassenbezeichner im Code, entspricht dem Pfad der nach zuladenen Klasse im Camel Case format. Hier könnte man die __autoload() Funktion also mit regulären Ausdrücken ausstatten, die die Positionen der einzelnen Großbuchstaben ermittelt und zwischen diesen Vorkommnissen ( also User und Admin in diesem Beispiel) ein Slash setzen. Daraus würde dann wieder ein entsprechender Pfad erzeugt werden, der zum Nachladen der Klasse
genutzt werden kann.

Aber auch hier finde ich einige Punkte die mich Stören. Zum einen,
werden bei diesem Lösungsansatz die Klassenbezeichner im Code schwer leserlich, sobald die Ordnerstruktur zur entsprechenden Klasse mehr als 2 oder 3 Ordner betrifft.

So wird aus der Ordnerstruktur:

Zitat:
Db/Connection/MySql.php
Ein Klassenbezeichner der so aussehen würde:

PHP-Code:

$connection 
= new DbConnectionMysql(); 
Also in diesem Beispiel sind es nicht einmal 2-3 Ordner und trotzdem sieht die Klassenbezeichnung im Code sehr unschön aus. Hier würde ich zum Beispiel
die Zend - Konvention vorziehen, da aus dem oben genannten Pfad folgende Klassenbezeichnung entstehen würde:

PHP-Code:

$connection 
= new Db_Connection_MySql(); 
Ist meiner Meinung nach, die definitiv schönere Variante. Aber nun zurück zum eigentlichen Problem.

Ein weiterer Punkt der viele Probleme mit sich bringt, bei der Verwendung der Camel Case - Konvention ( ich nenne sie jetzt mal so ),
ist, dass die eigentlichen Dateinamen der Klassen auf nur einen ersten Großbuchstaben beschränkt sind.

Gut sichtbar ist dies in dem Beispiel von oben:

PHP-Code:

$connection 
= new DbConnectionMySql(); 
Das "Sql" beginnt ebenfalls mit einem Großbuchstaben, was bedeutet das also im Ordner "My" nach der Datei "Sql" gesucht werden würde.

So nun hab ich viel erzählt.

Meine Fragestellung ist folgende:

Ich würde mir wünschen Klassen ganz normal nach ihrem wirklichen Bezeichner zu instanziieren.

Das bedeutet also sowas wie:

PHP-Code:

$user 
= new Admin(); 
Die __autoload() - Funktion soll mir nun also diese Klasse im System suchen.
Problem ist hier natürlich, das __autoload() nicht weiß, wo sie suchen muss. Dieses Problem gibt es in dem obigen Beispielen nicht.

Ich suche also nach einer Lösung, eine __autoload() Funktion zu implementieren, die mir allein anhand des Klassenbezeichners, den ich auch aufrufe, die Entsprechende Klasse nachäd.

Dies ist ja so ohne weiteres nicht möglich, wenn __autoload() nicht weiß, wo sie nach der entsprechenden Klasse suchen soll.

Nun habe ich folgende Überlegungen zusammen getragen:

Es gibt eine Funktion scan_dir(). Diese listet Dateien und Ordner innerhalb eines übergebenen Pfades aus.

Angenommen, ich würde die __autoload() Funktion so implementieren, das sie mit scan_dir() mein Root verzeichnis nach einer Datei absucht, die genauso heißt wie der übergebene Parameter für __autoload(), und mir diese dann entsprechend nachläd.

Also:

PHP-Code:

$user 
= new Admin();

// Funktion __autoload() würde im gesamten Ordnersystem (oder auch nur einige Bereiche), nach Admin.php suchen und diese nachladen. 

Ist dieser Lösungsansatz eher ungewöhnlich ?

Gibt es dort nicht vielleicht doch den einen oder anderen Harken ?

Ich frage mich nämlich gleichzeitig, wenn das alles so ohne weiteres funktioniert, warum hab ich eine solche Art von Lösung noch nirgendwo anders gesehen ?


So ich glaub das wars soweit auch. Vielen Dank für jeden Rat im Voraus
Tidus ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 20.04.2010, 23:12  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 35.994
PHP-Kenntnisse:
Fortgeschritten
nikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunft
Standard

Auf Dateisystemfunktionen würde ich tunlichst verzichten! Autoloader sollten IMHO möglichst performant sein. Das ist bei Dateizugriffen nicht gegeben.

Für kleine Projekte (für große gälte sicher die gleiche Argumentation bzgl. Speicherbelegung), benutze ich einfach eine statische Registry.

PHP-Code:
Application::registerClass ('BA_PropertyFactory_VerzeinhExtId'    $sSubPath 'specific/ext_id/ext_id_verzeinh.php');
Application::registerClass ('BA_PropertyVerzeinhExtId'            $sSubPath 'specific/ext_id/ext_id_verzeinh.php'); 
Das gibt mir alle Freiheiten für Datei/Klassennamen (ich mag gerne sprechende Namen) und hat einen positiven Nebeneffekt: Ich kann diese Angaben Modulweise einbinden (per require, $sSubPath zeigt hier bspw. auf den Modulpfad, wie man sieht gehen auch zwei zusammengehörige Klassen in einer Datei) UND
Ich kann Klassendefinitionen überschreiben, indem ich einfach später eine erneute Zuweisung mit dem selben Schlüssel benutze.
__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--
nikosch ist gerade online   Mit Zitat antworten
Alt 20.04.2010, 23:14  
da schreibt der ElePHPant
 
Benutzerbild von Flor1an
 
Registriert seit: 18.06.2008
Beiträge: 8.903
PHP-Kenntnisse:
Fortgeschritten
Flor1an ist ein wunderbarer AnblickFlor1an ist ein wunderbarer AnblickFlor1an ist ein wunderbarer AnblickFlor1an ist ein wunderbarer AnblickFlor1an ist ein wunderbarer AnblickFlor1an ist ein wunderbarer AnblickFlor1an ist ein wunderbarer Anblick
Standard

Es gibt zwei Gründe dir mir spontan einfallen:

1. Die Performance. Jedes mal das komplette Dateisystem zu scannen würde wohl relativ lange dauern. Gerade wenn du mehrere Dateien einbinden musst und jedes mal das komplette System gescannt wird, dann sprengt das wohl irgendwann den Rahmen.

2. Namenskonflikte: Wie schnell passiert es dass du dann zwei Klassen hast die den selben Namen haben? Du darfst auf keinen Fall zwei gleiche Dateien haben. Zend/Db/Adapter/Abstract.php oder Zend/Form/Decorator/Abstract.php beide würden bei deinem autoloader auf die selbe Klasse "zeigen".

Ich find eigentlich die Namenkonventionen des Zend Frameworks sehr angenehm. Grade weil man weiß das _ einen Ordner bezeichnet und die Großbuchstaben dann beliebig im Klassennamen verwendet werden können wie eben MySQL oder HtmlTag.

Ansonsten kannst du dich ja mal mit den Namespaces in PHP 5.3.0 auseinander setzen. Vlt. kannst du dir damit was schönes basteln. Ich muss ehrlich sagen ich hab damit noch nicht gearbeitet und dementsprechend kenn ich auch keine "Musterlösungen". Müsste man mal sehen was man damit anstellen könnte. Falls du ne Lösung findest kannst du dich ja nochmal melden
Flor1an ist offline   Mit Zitat antworten
Alt 20.04.2010, 23:30  
Benutzer
 
Registriert seit: 20.11.2009
Beiträge: 91
PHP-Kenntnisse:
Fortgeschritten
Tidus befindet sich auf einem aufstrebenden Ast
Standard

Also ersteinmal vielen Dank für die Schnellen Antworten.

@Florian:

- Der Punkt mit der Performance ist gut. Jedesmal das Dateisystem nach nur einer Klasse abzusuchen ist auf Dauer ein langer Prozess, sobald das Dateisystem eine entsprechende Größe hat.

- Die Namenskonflikte würden in meinem Lösungsansatz ja eigentlich wegfallen, da ich nach der Datei anhand des Klassennamens suchen würde. Also wird es nicht dazu kommen, das ich zwei oder mehrere Dateien in meinem System habe, die beispielsweise Abstract.php heißen.

Bezüglich der Namespaces.. Ich habe heute ehrlich gesagt, den ganzen Tag damit verbracht eine saubere Lösung mit Namespaces zu konzipieren, nur scheiterte jeder Versuch. Da auch dort die Klassenbezeichnungen nicht mehr nur die einzelnen Namen der Klassen sind, sondern die dazu gehörigen Namespaces vor den Klassenbezeichner geschrieben werden. Womit eine instanziierung einer Klasse auch nicht schön aussehen würde.

Aber vielen Danke das Argument mit der Performance überzeugt mich schon an ganzes Stück .

@nikosch:

- Also deine Lösung mit der Registry-class finde ich sehr gut. Sie bringt wirklich eine Menge Vorteile mit sich. Nur habe ich wohl vergessen zu erwähnen, das ich vor habe die nutzung von require_once oder include möglichst gering zu halten, wenn nicht sogar auf eine einmalige Verwendung zu reduzieren. Deswegen auch die Idee die __autoload() Funktion so zu Programmieren, das Sie mir alles an Klassen zurück geben kann, was ich grade so brauche.

Aber da wir ja eben schon den Punkt Dateizugriff und Performance hatten, muss ich sagen, das mich das schon sehr Überzeugt hat, von dem Lösungsansatz wegzulenken.


Nochmal vielen Dank für die Ratschläge

Gruß Tidus
Tidus ist offline   Mit Zitat antworten
Alt 20.04.2010, 23:46  
hpf
Benutzer
 
Registriert seit: 04.04.2010
Beiträge: 83
PHP-Kenntnisse:
Fortgeschritten
hpf befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von Tidus Beitrag anzeigen
Aber da wir ja eben schon den Punkt Dateizugriff und Performance hatten, muss ich sagen, das mich das schon sehr Überzeugt hat, von dem Lösungsansatz wegzulenken.
Du musst ja nicht bei jedem Scriptaufruf alle Verzeichniss scannen, sondern nur einmalig oder wenn neue Dateien hinzugekommen sind. Beim Scannen kannst du dir ein Array mit der Zuordnung Klassenname => Include-Datei erstellen und dieses dann serialisieren. Die Autoload-Funktion kann dieses Array dann wieder deserialisieren und hat so die Zuordnung.
hpf ist offline   Mit Zitat antworten
Alt 20.04.2010, 23:49  
Benutzer
 
Registriert seit: 20.11.2009
Beiträge: 91
PHP-Kenntnisse:
Fortgeschritten
Tidus befindet sich auf einem aufstrebenden Ast
Standard

Sorry dass ich hier noch mal anhänge...

@nikosch:

Ich hatte ebend eine statische Registry nur kurz überflogen. Wie sie letztendlich zu nutzen ist und was für Vorteile sie mit sich bringt ist ganz klar einleuchtend. Jetzt hätte ich allerdings noch eine Frage.

Du registrierst ja mit der statischen Methode registerClass($name, $value) die Klasse die du als Parameter $value (bzw. hier ist es ja der Pfad zur Datei) übergibst.

Aber das bedeutet ja, das jedesmal wenn du eine Klasse an einer bestimmten stelle brauchst, das du diese mit deiner registerClass() Methode erst einmal registrieren muss, damit du sie von da an anhand des Schlüssels als Klassenbezeichner instanziieren kannst. Das Bedeuted aber doch wiederum, das man dazu gezwungen ist, sämtliche Klassen, die grade gebraucht werden, händisch nachzuladen.

In deinem Fall, dass man sie registriert. Es sei denn, man registriert an einer Zentralen Stelle mit deiner Methode alle Klassen, was aber ja auch nicht unbedingt sinnvoll ist, da nicht immer alle Klassen gebraucht werden.

Ich hoffe ich habe die Funktionalität soweit richtig nachvoll ziehen können. Ich finde diese Lösung auch sehr gut. Nur der Punkt, das ich weiterhin händisch Klassen im Code nachladen muss, und dies nicht automatisch über die __autoload() Funktion passiert, ist mir weiterhin ein kleiner Dorn im Auge =/

Bei Missverständnissen meinerseits, bitte drauf aufmerksam machen.
Tidus ist offline   Mit Zitat antworten
Alt 20.04.2010, 23:55  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 35.994
PHP-Kenntnisse:
Fortgeschritten
nikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunft
Standard

Es bedeutet, dass ich sämtlich Klassen, die ich benötige „bekannt machen“ muss (eben registrieren), nicht aber, dass ich alle entspr. Files einbinden (require) muss. Ich halte das so, dass ich modulweise eine Datei erstelle (meinetwegen global.php im obersten Modulpfad) und dort dann alle Registrierungen notiere. Den Overhead für nicht benötigte Klassen nehem ich dabei in Kauf - wie gesagt, für Projekte mit tausenden Klassen ist das wahrscheinlich nicht mehr sinnvoll. Mir ist auch bewusst, dass dieses Prinzip nicht die Freiheit des „Modul reinkopieren und verwenden“ bieten kann.
Für den Core benutze ich übrigens ein zentrales File, das dann mehrere Core-Module umfasst.
__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--
nikosch ist gerade online   Mit Zitat antworten
Alt 20.04.2010, 23:55  
Benutzer
 
Registriert seit: 20.11.2009
Beiträge: 91
PHP-Kenntnisse:
Fortgeschritten
Tidus befindet sich auf einem aufstrebenden Ast
Standard

@hpf:

Vielen dank für deine Antwort.

Okay, das stimmt. Nur ab wann weiß mein System denn, das eine neue Klasse dazu gekommen ist, und ein neues Array mit den Pfaden erzeugt werden muss?

Das bedeutet, ich müsste bei jeder neuen Klasse mit das Array erweitern.

Diesen Ansatz habe ich bereits durchgekaut. Und halte ihn in der Hinsicht für ein wenig unflexibel, was die Automatisierung meines Problems angeht.

Für den Fall das ich dich falsch verstanden habe, korrigiere mich bitte.

Gruß Tidus
Tidus ist offline   Mit Zitat antworten
Alt 20.04.2010, 23:56  
Moderator
 
Benutzerbild von robo47
 
Registriert seit: 03.09.2004
Beiträge: 11.792
PHP-Kenntnisse:
Fortgeschritten
robo47 kann auf vieles stolz seinrobo47 kann auf vieles stolz seinrobo47 kann auf vieles stolz seinrobo47 kann auf vieles stolz seinrobo47 kann auf vieles stolz seinrobo47 kann auf vieles stolz seinrobo47 kann auf vieles stolz seinrobo47 kann auf vieles stolz sein
Standard

Betreffs einer kompletten Umsetzung mit Namespaces kannst du dir ja mal das hier anschauen:
PSR-0 Final Proposal - PHP Standards Working Group | Google Groups
implementierung in php 5.3:
gist: 221634 - GitHub

Das soll ein Standard werden auf den sich einige Frameworks und Projekte (Zend, Symfony, Drupal, Sonar, Lithium, Agavi, Cake, PEAR, Typo3/Flow3, phpBB ) einigen wollen um Code auch besser untereinander wiederverwendbar zu machen und bei der Nutzung von Code anderer Systeme nicht immer so einen Aufwand mit dem Autoloading zu haben.

Eventuell gibt es das ganze dann auch als PECL-Modul oder integration in die SPL:
-> SplClassLoader as a PECL extension - PHP Standards Working Group | Google Groups

Wenn du eh mit php 5.3+ arbeitest ist es ja auch kein problem deine Klasse einfach "Admin" zu nenen in den Namespace User zu packen und dann oben ein use User\Admin; oder use User\Admin as UserAdmin; zu machen, damit bist du im Quellcode selbst absolut frei die klasse zu nennen wie du willst und das autoloading passiert transparent über den ursprünglichen namen. Der aktuelle Autoloader des Zend Frameworks kann auch schon mit namespaces und php 5.3 umgehen.
robo47 ist offline   Mit Zitat antworten
Alt 20.04.2010, 23:57  
Benutzer
 
Registriert seit: 20.11.2009
Beiträge: 91
PHP-Kenntnisse:
Fortgeschritten
Tidus befindet sich auf einem aufstrebenden Ast
Standard

@nikosch

Okay verstehe. Damit hat sich diese Frage auch geklärt .

Vielen Dank

Gruß Tidus
Tidus ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Ergebnis von switch() in der Function verwenden ? ALiP PHP Tipps 2009 4 13.07.2009 17:04
Objekte in Objekten verwenden Cube PHP Tipps 2009 6 30.06.2009 16:18
[Erledigt] id als variabel verwenden. wie? ld_forester JavaScript, Ajax und mehr 4 29.08.2008 02:55
Variable aus Subselect in JOIN verwenden GSJLink Datenbanken 5 25.05.2008 11:36
Variablen in einer Funktion verwenden Smily0412 PHP Tipps 2006 3 24.09.2006 16:42
nuSoap mit document/literal verwenden vegeta PHP Tipps 2006 2 29.06.2006 12:49
<button> verwenden - wie unterscheiden??? Tigermoon PHP Tipps 2006 12 31.05.2006 11:44
Post- und Get-Methode gleichzeitig verwenden PHP Tipps 2007 50 07.12.2005 08:13
Instanz über mehrere Seiten verwenden? becks123 PHP Tipps 2005-2 3 22.08.2005 10:10
Mehrere SESSION verwenden? michi174 PHP Tipps 2005-2 4 22.06.2005 17:40
[Erledigt] $$var / ${$var} in preg_replace_callback() verwenden PHP Tipps 2005 8 20.04.2005 18:02
Grafiken als Rahmen verwenden?! CSS HTML, Usability und Barrierefreiheit 8 03.03.2005 20:49
musst man &uml; in meta tags verwenden? HTML, Usability und Barrierefreiheit 16 24.02.2005 17:50
blob verwenden (xtreme noob) Malfunction Datenbanken 9 03.02.2005 13:51
php und java script zusammen verwenden??? PHP Tipps 2005 6 14.01.2005 10:04

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
php __autoload, php autoload, __autoload, typo3 __autoload, php autoload mehrere ordner, php autoload performance, php autoload alle ordner durchsuchen, php gib alle deklarierten klassen aus, php autoload mehrere verzeichnisse, php autoload typo3, zend autoload überschreiben, php autoload windows, zend typo3 autoload, php __autoload function, neue autoloading php 5.3 namespaces, php autoload ordnerstruktur, php autoload abstract, __autoload(), wie zend in drupal einbinden, zend framework __autoload

Alle Zeitangaben in WEZ +2. Es ist jetzt 00:38 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum