Ankündigung

Einklappen
Keine Ankündigung bisher.

DI-Container Key

Einklappen

Neue Werbung 2019

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

  • #31
    Zitat von dr.e. Beitrag anzeigen
    Hast du dir mal die Implementierung von bereits vorhandenen Produkten angesehen?
    ja klar, habe ich. im laufe des beitrages erwähne ich pico, zend di, symfony di, guice, pinject und selbst den des apf's habe ich mir (doku) angehesen.

    momenan tendiere ich definitiv zu google guice (und pinject), das konzept ist ist etwas anders als von den anderen.

    Kannst du dies nicht einfach verwenden
    doch klar, aber vorab möchte ich mir sicher sein welchen ich nutzen möchte.

    Kommentar


    • #32
      Solange beides in Anführungszeichen steht isses recht egal, ob Servicename, der über eine Konfiguration aufgelöst wird oder direkt das Interface (Mehrfachverwendung mal außen vor). Syntax-Check wird so oder so nicht funktionieren.

      Tendentiell würde ich sagen, dass man in fast allen Fällen der Argumentation Service = Interface folgen kann. Durch das direkte Angeben des Interface hast du ggf. das Lookup gespart. Sofern du den Service in den DIC injectest. Ansonsten musste ja auch erst mal rausfinden, welche Klasse jetzt eigentlich das Interface implementiert.

      Der Punkt ist doch eher: Die Klasse, in die injected wird hat als einzige verlässliche Information das Inteface der injecteten Klasse. Welche Konfiguration dahinter steckt, ist der Klasse unbekannt. Die Klasse benötigt den Service, der etwas Spezifisches tut. Daher kommt die Idee, dass es eigentlich nie mehr als eine Implementierung eines Service-Interfaces gleichzeitig geben kann. Sieht man es jetzt von der anderen Seite, also dem Framework / Container, dann möchte man bestimmen welche Implementierung injected wird. Aus dieser Sicht, kann es also sehr wohl vorkommen, dass verschiedenen Klassen verschiedene Serviceimplementierungen injected werden.

      Fazit: Ein Container sollte beides können. In .NET (ich meine es wäre Unity) geht die Standardvariante allein über das Interface. Benötigt man mehrere Implementierungen wird zusätzlich mit Bezeichnern gearbeitet.

      Kommentar


      • #33
        Nicht zu vergessen muss ein Objekt nicht allein durch ein Interface beschrieben werden. Ein Interface kann auch nur eine Menge von Methoden beschreiben, die zwingend vorhanden sein sollen. Wie will man denn dann verfahren? Noch Parameter für meherere Interfaces einrichten? Mir erscheint das alles Unsinn. Ob ein Inject brauchbar ist, kann letztlich nur die nutzende Klasse entscheiden.
        --

        „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


        • #34
          Ich denke mittlerweile, eine Kombination aus Interface und optionalem Bezeichner klingt am besten. Das einzige, was mich da immer noch stört, ist, dass man bei externen Bibliotheken, die über den DI-Container genutzt werden sollen, noch mal ableiten muss, was zu Nebeneffekten führen kann, wenn die Bibliothek z. B. get_class benutzt.

          Kommentar


          • #35
            Wieso muss man nochmal ableiten?




            Und da wahrscheinlich mit Unity hier nicht so viele was anfangen können, mal ne Konfiguration:

            Code:
              
            <unity>
                <containers>
                  <container>
                    <types>
                                <type name="Alarm"
                                    type="IoCContainers.Components.Functions.IFunctionState, IoCContainersUnity"
                                    mapTo="IoCContainers.Components.Functions.AlarmFunctionState, IoCContainersUnity" />
            
                                <type name="NewLine"
                                    type="IoCContainers.Components.Functions.IFunctionState, IoCContainersUnity"
                                    mapTo="IoCContainers.Components.Functions.NewLineFunctionState, IoCContainersUnity"/>
            
                                <type name="Calculator"
                                    type="IoCContainers.Components.Functions.IFunctionState, IoCContainersUnity"
                                    mapTo="IoCContainers.Components.Functions.CalculatorFunctionState, IoCContainersUnity"/>
                    </types>
                  </container>
                </containers>
              </unity>

            Kommentar


            • #36
              Wieso muss man nochmal ableiten?
              Wenn Man einen Service anhand eines Interfaces identifizieren will, muss der entsprechende Service dieses ja auch implementieren. Wenn man jetzt aber z. B. Doctrine benutzen will, hätte ich nicht unbedingt Lust, der Doctrine-Klasse das Interface hinzuzufügen.

              Kommentar


              • #37
                Ich kann doch auch direkt die Klasse registrieren. Dann würde sich die Aufgabe des DI-Containers eben auf das Lifecycle-Management beschränken. Aber im geschilderten Fall ist es ja eher unwahrscheinlich, dass man die Implementierung mit etwas anderem ersetzen möchte. Da würde ich es mit Fowler halten und erst erweitern, wenn der Fall tatsächlich eintritt.

                Kommentar


                • #38
                  Aber im geschilderten Fall ist es ja eher unwahrscheinlich, dass man die Implementierung mit etwas anderem ersetzen möchte. Da würde ich es mit Fowler halten und erst erweitern, wenn der Fall tatsächlich eintritt.
                  Wenn ich zum Testen statt dessen ein Mock übergeben will, ist das IMHO überhaupt kein ungewöhnlicher Vorgang.
                  --

                  „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


                  • #39
                    Ich kann doch auch direkt die Klasse registrieren.
                    Das ist einer der Punkte, der durch DI vermieden werden soll.

                    Da würde ich es mit Fowler halten und erst erweitern, wenn der Fall tatsächlich eintritt.
                    Welcher eintritt, wenn man eine andere Bibliothek einbinden möchte.

                    Kommentar


                    • #40
                      Da will ich ja gar nicht widersprechen, aber die Aussage war, dass weder die Bibliothek geändert noch ein Adapter geschrieben werden soll. Und dann bleibt mir nichts anderes als die Klasse selber zu registrieren. Wobei das in PHP ja auch nicht 100%-richtig ist, je nachdem ob man Type-Hinting benutzt oder nicht.

                      Zum Mocken könnte man in dem Fall noch das Mock-Object von der Bibliothek erben lassen.


                      EDIT: Mir ist in einem anderen Forum gerade duck-typing über den Weg gelaufen. Wäre eine elegante Lösung für: Ich will Interfaces, kann aber die Bibliothek nicht anfassen http://blogs.remobjects.com/blogs/mh/2011/07/01. Zumindest in typsicheren Sprachen bzw. PHP mit Type-Hinting

                      Kommentar


                      • #41
                        sollte jemand mal eine blick auf meine ersten versuche werfen wollen:

                        https://github.com/timglabisch/pimDI...est/diTest.php

                        bitte beachten, dass ich den fokus momentan nur darauf gelegt habe, die tests zu bestehen, aufräumen steht nun an, demnach unperformant und unelegant sieht atm. der dic aus.

                        das ganze ist auch noch völlig unvollständig, die tests besteht er aber wunderbar und alles hier erwähnte funktioniert schon

                        momentan kann man klassen an interfaces binden, wenn man möchte kann man einen "concern" mitgeben.

                        durch die annotation @inject wird eine klasse automatisch einem objekt injiziert. (siehe testBasicInjection). dabei muss nicht angegeben was injiziert werden soll, dieses ergibt sich aus dem interface des parameters. möchte man einen "concern" mit angeben schreibt man einfach die annotation: @inject [CONCERN].
                        das geht natürlich für beliebig viele parameter.

                        anders als viele dic's ist shared bei mir standardmäßig auf false.

                        Kommentar


                        • #42
                          if(method_exists($className, '__construct'))
                          $instance = call_user_func_array(array($className, '__construct'), array());
                          else
                          $instance = new $className();
                          Wozu denn das?

                          Ich stehe da irgendwie auf dem Schlauch: Wofür ist dieses Shared gut?

                          Kommentar


                          • #43
                            shared gibt an ob eine neue Instanz oder die alte genutzt wird.

                            eine datenbank ist z.b. oft shared. bitte die DI Klasse noch nicht zu genau anschauen sondern die Api, (Tests). Shared ist auch getestet.

                            PHP-Code:
                            public function testSharedDefault() {
                                   
                            $di = new di();

                                   
                            $di->bind('istd')->to('std1');
                                   
                            $this->assertTrue($di->get('istd') !== $di->get('istd'));
                                }

                                public function 
                            testIsShared() {
                                   
                            $di = new di();

                                   
                            $di->bind('istd')->to('std1')->shared(true);
                                   
                            $this->assertTrue($di->get('istd') === $di->get('istd'));
                                } 
                            === vs !==

                            den DI selber refactoriere ich noch komplett mir ging es vorab um die API !

                            bitte auch beachten, dass dies nur ein teil des fertigen DiC ist, wird natürlich alles ausgebaut.

                            Kommentar


                            • #44
                              @notyyy

                              Naja ist halt ein fluent Inteface, Die mag man oder eben nicht


                              @DI allgemein

                              Es wäre viel einfacher, wenn sich die Leute mal auf einheitliche Benennungen einigen würden. Shared / Non-Shared. Recyceld / Singleton. Oder mein Favorit: Übergeben eines LifetimeManagers ohne weitere Bennenung um ein Singleton-Verhalten zu kriegen.

                              Kommentar


                              • #45
                                Zitat von mquadrat Beitrag anzeigen
                                @notyyy

                                Naja ist halt ein fluent Inteface, Die mag man oder eben nicht
                                in diesem thread geht es NUR um den DI-"key". ich zeige einen Ansatz wie man eine Klasse an ein Interface binden kann..

                                das Schlüsselwort "shared" hab ich aus dem symfony DI "geklaut"

                                Kommentar

                                Lädt...
                                X