Johannes3: include_path und __autoload gemeinsam nutzen

Hallo,

ist eine einfache, vielleicht auch blöde Frage. Funktioniert dies? Quasi, daß entweder zuerst die Pfade vom Include-Path abgeklappert werden und, wenn nix gefunden wird, __autoload greift bzw. umgekehrt, daß man, wenn nichts in Verzeichnissen, die von __autoload berücksichtigt werdeb, findet, an den Parser und include_path zurückdeligiert? Ich denke ja nicht, daß es geht, aber vielleicht gibt es ja doch etwas ähnliches!? Bitte keine Antworten wie "erweitere doch den include_path und verzichte auf __autoload". Das weiß ich auch selbst, daß das eine Möglichkeit ist, ich brauche aber was anderes.

  1. Hi,

    Quasi, daß entweder zuerst die Pfade vom Include-Path abgeklappert werden und, wenn nix gefunden wird, __autoload greift

    Wer soll abklappern?

    Damit der include-Pfad abgeklappert wird, müsste ja zunächst mal irgendsowas wie include o.ä. im Code stehen. Wenn das nichts findet, gibt's eine Meldung.
    Und erst dann soll autoload zum Zuge kommen ...?

    bzw. umgekehrt, daß man, wenn nichts in Verzeichnissen, die von __autoload berücksichtigt werdeb, findet, an den Parser und include_path zurückdeligiert?

    Wenn autoload nichts findet, dann hast du die Situation, dass eine Klasse benutzt werden soll, ohne das ihre Definition vorhanden ist - das muss auch schiefgehen.

    Ich denke ja nicht, daß es geht, aber vielleicht gibt es ja doch etwas ähnliches!? Bitte keine Antworten wie "erweitere doch den include_path und verzichte auf __autoload". Das weiß ich auch selbst, daß das eine Möglichkeit ist, ich brauche aber was anderes.

    Dann beschreibe bitte erst mal *nachvollziehbar*, *was* du eigentlich brauchst. Mir ist nicht klar, welche Fälle du abdecken willst und warum.

    Wenn du __autoload verwendest, dann steht in der Funktion, die du angibst, doch wohl ein include/require drin - und das durchsucht dann auch den include_path.
    Ich verstehe nicht, welches "extra" du da jetzt noch haben willst.

    MfG ChrisB

    --
    Light travels faster than sound - that's why most people appear bright until you hear them speak.
    1. Hi,

      ich habe nicht immer Zugriff auf die php.ini, um alle Pfade für Klassen einzutragen. Jedes Mal um die Erweiterung des include_path betteln will ich nicht, zudem wäre das auch gar nicht sinnvoll, weil es sehr, sehr viele Projekte gibt und der include_path bald nicht mehr überschaubar wäre. Deswegen habe ich mir anfangs mit __autoload beholfen, das nacheinander (je nach Projekt auch unterschiedliche) Verzeichnisse auf Existenz einer Klasse untersucht. Das ist nett, weil es includes in den Skripten spart, die Klassen stehen einfach zur Verfügung.

      Nun möchte ich aber zum einen Klassen aus PEAR benutzen, zum anderen während der Entwicklung gemeinsam benutzte Verzeichnisse über den include_path nutzen. Manche Klassen in PEAR - abgeleitete - nutzen selbst includes, und zwar relative bzw. gar nicht näher bestimmte, weil sie auf den include_path vertrauen. Dummerweise habe ich (noch) keinen eigenen Entwicklungshost, d .h., Entwicklungsumgebung und Produktivumgebung sind nur unterschiedliche Verzeichnisse, allerdings besteht die Produktivumgebung wiederum aus mehreren vhosts (einen teilen sich eine Produktivumgebung und die Entwicklungsumgebung).

      So, wenn ich das richtig sehe, wird ein include 'irgendwas' (das aus Verzeichnis a, welches im include_path eingetragen ist); new irgendwas nicht irgendwas instantiieren, sondern __autoload aufrufen, was natürlich in b, c oder d irgendwas nicht findet, weil es ja in a ist. Also muß ich selbst in __autoload nach irgendwas in a suchen, und das möchte ich nicht. Es wäre mir recht, wenn das include 'irgendwas' aus a; new irgendwas erkennt bzw. zuerst den include_path durchgeht, daß die Klasse geladen ist bzw. aus a im inc_path geladen werden soll und nicht __autoload aufruft. Erst wenn irgendwas nicht irgendwo in den Pfaden des inc_path gefunden wird, soll __autoload zum Zug kommen, daß dann erkenn, daß irgendwas_anderes in b oder c liegt und es von dort aus includet werden muß.

      Hoffe, ist jetzt so etwas klarer geworden, weiß ich meine.

      1. Hi,

        ich habe nicht immer Zugriff auf die php.ini, um alle Pfade für Klassen einzutragen. Jedes Mal um die Erweiterung des include_path betteln will ich nicht, zudem wäre das auch gar nicht sinnvoll, weil es sehr, sehr viele Projekte gibt und der include_path bald nicht mehr überschaubar wäre.

        include_path ist PHP_INI_ALL konfigurierbar.

        Nun möchte ich aber zum einen Klassen aus PEAR benutzen, zum anderen während der Entwicklung gemeinsam benutzte Verzeichnisse über den include_path nutzen.

        D.h. also, *nach* der Entwicklung wird die Pfadstruktur anders aussehen?

        Das Entwicklungs-/Testsystem immer möglichst nahe am Produktivsystem zu halten, ist eigentlich immer sinnvoll.
        Hier könnten evtl. auch symbolische Links helfen, an einem Ort gelagerte Dateien für mehrere Projekte unter "individuellen" Pfaden bereitzustellen.

        So, wenn ich das richtig sehe, wird ein include 'irgendwas' (das aus Verzeichnis a, welches im include_path eingetragen ist); new irgendwas nicht irgendwas instantiieren, sondern __autoload aufrufen, was natürlich in b, c oder d irgendwas nicht findet, weil es ja in a ist. Also muß ich selbst in __autoload nach irgendwas in a suchen, und das möchte ich nicht. Es wäre mir recht, wenn das include 'irgendwas' aus a; new irgendwas erkennt bzw. zuerst den include_path durchgeht, daß die Klasse geladen ist bzw. aus a im inc_path geladen werden soll und nicht __autoload aufruft.

        Hier hoffe ich nur, dass du in deinen Projekten strukturierter arbeitest, als du hier mit Sprache umgehst.
        Sorry, kaum ein Wort verstanden von dem Kauderwelsch.

        MfG ChrisB

        --
        Light travels faster than sound - that's why most people appear bright until you hear them speak.
        1. Hi!

          Hi,

          »» ich habe nicht immer Zugriff auf die php.ini, um alle Pfade für Klassen einzutragen. Jedes Mal um die Erweiterung des include_path betteln will ich nicht, zudem wäre das auch gar nicht sinnvoll, weil es sehr, sehr viele Projekte gibt und der include_path bald nicht mehr überschaubar wäre.

          include_path ist PHP_INI_ALL konfigurierbar.

          Dann müßte ich dennoch gemeinsam genutzte Pfade wieder bei jedem Projekt per ini_set setzen, dann kann ich es auch gleich in der __autoload abhandeln.

          »» Nun möchte ich aber zum einen Klassen aus PEAR benutzen, zum anderen während der Entwicklung gemeinsam benutzte Verzeichnisse über den include_path nutzen.

          D.h. also, *nach* der Entwicklung wird die Pfadstruktur anders aussehen?

          Ja, definitiv komplett anders, zumindest was Klassenverzeichnisse und das Applikationswurzelverzeichnis betrifft. Das alles wird auch schon in Konfig-Dateien berücksichtigt.

          Das Entwicklungs-/Testsystem immer möglichst nahe am Produktivsystem zu halten, ist eigentlich immer sinnvoll.

          Schon, aber ich habe da wenig Einfluß und muß mit dem Vorlieb nehmen, was ich vorfinde.

          Hier könnten evtl. auch symbolische Links helfen, an einem Ort gelagerte Dateien für mehrere Projekte unter "individuellen" Pfaden bereitzustellen.

          Damit kenne ich mich zu wenig aus. Kannst Du das deutlicher beschreiben, inwiefern man die nutzen kann?

          »» So, wenn ich das richtig sehe, wird ein include 'irgendwas' (das aus Verzeichnis a, welches im include_path eingetragen ist); new irgendwas nicht irgendwas instantiieren, sondern __autoload aufrufen, was natürlich in b, c oder d irgendwas nicht findet, weil es ja in a ist. Also muß ich selbst in __autoload nach irgendwas in a suchen, und das möchte ich nicht. Es wäre mir recht, wenn das include 'irgendwas' aus a; new irgendwas erkennt bzw. zuerst den include_path durchgeht, daß die Klasse geladen ist bzw. aus a im inc_path geladen werden soll und nicht __autoload aufruft.

          Hier hoffe ich nur, dass du in deinen Projekten strukturierter arbeitest, als du hier mit Sprache umgehst.
          Sorry, kaum ein Wort verstanden von dem Kauderwelsch.

          Eigentlich helfen die Antworten von Tom und Sven schon weiter bzw. beantworten die Frage, aber hier noch mal eine weniger "hingeschmierte" Beschreibung:

          Ein oder mehrere Verzeichnisse, nennen wir eins davon A, enthalten gemeinsam von mehreren Projekten benutzte Klassen. Dieses sollte daher im inc_path aufgeführt sein. Projekte benutzen darüber hinaus projektspezifische Klassenverzeichnisse, nennen wir sie B und C.

          Anforderung für die Entwicklung ist, daß zunächst A vom Parser durchsucht wird, wird er nicht fündig, überläßt er die weitere Suche der __autoload, die die projekteigenen Klassenverzeichnisse durchsucht.

          Soweit die Entwicklungsumgebung. In der Produktivumgebung sollte es gerade umgekehrt laufen. Zunächst werden die projektspezifischen Verzeichnisse durchsucht, danach das oder die allgemeinen Klassenverzeichnisse. Der Sinn ist, daß Projekte zu einem bestimmten Zeitpunkt mit bestimmten Versionen von Klassen laufen, während es offenbleiben soll, die Klassen zu ändern, ohne daß dadurch ältere Projekte nicht mehr laufen. Dazu werden, sobald eine Applikation als fertig befunden wurde, die Klassen aus dem allgemeinen Klassenverzeichnis in der Entwicklungsumgebung jeweils in projekteigenen Verzeichnisse innerhalb der Produktivumgebung kopiert. Versionierung kann ich leider auch nicht benutzen, deswegen dieser Weg.

          1. Hi,

            Anforderung für die Entwicklung ist, daß zunächst A vom Parser durchsucht wird, wird er nicht fündig, überläßt er die weitere Suche der __autoload, die die projekteigenen Klassenverzeichnisse durchsucht.

            Wenn man den include_path für jedes Projekt separat definiert, kann man dort doch zunächst A angeben, und dann anschliessend noch die jeweils projektspezifischen Verzeichnisse.

            Soweit die Entwicklungsumgebung. In der Produktivumgebung sollte es gerade umgekehrt laufen. Zunächst werden die projektspezifischen Verzeichnisse durchsucht, danach das oder die allgemeinen Klassenverzeichnisse.

            Dann definiert man in der produktiven Umgebung die include_path jeweils umgekehrt.

            Das stellt natürlich eine potentielle Fehlerquelle dar - aber wenn man das klar dokumentiert (insb. den Anpassungsprozess des include_path bei der Produktivsetzung) und dabei ein festes Muster streng einhält, halte ich das für nicht allzu kritisch.

            Aber um auch dieses Risiko zu vermeiden, ist der andere Weg vielleicht doch der bessere:

            Hier könnten evtl. auch symbolische Links helfen, an einem Ort gelagerte Dateien für mehrere Projekte unter "individuellen" Pfaden bereitzustellen.

            Damit kenne ich mich zu wenig aus. Kannst Du das deutlicher beschreiben, inwiefern man die nutzen kann?

            Wenn im Testsystem die Dateien für alle Projekte unter
            /xyz/a/
            liegen, und später aber jeweils individuell unter
            /xyz/project1/b/
            /xyz/project2/c/
            /xyz/project3/d/
            liegen werden - dann könnte man auf dem Testsystem doch schon Symlinks einrichten, die die "Pseudo-Verzeichnisse" /xyz/project1/b/, /xyz/project2/c/ und /xyz/project3/d/ simulieren, und alle auf /xyz/a/ zeigen lassen.

            Der Sinn ist, daß Projekte zu einem bestimmten Zeitpunkt mit bestimmten Versionen von Klassen laufen, während es offenbleiben soll, die Klassen zu ändern, ohne daß dadurch ältere Projekte nicht mehr laufen. Dazu werden, sobald eine Applikation als fertig befunden wurde, die Klassen aus dem allgemeinen Klassenverzeichnis in der Entwicklungsumgebung jeweils in projekteigenen Verzeichnisse innerhalb der Produktivumgebung kopiert.

            Dann erscheint mir eine Lösung mit Symlinks noch attraktiver. Den Projekten wird schon während der Entwicklung ein eigenes Projektverzeichnis "vorgegaukelt", das im Hintergrund auf das gemeinsame Verzeichnis "umgelenkt" wird. Die Projekte selber "merken" gar nichts davon, dass sie sich in dieser Phase noch aus einem gemeinsamen Verzeichnis "bedienen".

            MfG ChrisB

            --
            Light travels faster than sound - that's why most people appear bright until you hear them speak.
            1. Hallo

              Hi,

              Wenn man den include_path für jedes Projekt separat definiert, kann man dort doch zunächst A angeben, und dann anschliessend noch die jeweils projektspezifischen Verzeichnisse.

              Schon, aber dann muß ich ja auch wieder jeweils A für jedes Projekt definieren. Ich dachte an eine Möglichkeit, dieses eine Verzeichnis wirklich einmalig in der php.ini einzutragen, so daß es dann immer direkt allen Projekten zur Verfügung steht.

              »

              Aber um auch dieses Risiko zu vermeiden, ist der andere Weg vielleicht doch der bessere:

              »» > Hier könnten evtl. auch symbolische Links helfen, an einem Ort gelagerte Dateien für mehrere Projekte unter "individuellen" Pfaden bereitzustellen.
              »»
              »» Damit kenne ich mich zu wenig aus. Kannst Du das deutlicher beschreiben, inwiefern man die nutzen kann?

              Wenn im Testsystem die Dateien für alle Projekte unter
              /xyz/a/
              liegen, und später aber jeweils individuell unter
              /xyz/project1/b/
              /xyz/project2/c/
              /xyz/project3/d/
              liegen werden - dann könnte man auf dem Testsystem doch schon Symlinks einrichten, die die "Pseudo-Verzeichnisse" /xyz/project1/b/, /xyz/project2/c/ und /xyz/project3/d/ simulieren, und alle auf /xyz/a/ zeigen lassen.

              Diese Lösung scheint auch ein gangbarer Weg.

              Wie symbolische Links funktionieren, weiß ich ja, ich weiß nur leider nicht, wie ich sie praktisch umsetzen kann, sowohl was die Shell als auch was PHP betrifft.

              Ich erkläre mal kurz, wie ich Dich verstehe. Die Klassen kommen (in der Entwicklungsumgebung) nach /xyz/a/. In PHP selbst (mittels inc_path, ini_set etc.) greift man auf Dateien aus /xyz/projekt1/b/ zu. Dort liegen aber keine gewöhnlichen Dateien, sondern Links. Das merkt PHP selbst nicht, wohl aber das OS. Also müßte ich in /xyz/projekt/b// für jede Datei einen Link auf ein Pendant in xyz/a/ anlegen. Verstehe ich das soweit richtig?

              Der einzige Schritt, der getan werden muß, läge demnach gar nicht in der Programmierung mit PHP, sondern im Anlegen von symb. Links mittels Shell, ist das so richtig?

              Wenn das so wäre, würde das sogar noch ein anderes Problem lösen, nämlich wenn sich herausstellt, daß eine Applikation doch nicht fehlerfrei arbeitet und noch mal in der Entwicklungsumgebung nachbearbeitet werden muß. Jetzt bestünde natürlich die Möglichkeit, daß verwendete Klassen im allgemeinen Verzeichnis verändert wurden und nicht mehr kompatibel zum fehlerhaften Projekt sind. Ich könnte in dem Fall aber vorübergehend den symb. Link durch die tatsächliche Klasse in xyz/fehlerhaftes_projekt/a/ ersetzen, und das Problem wäre gelöst. Das wäre eine sehr sympathische Lösung, und wenn dies funktioniert, bin ich Dir sehr dankbar, daß Du mir diese Perpektive eröffnet hast.

              1. Hi,

                Ich erkläre mal kurz, wie ich Dich verstehe. Die Klassen kommen (in der Entwicklungsumgebung) nach /xyz/a/. In PHP selbst (mittels inc_path, ini_set etc.) greift man auf Dateien aus /xyz/projekt1/b/ zu. Dort liegen aber keine gewöhnlichen Dateien, sondern Links. Das merkt PHP selbst nicht, wohl aber das OS. Also müßte ich in /xyz/projekt/b// für jede Datei einen Link auf ein Pendant in xyz/a/ anlegen. Verstehe ich das soweit richtig?

                Nein, nicht für jede Datei - für's Verzeichnis.
                Wenn /xyz/projekt1/b/ ein SymLink ist, der auf /xyz/a/ verweist - dann sucht das OS bei "Aufruf" von /xyz/projekt1/b/blah.blubb diese Datei automatisch unter /xyz/a/blah.blubb

                Der einzige Schritt, der getan werden muß, läge demnach gar nicht in der Programmierung mit PHP, sondern im Anlegen von symb. Links mittels Shell, ist das so richtig?

                Ja, genau. PHP merkt gar nichts davon.
                (Ausser vielleicht, wenn man explizit mit Funktionen wie is_link darauf prüft.)

                Wenn das so wäre, würde das sogar noch ein anderes Problem lösen, nämlich wenn sich herausstellt, daß eine Applikation doch nicht fehlerfrei arbeitet und noch mal in der Entwicklungsumgebung nachbearbeitet werden muß. Jetzt bestünde natürlich die Möglichkeit, daß verwendete Klassen im allgemeinen Verzeichnis verändert wurden und nicht mehr kompatibel zum fehlerhaften Projekt sind. Ich könnte in dem Fall aber vorübergehend den symb. Link durch die tatsächliche Klasse in xyz/fehlerhaftes_projekt/a/ ersetzen, und das Problem wäre gelöst.

                Gut, das würde aber nur funktionieren, wenn du die SymLink wirklich auf Dateiebene benutzen würdest. Ginge auch, ist aber mehr Aufwand beim Einrichten.

                MfG ChrisB

                --
                Light travels faster than sound - that's why most people appear bright until you hear them speak.
                1. Hi!

                  Hi,

                  »» Ich erkläre mal kurz, wie ich Dich verstehe. Die Klassen kommen (in der Entwicklungsumgebung) nach /xyz/a/. In PHP selbst (mittels inc_path, ini_set etc.) greift man auf Dateien aus /xyz/projekt1/b/ zu. Dort liegen aber keine gewöhnlichen Dateien, sondern Links. Das merkt PHP selbst nicht, wohl aber das OS. Also müßte ich in /xyz/projekt/b// für jede Datei einen Link auf ein Pendant in xyz/a/ anlegen. Verstehe ich das soweit richtig?

                  Nein, nicht für jede Datei - für's Verzeichnis.

                  Aha, das wußte ich nicht, daß sowas geht. Das ist ja noch besser.

                  »» Wenn das so wäre, würde das sogar noch ein anderes Problem lösen, nämlich wenn sich herausstellt, daß eine Applikation doch nicht fehlerfrei arbeitet und noch mal in der Entwicklungsumgebung nachbearbeitet werden muß. Jetzt bestünde natürlich die Möglichkeit, daß verwendete Klassen im allgemeinen Verzeichnis verändert wurden und nicht mehr kompatibel zum fehlerhaften Projekt sind. Ich könnte in dem Fall aber vorübergehend den symb. Link durch die tatsächliche Klasse in xyz/fehlerhaftes_projekt/a/ ersetzen, und das Problem wäre gelöst.

                  Gut, das würde aber nur funktionieren, wenn du die SymLink wirklich auf Dateiebene benutzen würdest. Ginge auch, ist aber mehr Aufwand beim Einrichten.

                  Kann man ja dann im Bedarfsfall auf Dateiebene machen, ansonsten (während des Entwicklungsstadiums) auf Verzeichnisebene.

                  Herzlichen Dank für diesen Tip mit den symbolischen Links (vor allem denen von/ auf Verzeichnisse)!

  2. Hello,

    Funktioniert dies? Quasi, daß entweder zuerst die Pfade vom Include-Path abgeklappert werden und, wenn nix gefunden wird, __autoload greift

    Genau so ist es ja auch, wenn Du die Reihenfolge einhältst

    __autoload()-Funktion definieren
       include von Modulen (und Klassen vornehmen)
       Klasse benutzten

    Wenn nach den Includes die Klasse noch nicht geladen ist, die benutzt werden soll, greift der Autoload-Mechanismus.

    Wenn der auch keine passende Klasse findet, dann gibt's 'nen Fehler.

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
    Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. Hallo!

      Hello,

      »» Funktioniert dies? Quasi, daß entweder zuerst die Pfade vom Include-Path abgeklappert werden und, wenn nix gefunden wird, __autoload greift

      Genau so ist es ja auch, wenn Du die Reihenfolge einhältst

      __autoload()-Funktion definieren
         include von Modulen (und Klassen vornehmen)
         Klasse benutzten

      Wenn nach den Includes die Klasse noch nicht geladen ist, die benutzt werden soll, greift der Autoload-Mechanismus.

      So soll es ja sein, aber meine Beobachtung war, daß es so nicht funktioniert. Ich probiere das morgen noch mal aus, so macht __autoload auch Sinn für mich, und so hatte zunächst auch vermutet, daß es funktionieren würde, aber es ging nicht. Nun denn, dann habe ich vielleicht an irgend einer Stelle Mist gebaut.

  3. Moin!

    ist eine einfache, vielleicht auch blöde Frage. Funktioniert dies? Quasi, daß entweder zuerst die Pfade vom Include-Path abgeklappert werden und, wenn nix gefunden wird, __autoload greift bzw. umgekehrt, daß man, wenn nichts in Verzeichnissen, die von __autoload berücksichtigt werdeb, findet, an den Parser und include_path zurückdeligiert? Ich denke ja nicht, daß es geht, aber vielleicht gibt es ja doch etwas ähnliches!? Bitte keine Antworten wie "erweitere doch den include_path und verzichte auf __autoload". Das weiß ich auch selbst, daß das eine Möglichkeit ist, ich brauche aber was anderes.

    Im Grunde solltest du auf __autoload wirklich verzichten, denn damit kannst du nur genau eine Autoload-Routine einbinden. Es gibt mit spl_autoload_register() eine deutlich schönere Methode, Autoload-Funktionen einzubinden, genauer gesagt hintereinanderzuhängen.

    Außerdem bietet eigentlich jedes vernünftige PHP-Framework einen Mechanismus an, einen eigenen Autoloader zu benutzen, der die Möglichkeiten von spl_autoload oft noch mal deutlich erweitert. Im Falle des Zend-Frameworks wäre das Zend_Loader_Autoloader.

    Um den maximalen Vorteil aus dem Autoloading zu ziehen, sollte man auf jegliches include/include_once bzw. require/require_once verzichten, so dass wirklich nur diejenigen Klassen inkludiert werden, die der ausgeführte Code tatsächlich benutzt. Das setzt allerdings voraus, dass man sich hinsichtlich der Aufteilung von Klassen in Dateien an eindeutige und schlichte Regeln hält, die man seiner Autoload-Routine beibringen muss - oder man nutzt die vorgefertigten Art und Weise des Framework-Autoloaders, den man einsetzt. Üblich ist: Eine Klasse pro Datei, und der Klassenname ist, wenn man Unterstriche in Slashes umsetzt, der Pfadname zur jeweiligen Datei, ausgehend von einem zu definierenden Startverzeichnis (welches sich freundlicherweise nicht im DOCUMENT_ROOT befinden muss).

    Abgesehen davon kann man den include_path jederzeit mit ini_set() oder set_include_path() erweitern (zum Lesezugriff ini_get oder get_include_path()), ohne explizit irgendwelche Settings extern aufbohren lassen zu müssen.

    - Sven Rautenberg