Ankündigung

Einklappen
Keine Ankündigung bisher.

Dynamische (Modul-)Klassenverwaltung, sinnvoll?

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Dynamische (Modul-)Klassenverwaltung, sinnvoll?

    Hallo zusammen,

    ich bin neu hier und hoffe ich hab das richtige Unterforum erwischt, in den Anfänger-Bereich passt das vielleicht nicht?

    Den grundsätzlichen Inspirationsschub für dieses DI-Konzept habe ich in diesem Thread bekommen. Genauer, in der zweiten Antwort von Combie.
    Seinen Ansatz habe ich jetzt etwas erweitert, um dynamisch weitere installierte Module nachzuladen und ihnen automatisiert benötigte Objekte zu übergeben.

    Es funktioniert alles, darum geht es also nicht. Mich würde mehr interessieren ob das Konzept noch Schwächen, z.B. in Sachen Performance, hat, welche ich aktuell noch übersehe.

    Hier mal die relevanten Code-Teile für die Klassen-Verwaltung:

    PHP-Code:
    // index.php

    require_once "./classes/ffcms.class.php";
    $ffcms = new ffcms();
    $ffcms->run();

    // ffcms.class.php (extends diRegistry)

      
    public function run() {
        
    $this->buildContent->run();
      }
      protected function 
    di_db() {
        
    $db = new MySQLi(DB_HOSTDB_USERDB_PASSDB_NAME);
        if(
    mysqli_connect_errno()) die("Verbindung zur Datenbank konnte nicht hergestellt werden.");
        
    $this->db $db;
        return 
    $db;
      }
      protected function 
    di_user() {
        
    $user = new user($this->db);
        
    $this->user $user;
        return 
    $user;
      }
      protected function 
    di_modules() {
        
    $this->modules = new modules($this);
        return 
    $this->modules;
      }
      protected function 
    di_buildContent() {
        
    $buildContent = new buildContent($this);
        
    $this->buildContent $buildContent;
        return 
    $buildContent;
      }

    // diRegistry.class.php


      
    protected $values = array();

      public function 
    __set($id,$value) {
        
    $this->values[$id] = $value;
      }
      public function 
    __get($id) {
        if(isset(
    $this->values[$id]))
          return 
    $this->values[$id];
        return 
    $this->di($id);
      }
      protected function 
    di($element) {
        
    $di = array($this,'di_'.$element);
        if(
    is_callable($di)) {
          return 
    call_user_func($di);
        } elseif(
    $this->modules->isInstalled($element)) {
          
    $this->values[$element] = $this->modules->loadModule($element);
          return 
    $this->values[$element];
        }
        throw new 
    InvalidArgumentException("Can not create $element");
      }

    // modules.class.php

    class modules {
      private 
    $ffcms;
      public function 
    __construct(ffcms $ffcms) {
        
    $this->ffcms $ffcms;
      }
      public function 
    isInstalled($module) {
        
    $sql "SELECT isInstalled FROM module WHERE name=?";
        
    $res $this->ffcms->db->prepare($sql);
        
    $res->bind_param('s',$module);
        
    $res->bind_result($isInstalled);
        
    $res->execute();
        if(
    $res->fetch() && $isInstalled) {
          
    $res->free_result();
          if(
    is_dir("./modules/".$module) && file_exists("./modules/".$module."/".$module.".class.php") {
            return 
    true;
          }
        }
        return 
    false;
      }
      public function 
    loadModule($module) {
        require_once 
    "./modules/".$module."/".$module.".class.php";
        
    $object = new $module();
        
    $sql "SELECT class FROM module_requires WHERE module_id=(SELECT id FROM module WHERE name=?)";
        
    $res $this->ffcms->db->prepare($sql);
        
    $res->bind_param('s',$module);
        
    $res->bind_result($class);
        
    $res->execute();
        while(
    $res->fetch()) {
          
    $object->$class $this->ffcms->$class;
        }
        return 
    $object;
      }
    }

    // core.class.php

      
    public function run_test() {
        
    $this->ffcms->test->test();
      }

    // ./modules/test/test.class.php

    class test {
      private 
    $db;
      private 
    $user;
      public function 
    test() {
        
    print_r($this->db);
        
    print_r($this->user);
      }
      public function 
    __set($id,$element) {
        if(!isset(
    $this->$id)) $this->$id $element;
      }

    Es funktioniert soweit prima. Aber wie gesagt, vielleicht entdeckt jemand in dem Konzept noch Schwachstellen, dann freue ich mich über eine Antwort.


  • #2
    Der Code ist unvollständig.
    --

    „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
    Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


    --

    Kommentar


    • #3
      Er ist gekürzt, wie im Einleitungstext steht. Wenn mehr benötigt wird gerne auch das, dachte das wären alle relevanten Code-Teile

      Edit: Was fehlt dir denn?

      Kommentar


      • #4
        Edit: Was fehlt dir denn?
        • Die wirklich relevanten Code-Teile.
        • Eine generische DI-Implementierung.
        • Einen echten Anwendungsfall mit mehreren Modulen, die frei auf einer Seite platziert ausgegeben werden.
        • ...
        Viele Grüße,
        Dr.E.

        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        1. Think about software design before you start to write code!
        2. Discuss and review it together with experts!
        3. Choose good tools (-> Adventure PHP Framework (APF))!
        4. Write clean and reusable software only!
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        Kommentar


        • #5
          Zitat von dr.e. Beitrag anzeigen
          • Die wirklich relevanten Code-Teile.
          • Eine generische DI-Implementierung.
          • Einen echten Anwendungsfall mit mehreren Modulen, die frei auf einer Seite platziert ausgegeben werden.
          • ...
          Das ist absolut nicht böse gemeint, also bitte nicht so auffassen.
          * Die relevanten Code-Teile die meine Frage betreffen sind alle vorhanden. Im speziellen wären das eigentlich nur die elseif-Bedingung in der Methode diRegistry->di(), welche von diRegistry->__get() aufgerufen wird, und die zugehörigen Methoden in der modules-Klasse, isInstalled() und loadModule()

          * generische DI-Implementierung <- Tut mir leid, könntest du das spezifizieren? Wie gesagt, alles was die DI-Implementierung betrifft ist bereits enthalten, daher weiß ich nicht genau was dir da fehlt?
          * Ich kann gerne morgen mal einen simplen, konkreten Anwendungsfall vorbereiten, mit Test-Modulen. Ich verstehe nur den nutzen in Bezug auf meine Fragestellung nicht. Mir geht es ja nicht um "praktische Funktionalität". Das diese gegeben ist weiß ich bereits.
          Worum es mir geht sind mögliche Schwächen in der Theorie des angewendeten Konzepts.
          * ... <-- Wie gesagt, ich generiere gerne mehr Code zur Verdeutlichung des Ablaufs, ich sehe halt nur noch nicht den Nutzen darin in Bezug auf meine Fragestellung. Mal davon abgesehen, dass "..." doch schon ziemlich verallgemeinernd gewählt ist.




          Nochmal, alles nicht böse gemeint, ich freue mich über konstruktive Antworten, aber ich denke oft sehr rational, und gerade wenn es um Programmierung geht formuliere ich auchoft so.

          Vielleicht noch ein paar Sätze zur Funktionsweise:
          Die index.php ist komplett gepostet, da gibt es nur diese drei Zeilen. Alles andere wird über die run()-Methode der core-Klasse geregelt.

          Grundgedanke dieses Modells ist, dass keine Klasse mehr hard-gecoded instanziert werden muß, das wird alles automatisch von der diRegistry.class.php übernommen. Alle Klassen werden relativ zur __get-Methode in dieser Klasse angesprochen, und können somit direkt in ihren public-Eigenschaften und public-Methoden angesprochen werden.
          Objekte werden automatisch über die diRegistry->__get()-Methode erzeugt. Wird ein Objekt angefragt, dass bereits existiert, so wird es aus dem $values->array zurpckgegeben.
          Wird ein Objekt angefordert, welches noch nicht existiert, so wird in der Funktion di() als erstes überprüft, ob es in der Tochterklasse ffcms.class.php eine core-Methode zum erzeugen dieser Klasse gibt, andernfalls wird in der elseif-Bedingung geprüft, ob eine Modul-Klasse des angeforderten Objektes installiert ist, wenn ja wird dynamisch eine Instanz der angeforderten Klasse erstellt. Die für die Klasse benötigten Instanzen werden ermittelt aus einer db-Tabelle und an die Klasse übergeben. Dadurch werden Module eben dynamisch implementierbar/einsetzbar. Jede benötigte Klasse für Module kann zur Instanzierung und Zuweiseung der benötigten Objekte dynamisch herangezogen werden, da die ffcms.class.php (erbend von diRegistry.class.php) $this an den Konstruktor des modules-Objektes übergibt.

          Kommentar


          • #6
            Hallo,

            PHP-Code:
            // ffcms.class.php (extends diRegistry) 
            Hier würde ein

            PHP-Code:
            class ffcms extends diRegistry {
               ...

            wesentlich besser zur Verdeutlichung beitragen. Anders sieht es so aus, als ob du Dinge nicht preisgeben möchtest.

            Weiterhin halte ich ein extends hier für einen Fehler, denn was hat Modell-technisch ein CMS mit einer Registry zu tun. Ebenso fraglich ist, wie eine Klasse ein komplettes CMS abbilden kann. Sofern das so designed ist, ist das sinnlos und wiedersprich jeglichen Paradigmen von OO.

            Das ist absolut nicht böse gemeint, also bitte nicht so auffassen.
            Ich bin der letzte, der das böse auffasst, diese Aussage entbindet dich jedoch nicht des mitdenkens und stellt keine globale Rechtfertigung für Fachlichkeiten deinerseits dar.

            * Die relevanten Code-Teile die meine Frage betreffen sind alle vorhanden. Im speziellen wären das eigentlich nur die elseif-Bedingung in der Methode diRegistry->di(), welche von diRegistry->__get() aufgerufen wird, und die zugehörigen Methoden in der modules-Klasse, isInstalled() und loadModule()
            Das Registry-Pattern hat erstmal nichts mit DI zu tun und DI sollte als eigenständiger Container unabhängig von expliziten Services implementiert sein. Hier ist insbesondere dein "extends" Gift und es ist auch nicht sinnvoll Services eines CMS in diesem selbst als Erweiterung einer Registry zu erzeugen. DI bedeutet, dass du einer Komponente andere Komponenten einimpfst und nicht umgekehrt.
            Sofern ein CMS - oder besser eine CMS-Business-Komponente - einen Datenbank-Zugriff benötigt, so muss es einen DI-Container geben, der diese Abhängigkeit kennt und mit in meiner Präsentations-Komponente durch Aufruf des Containers mit dem zugehörigen Service bereits den initialisierten Service gibt. Ich muss in meiner Komponente daher keine Kenntnis darüber besitzten, was die andere für Abhängigkeiten hat, ich muss nichtmal den Ort kennen, an dem der Service implementiert ist. Mir reicht hier die Kenntnis des Interfaces des Services, denn nur so ist er austauschbar und die Software im Rahmen von Unittests testbar.

            * Ich kann gerne morgen mal einen simplen, konkreten Anwendungsfall vorbereiten, mit Test-Modulen. Ich verstehe nur den nutzen in Bezug auf meine Fragestellung nicht. Mir geht es ja nicht um "praktische Funktionalität". Das diese gegeben ist weiß ich bereits.
            Worum es mir geht sind mögliche Schwächen in der Theorie des angewendeten Konzepts.
            Ich bitte um einen Anwendungsfall. Schwächen bzw. konzeptionelle Fehler liegen auf der Hand: zu starke Kopplung, schlechte Testbarkeit, keine Schachtelung von Modulen möglich.

            * ... <-- Wie gesagt, ich generiere gerne mehr Code zur Verdeutlichung des Ablaufs, ich sehe halt nur noch nicht den Nutzen darin in Bezug auf meine Fragestellung. Mal davon abgesehen, dass "..." doch schon ziemlich verallgemeinernd gewählt ist.
            Nun sei du mir nicht böse: sofern die obigen Punkte noch nicht gelöst sind, werde ich auch keine Detail-Anmerkungen abgeben.
            Viele Grüße,
            Dr.E.

            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            1. Think about software design before you start to write code!
            2. Discuss and review it together with experts!
            3. Choose good tools (-> Adventure PHP Framework (APF))!
            4. Write clean and reusable software only!
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            Kommentar


            • #7
              Hey dr.e.,

              vielen Dank für deine Ausführungen soweit schonmal. Ich bin dir ebenfalls keineswegs böse.
              Leider bin ich grad nur kurz im Inet-Cafe online und habe keine Zeit mir das genauer zu Gemüte zu führen und einen konkreten Anwendungsfall zu posten.
              Ich werde das aber nächste Woche nachholen.

              Mit einigen von dir angesprochenen Punkten kann ich aber schon etwas anfangen. Ich stehe gerade noch ziemlich am Anfang in Sachen wirklicher OOP und Dependency Injection habe ich diese Woche das erste Mal gehört, daher auch meine Frage ob mein gedachtes Konzept Sinn macht.

              Also bis hierhin schonmal wie gesagt, vielen Dank. Sobald ich nächste Woche wieder mehr Luft habe werde ich das ganze auf jedenfall mal ausführlicher posten und würde mich dann sehr über weitere konstruktive Kritik freuen.
              Die Zusammenkürzung beim bisher geposteten Code hatte auf jedenfall nichts damit zu tun, dass ich irgendetwas nicht preisgeben möchte, sondern viel mehr damit, dass ich nicht zuviel "unnützen" Code posten und das ganze damit weniger übersichtlich machen wollte.

              Kommentar

              Lädt...
              X