borisbaer: PHP-Router mit Attributen: Automatisches Registrieren und Cachen von Controller-Klassen

Hallo zusammen,

ich habe einen einfachen PHP-Router geschrieben und hatte die Idee, die Controller-Klassen automatisch mappen zu lassen.

Dabei würde die entsprechende Methode das Verzeichnis app/controllers durchsuchen und die Namen aller darin befindlichen php-Dateien in einem Controllers-Array sammeln. Die Controller sind jedoch wiederum in mehrere Unterverzeichnis aufgeteilt, weshalb ich nach einer Funktion suche, die auch in allen Unterverzeichnissen von app/controllers nachschaut. Wie könnte man das heutzutage am effektivsten machen? Vielleicht mit dem RecursiveDirectoryIterator?

Mein zweites Anliegen wäre es, diese Controller zu cachen, damit sie nicht bei jedem Seitenaufruf erneut gemappt werden müssen. Ich habe jedoch überhaupt keine Ahnung vom Cachen und wüsste auch nicht, wie ich da am besten ansetzen soll.

Über Hilfe würde ich mich sehr freuen!

Grüße
Boris

  1. Nachtrag:

    Dabei würde die entsprechende Methode das Verzeichnis app/controllers durchsuchen und die Namen aller darin befindlichen php-Dateien in einem Controllers-Array sammeln. Die Controller sind jedoch wiederum in mehrere Unterverzeichnis aufgeteilt, weshalb ich nach einer Funktion suche, die auch in allen Unterverzeichnissen von app/controllers nachschaut. Wie könnte man das heutzutage am effektivsten machen? Vielleicht mit dem RecursiveDirectoryIterator?

    Das erste Problem konnte ich folgendermaßen lösen:

    private function getControllers(): array
    
    {
    
    	$controllers = [];
    
    	$dir = '..' . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'controllers';
    
    	$dir = new \RecursiveDirectoryIterator( $dir, \FilesystemIterator::SKIP_DOTS );
    
    	$iterator = new \RecursiveIteratorIterator( $dir );
    
    	foreach ( $iterator as $fileinfo )
    
    		$controllers[] = implode( '\\', array_map( 'ucwords', explode( '\\', str_replace( '.php', '', substr( $fileinfo -> getPathname(), 3 ) ) ) ) );
    
    	return $controllers;
    
    }
    
  2. Hello,

    was meinst Du mit "mappen"?

    Mein zweites Anliegen wäre es, diese Controller zu cachen, damit sie nicht bei jedem Seitenaufruf erneut gemappt werden müssen. Ich habe jedoch überhaupt keine Ahnung vom Cachen und wüsste auch nicht, wie ich da am besten ansetzen soll.

    Interessante Aufgabe. Dafür gibt es wohl denPHP OPCache

    Scheint inzwischen auch frei verfügbar zu sein!?

    Solltest Du bei deiner weiteren Recherche ein Schritt-für-Schritt-Tutorial finden, gib mal bitte Bescheid :-)

    Glück Auf
    Tom vom Berg

    --
    Es gibt soviel Sonne, nutzen wir sie.
    www.Solar-Harz.de
    S☼nnige Grüße aus dem Oberharz
  3. Hallo borisbaer,

    ja, ein RecursiveDirectoryIterator ermöglicht das, zusammen mit einm RecursiveIteratorIterator.

    Guck mal auf der RecursiveDirectoryIterator -Seite das Beispiel von Thriault an.

    Alternativ kannst Du auch selbst eine rekursive Suche implementieren, aber die Iteratoren machen es einfach.

    Ich bezweifle aber, dass es sinnvoll ist, die Controller in Unterverzeichnisse zu sortieren und damit die Klassen-Instanziierung zu erschweren. Warum packst Du nicht alle Controller in einen Ordner? Sind es so viele dass es unübersichtlich wird?

    Du könntest Dir auch ein Namensschema überlegen, das deine Directorystruktur abbildet. Wenn Du im Controller-Ordner einen Ordner base hast und darin einen Controller Foo.php, dann könnte der Controller in der URL den Namen base_foo tragen. Dadurch weißt Du, wo Du suchen musst.

    Ein Caching würde ich nicht empfehlen. Statt dessen solltest Du über ein separates Script, das nicht auf der Seite verlinkt ist und was Du nach Bedarf abrufen kannst, eine Referenzdatei erzeugen. Dabei handelt es sich um ein PHP Include, das ein Array dieser Art erzeugt:

    $controllerRef = [
       "Foo" => "base/foo.php",
       "Game" => "games/game.php",
       "Dialog" => "ui/dialog.php",
    ];
    

    Diese Datei prüfst Du im Router auf Existenz und includest sie, wenn sie da ist. Wenn Du das $controllerRef Array hast, arbeitest Du damit im Classloader. Wenn nicht, verwende die rekursive Dateisuche.

    Auf deinem Test-Web lässt Du diese Include-Datei weg und arbeitest mit der rekursiven Suche. Für das Test-Web ist das okay.

    Schreibe Dir ein Utility-Script, das Dir aus deinem Controller-Ordner die Include-Datei generiert. Pflege sie nicht von Hand. Die generierte Include-Datei lädst Du dann bei jeder Codeveröffentlichung mit auf den Server.

    Der Opcache der Zend-Engine sorgt dafür, dass diese Include-Datei nur einmal von PHP compiliert werden muss. Danach steht sie im Opcache binär zur Verfügung und es kostet keine merkliche Zeit, sie zu laden.

    Du könntest Dir auch ein PHP Script schreiben, das auf deinem Testsystem läuft und das mit den FTP-Funktionen von PHP automatisch deinen Code auf den öffentlichen Server lädt und sich dabei auch um das Generieren der Include-Datei kümmert.

    Was ich nicht empfehlen würde, ist, die include-Datei von deinem regulären PHP Code "on demand" erzeugen zu lassen. Ein öffentlich erreichbares PHP Script sollte niemals dorthin schreiben dürfen, von wo Code ausgeführt werden kann.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hello,

      was ich dabei nicht verstehe:

      Gehören die verschiedenen Controller denn nicht sowieso immer zu einzelnen Seiten(-Gruppen), deren Komponenten sich jeweils in einem eigenen Verzeichnis befinden, das über einen eindeutigen Pfad/Url aufrufbar ist?

      Oder verstößt das dann gegen das MVC-Prinzip?

      Glück Auf
      Tom vom Berg

      --
      Es gibt soviel Sonne, nutzen wir sie.
      www.Solar-Harz.de
      S☼nnige Grüße aus dem Oberharz
      1. Hallo TS,

        das "MVC" Prinzip besagt nur, dass ein Programm so strukturiert wird, dass es Klassen für Daten (Model), Präsentation (View) und Steuerung (Controller) gibt. Wo die Sourcen dieser Klassen gespeichert sind und wie die URLs einer Website aussehen, die auf MVC basiert, ist durch dieses Prinzip nicht festgelegt.

        Du kannst gerne einen Ordner pro Controller machen, in dem dann auch die zugehörigen Views und Models liegen, und ggf. auch Client-Ressourcen (js, css, Medien), die für diese Views erforderlich sind. Es ist aber nicht zwingend so, dass es zwischen Controller, Model und View feste Beziehungen gibt. Zumeist ist es so, dass ein View nur von einem Controller verwendet wird, d.h. es gibt zwischen Controllern und Views eine 1:n Relation. Das ist aber nicht in ROM gebrannt, Du kannst nicht ausschließen, dass sich einige Controller einen View teilen.

        Zwischen Controllern und Models besteht aber noch viel eher ein m:n, so dass man den Speicherort einer Modelklasse nicht klar einem Controller-Speicherort zuordnen kann.

        Deswegen macht man eher einen Ordner für alle Controller, einen Ordner für alle Model-Klassen, einen Ordner für alle View-Klassen. Man kann diese Ordner auch unterstrukturieren - das ist Dir überlassen.

        Zusammen mit MVC findet man oft auch die Idee von "Convention before Configuration". Heißt: Es gibt Konventionen, wo Klassen liegen oder wie die Dateien heißen, in denen der Code liegt, so dass Du nicht irgendwo konfigurieren musst, dass der Controller "Foo" in /controllers/hugo/tralala/foo.class.php zu finden ist. Oder schlimmer noch: zur Runtime im Projekt herumstöbern. Statt dessen legst Du als Konvention fest (oder das verwendete Framework tut es), dass der Controller Foo als Klasse "FooController" implementiert ist und durch die Datei "FooController.php" implementiert wird. In welchem Ordner diese Klasse liegt, kann eine weitere Konvention sein. Man kann festlegen, dass die Datei im Ordner /controllers liegt, man kann auch darauf verzichten und eine wilde Suche in einem verästelten Ordnerbaum beginnen. Man kann die wilde Suche durch einen Index beschleunigen, wie ich es Borisbär vorschlug, und man kann den Index on-demand aufbauen und aktualisieren (man sucht die Klassendatei via Index, und wenn man sie nicht findet, sucht man ihren Ort und aktualisiert den Index). Das ist alles fehlerträchtig und kompliziert.

        In ASP.NET MVC ist es so, dass die Controllerklassen einfach im Projekt mitcompiliert werden. ASP.NET geht dann per Reflection her und durchsucht die Assembly des Web-Projekts nach Klassen, die von Controller abgeleitet sind. Da ein ASP.NET Web aus compiliertem Code besteht, der nur einmal in den Application Pool geladen wird und dann drin bleibt, geht das fix und es ist kein Problem, das Ergebnis im RAM zu behalten. Bei PHP geht das (soweit ich weiß) leider nicht. Es gibt Memcache, aber dafür braucht's halt den Memcached Daemon im Hintergrund. Und der muss erstmal verfügbar sein.

        Meine Empfehlung: Flache Ordner, klare Konventionen. Tiefere Strukturen nur, wenn das Projekt sonst zu riesig wird.

        Vielleicht kann man ja die Ordner, in denen die Controller liegen, auch im URL Konzept mitnehmen. Statt /Foo/Bar/6 (Controller Foo, Action Bar, Parameter 6) kann die URL ja für den Fall, dass der Foo-Controller im Ordner blah liegt, auch /blah/Foo/Bar/6 heißen. Das wird nur schwierig für den Fall, dass die Ordnertiefe variiert - ggf. muss man den Controller irgendwie kennzeichnen. URLs sind case-sensitive, Ordner könnten so wie im Beispiel komplett in Kleinschrift stehen und Controller mit einem Großbuchstaben beginnen. Wieder gilt: Convention before Configuration.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hello Rolf,

          [...]

          Vielen Dank für deine ausführliche Erläuterung.
          Es gibt (in PHP) also kein starres Ordnungssystem, dass man einhalten muss, um es richtig™ zu machen.

          Bleibt für mich jetzt nur die Frage, wieviele Dateien man bei Linux üblicherweise in einem Verzeichnis unterbringen darf, damit das Filesystem nicht beim Suchen "überhitzt".

          Ggf. sollte man hier quasi direktgestreut vorgehen, also z. B. für jeden Anfangsbuchstaben ein Unterverzeichnis anlegen. So ähnlich hat das @borisbaer wohl auch schon angelegt.

          In der Anfangszeit meiner Site-Entwickung (nur die Backends) habe ich die Code-Schnipsel, Controller, Funktionen, usw. immer in der Datenbank untergebracht. Das machte das Zusammensuchen für eine Vorgangsbearbeitung zwar schnell und ermöglicht die Verwaltung von Userrechten, ist aber nicht gut zu pflegen. Und man benötigt das hässliche eval() dafür.

          Glück Auf
          Tom vom Berg

          --
          Es gibt soviel Sonne, nutzen wir sie.
          www.Solar-Harz.de
          S☼nnige Grüße aus dem Oberharz
          1. Hallo TS,

            das Problem bei eval() dürfte auch sein, dass der opcache dafür nicht greift.

            Bei den Filesystemen bin ich zuversichtlich, dass sie performant sind, wenn Du eine konkrete Datei suchst.

            Das sequenzielle Durchsuchen eines Ordners ist eine andere Sache. Aber mehr als 100 Controller wirst Du nicht haben. Selbst wenn es 200 oder 300 sind. Hier kann es helfen, eine Ordnerstruktur zu schaffen, die nur auf unterster Ebene Dateien enthält. Dadurch sind die Knoten auf höhererer Ebene nicht zu groß und lassen sich schnell einlesen. Das Suchen der Class-Datei in einem Order erfolgt mit file_exists, und das sollte - außer bei FAT-Systemen - immer schnell sein.

            Eine Verteilung von Controllern via Anfangsbuchstabe ist jedenfalls nichts, womit man ein Projekt organisieren sollte. Da gefällt mir die Idee mit Ordnern in der URL doch besser. Will man keine Schreibweisenkonvention, kann man auch hergehen und die URL in Pfadsegmente zerlegen. Segment für Segment schaut man im Code-Order

            • gibt es einen gleichnamigen Ordner für das Segment? -> Ok, Segment steht für einen Ordner, suche in diesem Ordner weiter.
            • gibt es im Pfad eine Datei "$segmentController.php" -> Ok, Segment bezeichnet einen Controller

            Die Namenskonvention "xyzController.php" stellt sicher, dass auf diese Weise nur Controller angesprochen werden können. Es mag auch interne (Sub-)Controller geben, die nicht direkt von außen angesprochen werden sollen. Diese kann man z.B. xyzSubCtrl.php nennen (NICHT SubController).

            Bevor man solche Dinge angeht, sollte man aber erstmal ein paar Performance-Messungen des verwendeten Dateisystems machen. Ein RASPI, ein Windows-PC und ein Shared Hosting Server könnten sich - vor allem unter Last - sehr unterschiedlich verhalten.

            Die aus meiner Sicht sicherste Lösung ist aber ein Controller-Repository, das durch ein Tool gepflegt wird und sich aus dem Quellcode ableitet. Ab PHP 8 bieten sich hier auch Attribute an, die ein Tool finden und auswerten kann. Das Controller-Repository kann man in eine Datenbank legen (DB-Zugriffe wird man eh brauchen) oder in einer Textdatei speichern. Auf diese Weise wird zuverlässig verhindert, dass eine gefälschte URL Code lädt, der eigentlich gar nicht als Controller geladen werden soll. Und man hat, nachdem im Repository die richtige Zeile gefunden ist, sofort den korrekten Pfad zur Source-Datei.

            Ein Projekt, das so groß ist, dass man solche Performance-Klimmzüge machen muss, sollte sich aber auch fragen, ob PHP das richtige Werkzeug dafür ist.

            Rolf

            --
            sumpsi - posui - obstruxi
    2. Hallo Rolf,

      Guck mal auf der RecursiveDirectoryIterator -Seite das Beispiel von Thriault an.

      das hat mir leider keine Ergebnisse geliefert. Ich hatte es genauso kopiert und auf mein Verzeichnis angewandt. Auf andere Weise (siehe oben) habe ich es aber hinbekommen.

      Ich bezweifle aber, dass es sinnvoll ist, die Controller in Unterverzeichnisse zu sortieren und damit die Klassen-Instanziierung zu erschweren. Warum packst Du nicht alle Controller in einen Ordner? Sind es so viele dass es unübersichtlich wird?

      Es könnten schon so um die 30 ControllerKlassen werden. Inwiefern wird die Instanziierung dadurch erschwert? Ich habe z.B. „tatsächliche“ Seiten (mit GET-Request) wie Home, Spiele, Plattformen usw. von ich nenne sie mal user-related Controllern wie SignInController, SignUpController und SignOffController getrennt. Dann haben manche Seiten auch noch Unterseiten, z.B. kann die konkrete Spiele-Seite in Releases, Merchandise, Emulation, Map usw. aufgeteilt sein. Diese Unterseiten haben jeweils eigene Controller und die stecke ich auch zusammen in ein entsprechendes Unterverzeichnis. Für mich ist es so übersichtlicher als alle Controller in einem Ordner zu haben.

      Du könntest Dir auch ein Namensschema überlegen, das deine Directorystruktur abbildet. Wenn Du im Controller-Ordner einen Ordner base hast und darin einen Controller Foo.php, dann könnte der Controller in der URL den Namen base_foo tragen. Dadurch weißt Du, wo Du suchen musst.

      Könnte man machen, aber ich sehe hier ehrlich gesagt keinen großen Nutzen für mich.

      Ein Caching würde ich nicht empfehlen. Statt dessen solltest Du über ein separates Script, das nicht auf der Seite verlinkt ist und was Du nach Bedarf abrufen kannst, eine Referenzdatei erzeugen. Dabei handelt es sich um ein PHP Include, das ein Array dieser Art erzeugt:

      $controllerRef = [
         "Foo" => "base/foo.php",
         "Game" => "games/game.php",
         "Dialog" => "ui/dialog.php",
      ];
      

      Diese Datei prüfst Du im Router auf Existenz und includest sie, wenn sie da ist. Wenn Du das $controllerRef Array hast, arbeitest Du damit im Classloader. Wenn nicht, verwende die rekursive Dateisuche.

      Das ist eine interessante Idee, aber ich verstehe nicht was du meinst, wenn du sagst, ich soll damit im Classloader arbeiten. Dieses Autoload habe ja installiert, aber inwiefern kann ich das verwenden, um nicht cachen zu müssen. Ich kenne mich damit leider nicht aus.

      Schreibe Dir ein Utility-Script, das Dir aus deinem Controller-Ordner die Include-Datei generiert. Pflege sie nicht von Hand. Die generierte Include-Datei lädst Du dann bei jeder Codeveröffentlichung mit auf den Server.

      Ja, da ich die Controller-Verwaltung automatisieren möchte, bietet sich das auf jeden Fall an.

      Der Opcache der Zend-Engine sorgt dafür, dass diese Include-Datei nur einmal von PHP compiliert werden muss. Danach steht sie im Opcache binär zur Verfügung und es kostet keine merkliche Zeit, sie zu laden.

      Von so was habe ich leider keine Ahnung, aber wenn ich dich hier richtig verstehe, dann kommen inkludierte Dateien bei PHP sowieso automatisch in einen Cache?

      Du könntest Dir auch ein PHP Script schreiben, das auf deinem Testsystem läuft und das mit den FTP-Funktionen von PHP automatisch deinen Code auf den öffentlichen Server lädt und sich dabei auch um das Generieren der Include-Datei kümmert.

      FTP und PHP. Ist leider noch zu hoch für mich. 🤔

      Was ich nicht empfehlen würde, ist, die include-Datei von deinem regulären PHP Code "on demand" erzeugen zu lassen. Ein öffentlich erreichbares PHP Script sollte niemals dorthin schreiben dürfen, von wo Code ausgeführt werden kann.

      Was ist die Alternative? „Schreibe dir ein Utility-Script“ hast du oben geschrieben. Meinst du damit eine Art Helfer-Funktion? Könntest du da etwas konkreter werden. Du weißt ja, ich bin kein Fachmann. ^^

      Grüße
      Boris

      1. Hallo borisbaer,

        Es könnten schon so um die 30 ControllerKlassen werden. Inwiefern wird die Instanziierung dadurch erschwert?

        Das ist gar nichts.

        Diese Unterseiten haben jeweils eigene Controller und die stecke ich auch zusammen in ein entsprechendes Unterverzeichnis

        Jetzt sag nicht, du programmierst für jedes Spiel eigene Controller?!

        Dieses Autoload habe ja installiert, aber inwiefern kann ich das verwenden, um nicht cachen zu müssen.

        Der Autoloader muss doch zur Klasse XyzController die richtige Quellcode-Datei finden. Dazu musst Du per require die richtige PHP Datei laden. Wenn Du nun ein Array hast, wo drinsteht, dass SignInController in /controllers/user/SignInController.php) zu finden ist, dann kann der Autoloader das verwenden, wenn er aufgefordet wird, die Klasse SignInController zu beschaffen.

        Die Herausforderung ist, dieses Array zur Laufzeit performant zu beschaffen. Ein Caching während eines einzigen PHP Requests ist sinnlos, weil PHP ja eine Klasse nur einmal lädt, danach ist sie im Speicher und der Autoloader wird nicht noch einmal danach gefragt. Du brauchst also für diesen Klassen-Index eine Speicherungsform, die einen einzelnen PHP Request überlebt, und am besten auch nicht Userbezogen ist (damit meine ich: $_SESSION wäre ein schlechter Platz dafür).

        In ASP.NET gibt's außer dem Session-Speicher auch einen Application-Speicher, aber nicht in PHP. Deshalb mein Vorschlag mit einer Textdatei, oder mit einer PHP-Datei, die dieses Index-Array erzeugt und die Du mit require_once einmal dazu holst. Eine solche Datei sollte aber nicht im laufenden Webrequest-Betrieb verändert werden, das stört den OpCache und es kann auch zu konkurrierenden Zugriffen kommen. Deshalb mein Vorschlag, sie über ein Tool vorab zu generieren und zusammen mit der Anwendung auf den Server zu laden.

        dann kommen inkludierte Dateien bei PHP sowieso automatisch in einen Cache?

        Jein. Das hängt an der PHP Version und an der Serverkonfiguration. Guck in die php.ini des Servers, oder lass auf dem Server ein Miniscript laufen, in dem nur phpInfo() aufgerufen wird. Und dann guck, was da bei den opcache-Einstellungen steht.

        Wenn PHP eine Code-Datei lädt, interpretiert es nicht deinen Sourcecode. Statt dessen compiliert es ihn in einen Zwischencode, den Bytecode, und der wird dann von der ZEND-Engine interpretiert. Der OpCache speichert den generierten Bytecode und prüft bei jedem Zugriff, ob sich die Quellcodedatei verändert hat.

        Neuere PHP Versionen gehen noch einen Schritt weiter, so wie auch neuere JavaScript Engines, und compilieren den Bytecode zu echtem Maschinencode (Just In Time Compiler - JIT). Auch das kann man ein/ausschalten, auch darüber gibt Dir phpInfo() Auskunft. Ein JIT bringt aber nur dann richtig was, wenn man CPU-intensive Dinge tut. Für normales "Datenschaufeln" ist der Bytecode kaum langsamer.

        Was ist die Alternative? „Schreibe dir ein Utility-Script“ hast du oben geschrieben. Meinst du damit eine Art Helfer-Funktion?

        Ich meine eine eigene PHP Datei, die Du entweder über deinen lokalen Webserver oder gleich von der Kommandozeile aus laufen lässt, und die die Index-Datei erzeugt. Diese PHP Datei kommt nicht auf den öffentlichen Webserver, die bleibt auf deiner Entwicklungsmaschine. Aufgaben: Controller zusammensuchen, Index aufbauen und in eine Datei schreiben. Das ist dann eher klassische Dateiverarbeitung und keine Verarbeitung eines Webrequests. PHP ist dafür nicht optimiert, kann es aber auch.

        Okay, das muss gar nicht PHP sein. Wenn Du lieber ein Bash-Script oder ein Programm in Java oder Python dafür schreibst - geht genauso.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hallo Rolf

          Jetzt sag nicht, du programmierst für jedes Spiel eigene Controller?!

          nein, nein. Das könnte ich gar nicht leisten. Ich wollte nur sagen, dass eine konkrete Spiele-Seite in mehrere Unterseiten aufgeteilt ist (z.B. Releases, Merchandise, Emulation usw.) und diese Unterseiten haben ihren eigenen Controller (z.B. GameReleasesController, GameMerchandiseController usw.).

          Der Autoloader muss doch zur Klasse XyzController die richtige Quellcode-Datei finden. Dazu musst Du per require die richtige PHP Datei laden. Wenn Du nun ein Array hast, wo drinsteht, dass SignInController in /controllers/user/SignInController.php) zu finden ist, dann kann der Autoloader das verwenden, wenn er aufgefordet wird, die Klasse SignInController zu beschaffen.

          Ach ja, bei mir steht das in der composer.json:

          "autoload": {
          	"files": ["app/functions.php"],
          	"psr-4": {
          		"App\\": "app/",}
          },
          

          Dann könnte ich einfach dieses automatisch generierte Controllers-Array per Autoloader laden.

          Die Herausforderung ist, dieses Array zur Laufzeit performant zu beschaffen. Ein Caching während eines einzigen PHP Requests ist sinnlos, weil PHP ja eine Klasse nur einmal lädt, danach ist sie im Speicher und der Autoloader wird nicht noch einmal danach gefragt.

          Heißt das, die durch den Autoloader geladenen Dateien werden gecacht?

          Deshalb mein Vorschlag mit einer Textdatei, oder mit einer PHP-Datei, die dieses Index-Array erzeugt und die Du mit require_once einmal dazu holst. Eine solche Datei sollte aber nicht im laufenden Webrequest-Betrieb verändert werden, das stört den OpCache und es kann auch zu konkurrierenden Zugriffen kommen. Deshalb mein Vorschlag, sie über ein Tool vorab zu generieren und zusammen mit der Anwendung auf den Server zu laden.

          Ich habe in der index.php require_once '../vendor/autoload.php';. Wenn ich dann in der composer.json beim autoload unter files die oben genannte Textdatei ergänze, sollte das doch reichen, oder?

          Es ergibt Sinn, dass diese Textdatei nicht in Runtime erzeugt werden soll, sondern im Vorfeld über ein externes Tool. Was für ein Tool man da nehmen soll, weiß ich nicht. Das ist für mich wohl die größte Schwierigkeit, denn ich habe bisher nur mit PHP und JS gearbeitet.

          dann kommen inkludierte Dateien bei PHP sowieso automatisch in einen Cache?

          Jein. Das hängt an der PHP Version und an der Serverkonfiguration. Guck in die php.ini des Servers, oder lass auf dem Server ein Miniscript laufen, in dem nur phpInfo() aufgerufen wird. Und dann guck, was da bei den opcache-Einstellungen steht.

          In der php.ini sind unter [opcache] nur einige auskommentierte Zeilen, z.B.:

          ; Determines if Zend OPCache is enabled
          ;opcache.enable=1
          

          Wenn PHP eine Code-Datei lädt, interpretiert es nicht deinen Sourcecode. Statt dessen compiliert es ihn in einen Zwischencode, den Bytecode, und der wird dann von der ZEND-Engine interpretiert. Der OpCache speichert den generierten Bytecode und prüft bei jedem Zugriff, ob sich die Quellcodedatei verändert hat.

          Gut zu wissen, aber ich kenne weder Bytecode noch den genauen Unterschied zwischen interpretieren und kompilieren. 🐵 Aber grob verstehe ich, glaube ich, was du meinst. PHP interpretiert (anders als JS?) den Code nicht selbst, sondern verwendet dafür diese Engine.

          Ich meine eine eigene PHP Datei, die Du entweder über deinen lokalen Webserver oder gleich von der Kommandozeile aus laufen lässt, und die die Index-Datei erzeugt. Diese PHP Datei kommt nicht auf den öffentlichen Webserver, die bleibt auf deiner Entwicklungsmaschine. Aufgaben: Controller zusammensuchen, Index aufbauen und in eine Datei schreiben. Das ist dann eher klassische Dateiverarbeitung und keine Verarbeitung eines Webrequests. PHP ist dafür nicht optimiert, kann es aber auch.

          Okay, das muss gar nicht PHP sein. Wenn Du lieber ein Bash-Script oder ein Programm in Java oder Python dafür schreibst - geht genauso.

          Kommandozeile? Bisher habe ich auch weder mit Bash noch mit Java oder Python gearbeitet. Aber Bash könnte ich mir mal anschauen.

          Mein Ziel wäre also, ein Bash-Script zu schreiben, das nur lokal ausgeführt wird und eine Datei generiert, in der alle ControllerNamen gespeichert sind. Diese Datei wiederum würde ich über den Autoloader einpflegen. Habe ich das soweit richtig verstanden?

          Vielen Dank bis hierhin!

          Grüße
          Boris

          1. Hallo borisbaer,

            ach so.

            Wenn du den von Composer generierten Autoloader verwendest, dann sieht die Sache schwieriger aus. Composer bietet ja nur an, für einen Namespace einen Ordner zu hinterlegen.

            Da bin ich jetzt raus - ich kompostiere nicht…

            Rolf

            --
            sumpsi - posui - obstruxi
  4. Lieber borisbaer,

    Du suchst wahrscheinlich spl_autoload_register().

    Liebe Grüße

    Felix Riesterer

    1. Hallo Felix,

      Du suchst wahrscheinlich spl_autoload_register().

      vielen Dank für den Hinweis. So richtig kapiert habe ich die Funktion jedoch noch nicht. Da muss ich mich noch genauer mit auseinandersetzen.

      Viele Grüße
      Boris