Ankündigung

Einklappen
Keine Ankündigung bisher.

Best Practice bei Dependency Injections

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

  • Best Practice bei Dependency Injections

    Hallo,

    Ich frage mich was der beste Weg ist um Abhängigkeiten zu definieren die dann ein DIContainer injizieren kann:

    1. Konfigurationsdatei
    Dependencies Konfigurationsdatei:
    PHP-Code:
    return array(
         
    'UselessClass' => array(
              
    'storage' => 'ExampleDatabaseClass',
              
    'lorem' => 'Ipsum',
         ),
    ); 
    Die Abhängigkeiten werden dann über Setter Injections eingeimpft, d.h. im oberen Beispiel würde der Methode setStorage ein Objekt der Klasse ExampleDatabaseClass und setLorem ein Objekt von Ipsum übergeben.

    2. Array in Klasse
    Im Grunde genommen das exakt gleiche, das Array befindet sich statt in einer externen Konfigurationsdatei direkt im Code der Klasse.

    Mehr Möglichkeiten sind mir noch nicht eingefallen, bin aber sicher dass es noch mehr gibt. Welche eignet sich am besten?

    Nächste Frage: Wie sollte der DIContainer umgesetzt sein?

    1. statische Methode
    PHP-Code:
    Container::create('UselessClass'); 
    Macht aber spätistens dann Probleme wenn man noch vor der Erzeugung des Objekts die konfigurierten Abhängigkeiten ändern will. Im Nachhinein würde das natürlich gehen, die Klasse des zurückgegebenen Objekts besitzt ja die Setter-Methoden:
    PHP-Code:
    Container::create('UselessClass')->setStorage(new ExampleFileClass()); 
    2. eigenes Objekt
    PHP-Code:
    Container::factory('UselessClass')->setStorage('ExampleFileClass')->create();
    Container::factory('UselessClass')->setStorage(new ExampleFileClass())->create(); 
    Die factory()-Methode dient in diesem Beispiel wieder nur zur Ermöglichung eines Fluent Interfaces, das Objekt wird erst beim Aufruf von create() erstellt, die Abhängigkeiten können so schon vor der Erstellung des Objektes geändert werden.
    Hier kann man als Parameter entweder ein Objekt an setStorage() übergeben oder aber die Klasse von der dann wiederum über den DIContainer ein Objekt erzeugt wird.

    Bin jetzt hier natürlich für 1. Option für die Definierung und 2. Option für die Erzeugung, mich interessieren aber vorallem weitere, hier nicht aufgezählte Möglichkeiten, mögliche Verbesserungsvorschläge etc.

    Freue mich sehr über Antworten: Vielen Dank im Voraus

    bitsnack
    Programming today is a race between developers striving to build better idiot-proof programs, and the universe trying to produce better idiots. So far, the universe is winning.


  • #2
    Bitte Suche nutzen:
    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


    • #3
      Ich favorisiere aktuell Annotationen. Bibliotheken gibt es dafür verschiedene. Beispielsweise bei Doctrine Common ist eine dabei.

      Beispielsweise beschrieben hier und hier

      Kommentar


      • #4
        Zitat von mquadrat
        Ich favorisiere aktuell Annotationen. Bibliotheken gibt es dafür verschiedene. Beispielsweise bei Doctrine Common ist eine dabei.

        Beispielsweise beschrieben hier und hier
        Annotations sind für Einzel-Entwicklungen durchaus praktisch. Sobald man im Team arbeitet, hat man erhöhte Dokumentationsrate sowie ein paar andere Dinge, die mir nicht gefallen.

        Man sollte immer Abwegen, ob Annotations nicht direkt im Code untergebracht werden können.

        Desweiteren hat das ganze Annotation geraffel einen großen Nachteil: Reg-Ex. Wenn man Performant bleiben will sollte man alles, was mit Reg-Ex umgesetzt wird, vermeiden. Natürlich gibt es auch Punkte, bei denen Reg-Ex direkt Sinn macht, allerdings sind Annotations meiner Meinung nach keiner davon. Den einzigen Vorteil den ich daran sehe ist, dass man sich ein wenig Code spart.

        Zu deinen Container: Hatte Symfony nicht mal eine schöne Lösung zwecks DI?
        true||false - www.trueorfalse.de - Rund um Software Entwicklung

        Kommentar


        • #5
          Jep, Symfony hat einen DI-Container. Man kann (wie in dem einen Link beschrieben) die Konfiguration über die Annotations machen und das ganze dann via Symfony als Plain PHP exportieren. Oder man nimmt den Cache, den einen die Doctrine Annotations anbieten. Wenn man das im User-Cache ablegt hat man eigentlich keine Probleme mehr mit der Performance.

          Erhöhte Dokumentationsrate? Aus meiner Sicht führt die Verwendung von Annotations nicht automatisch zu mehr Dokumentation. Ich tendiere sogar fast zum Gegenteil, den man spart sich die Dokumentation der Konfiguration.

          Bei einer Property direkt sagen zu können, dass diese über DI injected wird erspart zum einen, das Nachschauen in der Konfiguration und Kollegen im Team wissen auch sofort was Sache ist und fangen nicht erst an zu suchen, wo sie nun den Service herkriegen.

          Ich stimme natürlich zu, dass es wesentlich schöner wäre, wenn Annotations direkt in PHP integriert werden, als den Umweg über die Kommentare zu nehmen.

          Kommentar


          • #6
            PHP-Code:
            /**
             * @Services({
             *   @Service(
             *    class="\de\ifschleife\ADependency",
             *    constructorArgs={
             *      "pong"
             *    }
             *  ),
             *  @Service(
             *    class="\de\ifschleife\AnotherDependency",
             *    constructor={"\de\ifschleife\AnotherDependency", "getAnotherDependency"}
             *  ),
             *  @Service(
             *    class="\de\ifschleife\YetAnotherDependency",
             *    constructor="makeYetAnotherDependency"
             *  )
             * })
             */ 
            Wenn ich sowas sehe rollen sich mir die Fußnägel hoch. Ein Kommentar ist immer noch ein Kommentar und potentiell löschbar. Und warum man dieses - Geraffel ist wirklich das richtige Wort - nicht gleich als Code abbildet erschließt sich mir nicht.

            [edit]

            LOL, vor allem:
            $test = new \de\ifschleife\DITest();
            Da fällt einem nicht mehr viel ein.
            --

            „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


            • #7
              Zitat von nikosch Beitrag anzeigen
              ...

              LOL, vor allem:

              $test = new \de\ifschleife\DITest();
              Da fällt einem nicht mehr viel ein.
              Ich glaube, der Autor ist sich dessen bewusst, dass es keine If-Schleifen gibt. Zumindest deutet dieser Text auf seiner Homepage darauf hin:

              *) Einfach nur auf der Suche nach der If-Schleife? Dann hier entlang.
              Namespaces im Java-Style zu verwenden führt halt zu Problemen, wenn man lustig( gemeint)e Domains registiert hat ...
              Wenn man die Wurst schräg anschneidet, hält sie länger, weil die Scheiben größer sind.

              Kommentar


              • #8
                Ach so. Nun gut.
                --

                „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


                • #9
                  Ja,das Beispiel ist sicher wenig glücklich. Würde ich so auch nicht benutzen wollen. Als einzige Parameter würde ich mir noch einen Dienstnamen gefallen lassen. MEF in .NET löst das finde ich wirklich nett.

                  Das Annotationen in den Kommentaren nicht die Beste aller Lösungen ist, dürfte auch klar sein. Aber in meinen Augen beim Thema DI immer noch besser als XML oder YML Dateien.

                  Das Beispiel trifft es denke ich besser.

                  PHP-Code:
                  /**
                       * Description of Default_Service_TestService
                       *
                       * @author Loïc Frering <loic.frering@gmail.com>
                       * @Service
                       */
                      
                  class Default_Service_TestService
                      
                  {
                          
                  /**
                           * @var Default_Service_TestService2
                           */
                          
                  protected $_testService2;
                       
                          
                  /**
                           * @param Default_Service_TestService2 $testService2
                           * @return Default_Service_TestService
                           * @Inject
                           */
                          
                  public function setTestService2($testService2)
                          {
                              
                  $this->_testService2 $testService2;
                              return 
                  $this;
                          }
                       
                          public function 
                  test()
                          {
                              return 
                  'Test method from TestService';
                          }
                       
                          public function 
                  test2()
                          {
                              return 
                  $this->_testService2->test2() . ' called from testService';
                          }
                      } 
                  Bei Properties muss man das Type-Hinting ja sowieso über die Kommentare machen. Insofern stört nun eine @-Direktive in den Kommentaren mehr auch nicht. Sinnvollerweise halt auf das @Service und @Inject beschränkt. Um alles andere hat sich der DI-Container zu kümmern, wenn da wieder konkrete Klassennamen drin stehen hat man ja nichts gewonnen.

                  Kommentar


                  • #10
                    Um alles andere hat sich der DI-Container zu kümmern, wenn da wieder konkrete Klassennamen drin stehen hat man ja nichts gewonnen.
                    Und warum steht dann bei
                    $_testService2 ein @var Default_Service_TestService2? Egal ob das nun als Annotation oder in einer XML-/YAML-Datei definiert ist, irgendwo musst du Farbe bekennen.

                    Der meiner Ansicht nach definitive Vorteil von "externen" Dateien ist, dass Code von Konfiguration bzw. Service-Definition von der Implementierung getrennt wird. Die Annotation-Geschichte vermischt wieder beides und wenn du in einem Service A mal eine andere Implementierung des Service B brauchst, musst du Code ändern. Das ist nicht DI!

                    Annotationen mögen vielleicht für O/R-Mappern ganz brauchbar sein, da da die Abhängigkeiten statisch sind, nicht aber für dynamische Services, denen ich jetzt eine echte Implementierung geben möchte und wenn ich nachher im Zug nach Hause sitze eine MOCK-Schicht. Das muss meiner Ansicht nach getrennt sein und ist auch der Grund, warum das in allen gängigen Produkten (z.B. bei SPRING im JAVA-Bereich, APF im PHP-Bereich) so gehandhabt wird.
                    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


                    • #11
                      Ah, ich verstehe was dich an dem Beispiel stört. Die Frage ist woher weiß der DI-Container, welche konkrete Implementation er für ein Service-Interface injecten soll. Das darf natürlich NICHT in der Klasse stehen, in die injected wird. Dort darf immer nur das Interface stehen.

                      Die Wahl der konkrete Implementation könnte man natürlich in den Konfigurationsdateien festlegen und sollte nicht fest im Code stehen. Eine andere Möglichkeit wäre den Katalog des DI-Containers über einen File-Scan schauen zu lassen welche Klasse, welches Interface implementiert. Macht natürlich nur Sinn, wenn es jeweils nur eine Implementierung gibt. Fest gekoppelt ist aber nichts.

                      Aber ich gebe zu der Eindruck kann leicht entstehen wenn man die Blog-Posts des Autors des Beispiels nicht gelesen hat. Womit mal wieder gezeigt wäre, dass nicht alle Beispiele gute Beispiele sind.

                      PHP-Code:
                      class GanzNormaleKlasse {

                        protected 
                      $serviceXYZ;

                        
                      /**
                         * @inject IServiceXYZ
                         */
                        
                      public function setService($service) {
                            
                      $this->serviceXYZ $service;
                        }


                      PHP-Code:
                      class ServiceXYZImplementation1 implements IServiceXYZ {


                      Zuordnung dann wie geschrieben in Konfig-Datei oder über Annotationen und File-Scan.


                      @OT
                      In Spring kann man doch auch Annotationen verwenden, wenn ich nicht irre. Auch die meisten .NET DI-Container verwenden Annotationen, aber dort sind die ja auch fester Bestandteil der Sprache.

                      Kommentar


                      • #12
                        Wie du schon sagst: Annotationen sind nur für die eindeutige Auflösung zu gebrauchen. Ob das ein Sprach-Konstrukt ist oder nicht. Alles andere ist Abenteuer pur!
                        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


                        • #13
                          Tut mir leid dass ich mich bisher nicht mehr gemeldet habe, ich musste mich erstmals zu den hier neu aufgetauchten Begriffen informieren.

                          Erstmal zum Service-Locator: Hier fordert eine Klasse A selbst das Objekt der konfigurierten Klasse B zu einem bestimmten Interface C, annähernd richtig? Sehe hier keinen grossen Vorteil da man so beim Erstellen eines Objektes der Klasse A keinen Einfluss darauf hat, welche Klassen genutzt werden, man kann also keine nicht-konfigurierten Objekte erstellen was schlussendlich wieder dazu führt dass man genauso gut das Objekt normal erstellen könnte und nur die Möglichkeit hat etwas einfacher die zu nutzenden Klassen zu konfigurieren.

                          Beim DI wird ein Objekt der Klasse B mit einem bestimmten Interface C in die Klasse A injiziert wie der Name ja schon sagt. Hier kann man also an jeder Stelle das Erzeugen des Objektes der Klasse A beeinflussen und zusätzlich alles komfortabel konfigurieren.

                          Ich hatte leider noch keine Zeit oder keinen Mut diese beiden Dinge praktisch auch anzuwenden, zumindest nicht in richtigen Applikationen, ich kann mich deshalb noch nicht entscheiden ob es besser wäre generell die konfigurierte Klasse mit angegebenem Interface zu laden oder für jeden Anwendungsfall etwas benanntes zu konfigurieren?

                          Was sind die Vor- und Nachteile der beiden Möglichkeiten?
                          Oder sonstige Aspekte zu diesem Thema?
                          Programming today is a race between developers striving to build better idiot-proof programs, and the universe trying to produce better idiots. So far, the universe is winning.

                          Kommentar


                          • #14
                            DI ohne Container:
                            - erzeugt mehr Code.
                            - braucht gut überlegte Konzepte für Scopes von Variablen

                            DI mit Container/externem Setting + SL:
                            - benötigt eine Konfigurationsmöglichkeit
                            - Abhängigkeiten (Bekannsein) bestimmter Klassen
                            - FooBar - mehr Voodoo und damit höherer Dokumentationsbedarf
                            --

                            „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


                            • #15
                              Werde es wohl bestimmt mit einem Container umsetzen, nur eben: benannte Konfigurationen für jeden Anwendungsfall oder einfaches Anfordern der Klasse und wie gewünscht anpassen ($container->setStorage($database)->create('UserModel'))?

                              Könntet ihr mir einige konkrete und praktische Beispiele vorstellen? Ich kann mir bei dem ganzen Thema irgendwie noch nichts wirklich vorstellen. Wenn ich z.B. das Objekt für Storage selbst setze, wie erzeuge ich dann wieder dieses? Wenn ich die verschiedenen Konfigurationen benenne fällt mir leider auch kein gutes Beispiel dafür ein.
                              Programming today is a race between developers striving to build better idiot-proof programs, and the universe trying to produce better idiots. So far, the universe is winning.

                              Kommentar

                              Lädt...
                              X