MB.: Wo sind allgemein Static, Interface Klassen in MVC in ihrer Funktion Sinnvoll?

Moin Community,

der Betreff sagt eigentlich alles. Ich hab Konfigurations-Dateien final gemacht und ziehmlich viel in diesem Bereich mit static gearbeitet.

  • 1: Ist static in einer klasse sinvoll die nur einmal verwendet wird und das immer wieder? z.B. in den ganzen Controller klassen und Core Klassen in dem z.B. Router Klasse und App Klasse was die die Router Klasse aufruft.

  • 2: Wie stehts mit interface? MVC ist ja mehr oder weniger sehr komplex. Da lohnt es sich interface zu verwenden. Ich aber nie sinvoll interfaces verwendet.

vlg MB

PS: Ich hab viele Softwarelösungen in MVC mir angeschaut, gut und weniger gut. Und auch welche von euch.

  1. Kurz und knapp:

    1. static: für die Config sinnvoll, wie das Schlüsslwort schon sagt, kann eine config sogar persistent im Hauptspeicher liegen (mod_perl, mod_php...), unsinnig ist static für ein Objekt, was verschiedene Views erzeugen soll (genauso blödsinnig ist es gerenderte Templates zu cachen)
    2. interface: Immer sinnvoll, wenn es sich wiederholende Abläufe gibt. Und das ist bei Request-Response-Zyklen auf jeden Fall der Fall ;)

    MfG

    1. genauso blödsinnig ist es gerenderte Templates zu cachen

      #!/bin/bash
      echo 'genauso blödsinnig ist es gerenderte Templates zu cachen' | sed '~s/ist es/erscheint es manchem/' | sed '~s/gerenderte Templates/erzeugte HTML-Dokumente/';
      

      "Blödsinnig" ist das eigentlich nur, wenn man es mit ungeeigneten Inhalten oder auf eine ungeeignete Weise versucht. Für quasistatische Inhalte lohnt sich das durchaus und hat auch schon die Wirksamkeit von DDOS-Attacken auf meinen Webauftritt verhindert.

      1. "Blödsinnig" ist das eigentlich nur, wenn man es mit ungeeigneten Inhalten oder auf eine ungeeignete Weise versucht. Für quasistatische Inhalte lohnt sich das durchaus und hat auch schon die Wirksamkeit von DDOS-Attacken auf meinen Webauftritt verhindert.

        Übers Cachen sollte der UserAgent entscheiden. Und das kann er auch, wenn das Cachen nach bewährten sowie standardisierten Verfahren erfolgt wie z.B. über einen Last-Modified HTTP Header -- Da kann der Anwender im Zweifelsfall den Cache selbst löschen oder ein Force Reload machen.

        Wenn aber z.B. der aktuelle Monat ins Template gerendert wird und aufgrund einer Fehlkonfiguration mit expires > 2 Monaten serverseitig gecached wird, hat der Anwender keine Chance auf eine aktuelle Seite.

        MfG

        1. Hallo pl,

          "Blödsinnig" ist das eigentlich nur, wenn man es mit ungeeigneten Inhalten oder auf eine ungeeignete Weise versucht. Für quasistatische Inhalte lohnt sich das durchaus und hat auch schon die Wirksamkeit von DDOS-Attacken auf meinen Webauftritt verhindert.

          Übers Cachen sollte der UserAgent entscheiden. Und das kann er auch, wenn das Cachen nach bewährten sowie standardisierten Verfahren erfolgt wie z.B. über einen Last-Modified HTTP Header -- Da kann der Anwender im Zweifelsfall den Cache selbst löschen oder ein Force Reload machen.

          Es gibt verschiedene Layer von Caching. Caching am User-Agent ist sinnvoll und gut, aber es verhindert nicht eine erhöhte Last auf dem Server. Dafür ist serverseitiges Caching gut und sinnvoll und wird gerne angewandt; gerne auch in Form eines reverse proxies wie HAProxy oder sogar mit nginx.

          Wenn aber z.B. der aktuelle Monat ins Template gerendert wird und aufgrund einer Fehlkonfiguration mit expires > 2 Monaten serverseitig gecached wird, hat der Anwender keine Chance auf eine aktuelle Seite.

          Wenn ich etwas falsch mache geht etwas schief. Big news.

          LG,
          CK

          1. Es gibt verschiedene Layer von Caching. Caching am User-Agent ist sinnvoll und gut, aber es verhindert nicht eine erhöhte Last auf dem Server. Dafür ist serverseitiges Caching gut und sinnvoll und wird gerne angewandt; gerne auch in Form eines reverse proxies wie HAProxy oder sogar mit nginx.

            Caching via haproxy? Wie das? Im Zusammenspiel mit z.B. Varnish? Klar! Aber standalone? Wie das?

            1. Hallo Mitleser,

              Caching via haproxy? Wie das? Im Zusammenspiel mit z.B. Varnish? Klar! Aber standalone? Wie das?

              Ja, du hast recht, bei haproxy muss noch der Cache (z.B. Varnish) dazu kommen.

              LG,
              CK

        2. Tach!

          Übers Cachen sollte der UserAgent entscheiden.

          Das ist als pauschale Aussage nicht weiter sinnvoll. Wenn Systeme wie Mediawiki nicht serverseitig die gerenderten Seiten cachen würden, wäre das eine unnötig hohe Belastung des Servers. Die Inhalte bleiben statisch bis zum nächsten Edit. Es gibt keinen Grund, die Seite bei jedem Request eines anderen Clients neu zu rendern.

          Wenn aber z.B. der aktuelle Monat ins Template gerendert wird und aufgrund einer Fehlkonfiguration mit expires > 2 Monaten serverseitig gecached wird, hat der Anwender keine Chance auf eine aktuelle Seite.

          Das ist ein spezieller Anwendungsfall. Natürlich muss man bei sich ändernden Daten seine Caching-Strategie anpassen. Generell nicht serverseitig zu cachen, nur weil man dabei einen Fehler machen könnte, ist kein Argument.

          dedlfix.

          1. Hallo und guten Morgen,

            Das ist ein spezieller Anwendungsfall. Natürlich muss man bei sich ändernden Daten seine Caching-Strategie anpassen. Generell nicht serverseitig zu cachen, nur weil man dabei einen Fehler machen könnte, ist kein Argument.

            Man könnte ja auch Teile des Dokumentes cachen und andere nicht, oder? Mod_SSI gibt es ja auch noch... Das entspricht dann ja etwa dem Reverse-Proxy, wenn ich nicht ganz falsch liege.

            Grüße
            TS

            --
            es wachse der Freifunk
            http://freifunk-oberharz.de
            1. Tach!

              Man könnte ja auch Teile des Dokumentes cachen und andere nicht, oder?

              Ja, na klar, je nach Anwendungsfall. Zum Beispiel nur den Haupt-Inhalt, das Seitengerüst inklusive Navigation jedoch nicht. In Mediawiki zum Beispiel wäre es sonst ein zu großer Aufwand, bei Seitengerüst-Änderung alle Inhalte neu zu generieren.

              dedlfix.

        3. Übers Cachen sollte der UserAgent entscheiden. Und das kann er auch, wenn das Cachen nach bewährten sowie standardisierten Verfahren erfolgt wie z.B. über einen Last-Modified HTTP Header -- Da kann der Anwender im Zweifelsfall den Cache selbst löschen oder ein Force Reload machen.

          Wieso willst den Output für jeden Useragent partout (also bei unveränderten Inhalten) aufwendig neu erzeugen und dieses auch dann machen, wenn der Useragent behauptet, das Dokument nicht zu haben? Das kannst Du soweit treiben, dass Du eine Fotosammlung veröffentlichst und bei jedem Abruf den Fotograf nach Barcelona schickst...

          Wenn aber z.B. der aktuelle Monat ins Template gerendert wird und aufgrund einer Fehlkonfiguration mit expires > 2 Monaten serverseitig gecached wird, hat der Anwender keine Chance auf eine aktuelle Seite.

          Ich schrieb:

          "Blödsinnig" ist das eigentlich nur, wenn man es mit ungeeigneten Inhalten oder auf eine ungeeignete Weise versucht.

          Du lieferst ein Beispiel genau dafür, widersprichst mir aber?

        4. Übers Cachen sollte der UserAgent entscheiden. Und das kann er auch, wenn das Cachen nach bewährten sowie standardisierten Verfahren erfolgt wie z.B. über einen Last-Modified HTTP Header -- Da kann der Anwender im Zweifelsfall den Cache selbst löschen oder ein Force Reload machen.

          Wenn aber z.B. der aktuelle Monat ins Template gerendert wird und aufgrund einer Fehlkonfiguration mit expires > 2 Monaten serverseitig gecached wird, hat der Anwender keine Chance auf eine aktuelle Seite.

          Faszinierend, wie Du die Thematik durchdrungen hast!

    2. Tach!

      2. interface: Immer sinnvoll, wenn es sich wiederholende Abläufe gibt. Und das ist bei Request-Response-Zyklen auf jeden Fall der Fall ;)

      Interface wird in der Programmiererei mehrfach verwendet. Hier geht es um Interfaces im Sinne von OOP-Sprachen wie Java, C# oder (dem OOP-Teil von) PHP, nicht um Schnittstelle wie das I wie in APIs.

      dedlfix.

    3. für mich einfache, pregnate und präzise AW. So liebe ich es. :)

      1. Tach!

        für mich einfache, pregnate und präzise AW. So liebe ich es. :)

        Für mich war sie zwar kurz, aber auch fehlerhaft. Seine Antwort zum Interface beispielsweise bezieht sich nicht auf das Interface, was in OOP-Sprachen zu finden ist. Es gibt keinen Zusammenhang zwischen sich wiederholenden Abläufen und einem solchen Interface.

        dedlfix.

        1. moin dedlfix

          Für mich war sie zwar kurz, aber auch fehlerhaft. Seine Antwort zum Interface beispielsweise bezieht sich nicht auf das Interface, was in OOP-Sprachen zu finden ist. Es gibt keinen Zusammenhang zwischen sich wiederholenden Abläufen und einem solchen Interface.

          Ich glaube so wie du hat er das auch kurz und bündig gemeint. Ich kenne mich in interface aus und weis wo es angewendet wird. aber wie viele parameter (nicht EDV bezogen) stimmen müssen damit man interface verwendet wusste ich nicht. Du hast das ganze sehr ausführlich und sehr veständlich ausformuliert und pregnate beispiele angeführt. Dafür danke ich dir :-). Viele Dinge ware mir nicht. bekannt.

          vlg MB

      2. für mich einfache, pregnate und präzise AW. So liebe ich es. :)

        Schön ;)

        Schade dass Du Dich so auf PHP fixiert hast, in Perl ist das alles wesentlich unkomplizierter zu machen, auch die sog. traits. Meine Erfahrung wegen Caching gebe ich gerne weiter, glaub' jedoch nicht, dass das die Anderen hier wenigstens ansatzweise verstanden haben, weil denen offensichtlich die eigenen Erfahrungen fehlen (des sehe ich an der Bewertung meiner Beiträge).

        Hier noch ein Blick in meine Routingtable, Du siehst darin die an den URL gebundende Klasse (Attribute class=). Per Konfiguration, Attribute interface= ist es möglich, der Klassenbindung ein Interface hinzuzufügen, bspw. ersetzt interface=date die Platzhalter %month% und %year% über einen trait welcher die Interface-Methode trailer() definiert.

        Andere traits definieren andere Methoden, je nach Bedarf. Auf diese Art und Weise kann jede Seite dynamische Inhalte bekommen der interaktiv werden ohne dass der Programmierer in einer Flut von Dateien und Klassen erstickt.

        Die Routingtable ist übrigens ein Kandidat für static und liegt komplett im Hauptspeicher.

        MfG

  2. PS: Ich hab viele Softwarelösungen in MVC mir angeschaut, gut und weniger gut. Und auch welche von euch.

    Bei MVC muss ich seit gestern immer schmunzeln, wegen dieses Tweets hier:

    How to do MVC:\

    1. Take any three things, ANY\
    2. Call them Model, View and Controller\
    3. Draw some arrows between them

    Done!

  3. Tach!

    der Betreff sagt eigentlich alles. Ich hab Konfigurations-Dateien final gemacht und ziehmlich viel in diesem Bereich mit static gearbeitet.

    Dateien - final? Final ist kein Begriff, der im Zusammenhang mit Dateien steht. Du meinst vielleicht Klassen. Aber warum hast du sie final gemacht? Was genau möchtest du damit erreichen oder verhindern?

    • 1: Ist static in einer klasse sinvoll die nur einmal verwendet wird und das immer wieder? z.B. in den ganzen Controller klassen und Core Klassen in dem z.B. Router Klasse und App Klasse was die die Router Klasse aufruft.

    Static hat nichts mit der Häufigkeit der Verwendung zu tun. Static nimmt man, wenn man keine Instanzen braucht/haben möchte/wasauchimmer, oder diese keinen Sinn ergeben, wie beispielsweise die Funktionssammlung in der Math-Klasse, die es oftmals in objektorientierten Systemen gibt. (In PHP nicht, das hat dafür ja eigenständige Funktionen). Statische Dinge können aber auch erheblich von Nachteil für bestimmte Vorgehensweisen sein. Zum einen muss man sich als Verwender darauf verlassen, dass sie richtig initialisiert sind und/oder nicht von anderen Orten aus verändert werden. Man holt sich mit statischen Dingen einen globalen Status ins Haus. Dinge wie automatische Testbarkeit sind damit nicht wirklich gut zu realisieren.

    Wie immer, wnen du keine plausible Begründung für eine Vorgehensweise liefern kannst, mach es nicht so. Natürlich wirst du auch beim Finden von Begründungen Fehler machen, aber das ist halt so. Manches lernt man erst im Laufe der Zeit und erkennt dann erst (hoffentlich) die eigenen Fehler.

    • 2: Wie stehts mit interface? MVC ist ja mehr oder weniger sehr komplex. Da lohnt es sich interface zu verwenden. Ich aber nie sinvoll interfaces verwendet.

    Interfaces sind eine Art Vereinbarung. Damit wird vereinbart, dass ein Objekt bestimmte Eigenschaften und/oder Funktionen hat. Das nimmt man vor allem dann, wenn Klassen keinen fachlichen Bezug zueinander haben und damit Vererbung nicht sinnvoll ist, man aber eine gleiche Funktionalität braucht.

    Ein Beispiel sind Funktionen zum de/serialisieren von Objekten. Speichern muss man die verschiedensten Dinge und dafür müssen ihre Daten in eine speicherbare Form gebracht werden und aus dieser wiederhergestellt werden können. Man erstellt sich dazu ein Interface ISerializable

    interface ISerializable {
      function serialize(); // Rückgabewert ist ein String.
      function deserialize($data); // $data ist ein String.
    }
    

    Jede Klasse, deren Objekte gespeichert werden müssen, implementiert dieses Interface, sprich: füllt diese vereinbarten Funktionen mit Leben.

    class Foo implements ISerializable {
      // anderes Zeugs
    
      public function serialize() {
        return $daten_als_string;
      }
    
      public function deserialize($data) {
        this->irgendwas = holeDatenAusDemString($data);
      }
    }
    

    Der Mechanismus, der die Daten dann speichert, bekommt Objekte vom Typ ISerializable übergeben. Was die sonst so tun, ist dem Speichermechanismus komplett egal, der muss nur ihre Daten bekommen und braucht deshalb nur Zugriff auf die im Interface vereinbarten Methoden. Alles andere sieht der nicht, zumindest in kompilierten Sprachen. In PHP mit seiner Dynamic könnte man auch daran vorbeiarbeiten.

    dedlfix.

    1. Hallo dedlfix,

      Dateien - final? Final ist kein Begriff, der im Zusammenhang mit Dateien steht. Du meinst vielleicht Klassen. Aber warum hast du sie final gemacht? Was genau möchtest du damit erreichen oder verhindern?

      um sie nicht veränderrn zu können. Ich verwende das in Comfig dateien.

      ... oder diese keinen Sinn ergeben, wie beispielsweise die Funktionssammlung in der Math-Klasse, die es oftmals in objektorientierten Systemen gibt.

      ist mir neu. Vielen Dank :-)

      Statische Dinge können aber auch erheblich von Nachteil für bestimmte Vorgehensweisen sein. [...] nicht von anderen Orten aus verändert werden.

      deswegen final

      Ein Beispiel sind Funktionen zum de/serialisieren von Objekten. Speichern muss man die verschiedensten Dinge und dafür müssen ihre Daten in eine speicherbare Form gebracht werden und aus dieser wiederhergestellt werden können. Man erstellt sich dazu ein Interface ISerializable

      gutes beispiel. Ich möchte Nachrichten Anzeige Programmieren im Programm. Lohnt es sich dafür *Interface zu verwenden oder *traits? Ich mein Die Funktionan die ich programmieren werden sind alle nach einem muster. Wozu dann noch Intefrace?

      vlg MB

      1. Tach!

        Aber warum hast du sie final gemacht? Was genau möchtest du damit erreichen oder verhindern?

        um sie nicht veränderrn zu können. Ich verwende das in Comfig dateien.

        Das ist ja offensichtlich, aber warum soll da keiner vas ändern können? Bist du dir sicher, dass es unter keinen Umständen passieren darf, dass jemand eine abgeleitete Klasse erstellt, Methoden überschreibt und dann eine solche Klasse übergibt?

        Statische Dinge können aber auch erheblich von Nachteil für bestimmte Vorgehensweisen sein. [...] nicht von anderen Orten aus verändert werden.

        deswegen final

        Moment mal, final ist kein Synonym für readonly oder const.

        Ein Beispiel sind Funktionen zum de/serialisieren von Objekten. Speichern muss man die verschiedensten Dinge und dafür müssen ihre Daten in eine speicherbare Form gebracht werden und aus dieser wiederhergestellt werden können. Man erstellt sich dazu ein Interface ISerializable

        gutes beispiel. Ich möchte Nachrichten Anzeige Programmieren im Programm. Lohnt es sich dafür *Interface zu verwenden oder *traits? Ich mein Die Funktionan die ich programmieren werden sind alle nach einem muster. Wozu dann noch Intefrace?

        Bei stark typisierten Systemen muss man einen Typ angeben. Wenn man keine Basisklasse hat, dann muss es eine andere gemeinsame Basis geben, die man da als Typ angeben kann, zum Beispiel ein Interface. Bei schwach typisierten Systemen, die auch nach dem Duck-Type-Prinzip arbeiten, kann man auch auf Interfaces verzichten. Ob man aber besser fährt, dass der Compiler und Entwicklungumgebung keine Ahnung davon hat, was wirklich zur Laufzeit abläuft und einem dann auch keine Unterstützung in der Entwurfsphase bieten können, steht auf einem anderen Blatt. Das Duck-Type-Prinzip kommt von: wenn es quakt wie eine Ente, wird es wohl eine Ente sein. Wenn man eine bestimmte Methode aufrufen kann, ist alles in Ordnung, Interfaces und Klassenzugehörigkeiten spielen dabei keine Rolle, Hauptsache das Ding hat die Methode. Da kann man auch einen Fuchs mit Fremdsprachenkenntnissen übergeben.

        Interfaces legen nur fest, wie etwas an der Oberfläche aussehen muss. Da ist kein Code dahinter, der irgendwas macht. Den muss derjenige schreiben, der das Interface implementiert. Traits hingegen sind Codestücke, die man sozusagen anderen Klassen einverleiben kann. Ich hab noch nie Traits verwendet. Man kann gemeinsame Aufgaben auch als Service implementieren. Logging muss beispielsweise nicht in jede Klasse eingebaut werden, auch nicht als Trait. Da reicht es, die Logger-Instanz zu übergeben und wenn man was mitzuteilen hat, übergibt man den Text an eine Methode des Loggers.

        Man könnte auch den Serializer als Service auslegen, aber dann kann der meist nur die von außen sichtbaren Eigenschaften ermitteln und nichts individuelles anstellen. Wenn man spezielle Dinge serialisieren muss, die nur die Klasse selbst kennt, dann braucht man den Serializer-Code an Bord. Aber da hilft auch kein Trait, denn der ist dann entweder so speziell, dass er gleich als direkter Code eingebunden werden kann, oder er ist wieder so allgemein, dass es ein Service auch tut (nebst einer Menge Graustufen zwischen diesen beiden Enden).

        dedlfix.

        1. Ein, zwei Ergänzungen:

          Aber warum hast du sie final gemacht? Was genau möchtest du damit erreichen oder verhindern?

          um sie nicht veränderrn zu können. Ich verwende das in Comfig dateien.

          Das ist ja offensichtlich, aber warum soll da keiner vas ändern können? Bist du dir sicher, dass es unter keinen Umständen passieren darf, dass jemand eine abgeleitete Klasse erstellt, Methoden überschreibt und dann eine solche Klasse übergibt?

          Wenn sich ein Usecase ergibt, könnte man das final aber auch noch nachträglich entfernen. Es gibt schon gewisse Argumente dafür.

          Statische Dinge können aber auch erheblich von Nachteil für bestimmte Vorgehensweisen sein. [...] nicht von anderen Orten aus verändert werden.

          deswegen final

          Moment mal, final ist kein Synonym für readonly oder const.

          Ich bin mir auch nicht sicher, ob die Wahl der Begrifflichkeiten vollständig Sinn ergibt. Hier noch eine Quelle, wieso static/global state besser vermieden werden sollte:

          Ein Beispiel sind Funktionen zum de/serialisieren von Objekten. Speichern muss man die verschiedensten Dinge und dafür müssen ihre Daten in eine speicherbare Form gebracht werden und aus dieser wiederhergestellt werden können. Man erstellt sich dazu ein Interface ISerializable

          gutes beispiel. Ich möchte Nachrichten Anzeige Programmieren im Programm. Lohnt es sich dafür *Interface zu verwenden oder *traits? Ich mein Die Funktionan die ich programmieren werden sind alle nach einem muster. Wozu dann noch Intefrace?

          […]

          Ehrlich gesagt: Die Frage ist in der Form eigentlich nicht verständlich. „Nachrichten Anzeige“ könnte alles sein. Der Zusammenhang mit Interfaces und/oder Traits ist unklar.

          Bei stark typisierten Systemen muss man einen Typ angeben. Wenn man keine Basisklasse hat, dann muss es eine andere gemeinsame Basis geben, die man da als Typ angeben kann, zum Beispiel ein Interface. Bei schwach typisierten Systemen, die auch nach dem Duck-Type-Prinzip arbeiten, kann man auch auf Interfaces verzichten. Ob man aber besser fährt, dass der Compiler und Entwicklungumgebung keine Ahnung davon hat, was wirklich zur Laufzeit abläuft und einem dann auch keine Unterstützung in der Entwurfsphase bieten können, steht auf einem anderen Blatt.

          Allerdings. :) Anders gesagt: In der Regel zielt man in der PHP-Welt inzwischen auf eine möglichst strikte Typisierung ab (z. B. über explizite Typehints in Methoden-Signaturen), um robusteren Code zu schaffen und um etwa auch IDE-Features aus dem Bereich der statische Analyse nutzen zu können.

    • 2: Wie stehts mit interface? MVC ist ja mehr oder weniger sehr komplex. Da lohnt es sich interface zu verwenden. Ich aber nie sinvoll interfaces verwendet.

    Das findet sich so für PHP als auch für Java:

    "Interfaces erlauben die Erzeugung von Code, der spezifiziert, welche Methoden eine Klasse implementieren muss, ohne definieren zu müssen, wie diese Methoden behandelt werden."

    Stell Dir vor: großes Projekt, viele Mitarbeiter, welche einzelne Einheiten (Klassen) programmieren.

    Das schnell geschriebene interface (es enthält ja keine Methoden an sich) erzwingt es, dass die Klassen alle vorgesehenen Methoden haben müssen. Das vereinfacht das Testen der einzelnen Klassen erheblich. Verlangt aber eine gute Programmplanung.

    Für kleine Projekte sind interfaces einfach zu viel des Guten.

    1. Tach!

      Für kleine Projekte sind interfaces einfach zu viel des Guten.

      So sehe ich das nicht. Größe sollte kein Faktor sein, sondern man sollte das entsprechend der Sinnhaftigkeit im vorliegenden Anwendungsfall entscheiden.

      dedlfix.

      1. Tach!

        Für kleine Projekte sind interfaces einfach zu viel des Guten.

        So sehe ich das nicht. Größe sollte kein Faktor sein, sondern man sollte das entsprechend der Sinnhaftigkeit im vorliegenden Anwendungsfall entscheiden.

        Naja. Größe und Sinnhaftigkeit haben hier aber durchaus einen Zusammenhang:

        • kleinere Projekte -> oft nur ein Programmierer
        • kleinere Projekte -> weniger Klassen, weniger Instanzen (mal von Arrays von solchen abgesehen)
        • größere Projekte -> Mehr Klassen und mehr Instanzen -> also mehr Anlass dazu, Units abzugrenzen, zu definieren und die Einhaltung der Definitionen einfach überprüfen zu wollen.
        1. Tach!

          Naja. Größe und Sinnhaftigkeit haben hier aber durchaus einen Zusammenhang:

          Der Zusammenhang ist aber nicht kausal, auch wenn sich oftmals aus der Aufgabenstellung und der Beurteilung der dazu passenden Werkzeuge eine solche scheinbare Regelmäßigkeit ergibt.

          dedlfix.

  4. Die Frage nach static und interface hängen zusammen. Grundsätzlich kann man den Prozeduralen Ansatz wählen und alles, was nicht mehrfach als Objekt instanziiert werden muss, als Klasse mit statischen Elementen realisieren. Die Klasse wird dann zum Namespace degradiert. Wenn die Klasse Hinz aus der Klasse Kunz die Methode Foo braucht, ruft sie eben Kunz::Foo() auf und gut ist.

    Problem sind hier die Abhängigkeiten, die das schafft. Wenn du die Klasse Hinz testen willst, muss Kunz immer mit an Bord sein. Das ist ein Problem, vor allem dann, wenn Kunz::Foo() dazu da ist, eine komplexere SQL-Abfrage zu kapseln. Tests funktionieren dann nur mit definierten Datenbankinhalten und brauchen ewig. Aber eigentlich sollte der Test ja nur zeigen, dass die Methode Hinz->Oaf() die von Kunz::Foo() gelieferten Daten ordentlich filtert. Das würde mit einer Simulation eines SQL Ergebnisses viel besser und schneller funktionieren, aber weil Kunz::Foo() in Hinz->Oaf() hardcoded ist, geht es nicht.

    Viele Programme sehen so aus, viele Programmierer arbeiten so, und plärren dann: Unit Tests sind scheiße und sind überhaupt nicht baubar. Weiß ich genau, habe ich jahrelang selbst gemacht. Wenn man Programmieren mit direkten Abhängigkeiten gelernt hat, dauert es einige Zeit, bis der IoC[1] Groschen fällt.

    Deshalb: statische Elemente sind IMMER eine Problemquelle und sollten homöopathisch verwendet werden. Du kannst sie nicht mocken (sprich: dem Nutzer vortäuschen, er würde damit arbeiten, aber in Wahrheit verwendet er ein Surrogat) und du kannst Hinz auch nicht sagen, er soll jetzt statt Kunz bitte Krethi verwenden (na gut, kannst du, aber das macht in PHP mangels Metaklassen bzw. Type-Klasse wenig Spaß).

    Viel einfacher ist es, wenn Kunz ein Interface IKunz implementiert (oder mehrere Interfaces, nach Funktionsgruppen). Auf IKunz sind alle Methoden deklariert, die Kunz öffentlich bereitstellt. Kleines Manko in PHP: Es gibt keine automatischen Property-Getter, und deshalb musst Du für öffentliche Eigenschaften, die auf dem Interface erscheinen sollen, get- und set-Methoden definieren (oder machst es wie jQuery: $kunz->bar() liefert das bar-Property und $kunz->bar(4711) schreibt einen Wert hinein). Wer ein Hinz-Objekt erzeugen will, muss dann zwangsweise eine Implementierung von IKunz mitliefern. Das nennt man Dependency Injection oder Inversion of Control: Hinz holt sich seine Abhängigkeiten nicht, sondern bekommt sie eingespritzt.

    Natürlich ist das mühsam, wenn man das alles von Hand tun muss. Darum gibt es Tools, sogenannte IoC Container, die das per Reflection oder Config-File automatisch erledigen. Du sagst nicht "new Hinz(new Kunz()), sondern $ioc->resolve("Hinz"). Was in PHP wieder mühsam ist. In C# oder Java hättest du generische Typen und Methoden, und würdest container->Resolve<IHinz>() aufrufen. Wenn's Hinz nicht gibt, merkt das dann schon der Compiler. Ich habe mich selbst noch nicht mit IoC in PHP beschäftigt, nur in C#, aber ich weiß, dass es auch in PHP Container gibt.

    Das ist alles Infrastruktur für zwei Zwecke: Auflösen von direkten Abhängigkeiten und Testbarkeit. Direkte Abhängigkeiten behindern Wiederverwendbarkeit, und Testbarkeit ist wichtig für die Softwarequalität. Das Konzept der Testgetriebenen Entwicklung (TDD) sagt, dass man erst die Tests schreibt und damit spezifiziert, welches Verhalten man von einer Klasse erwartet, und dann die Methoden baut. Wenn man etwas ändern will, ändert man erst die Tests, dass sie das gewünschte neue Verhalten abfragen, und erweitert dann die betroffenen Methoden. Das ist eine GANZ andere Denkweise als früher und es fällt zumindest mir sehr schwer, mich konsequent daran zu halten. Ich muss mich immer wieder treten, nicht "mal eben so" eine Methode zu updaten. TDD ist eine Wissenschaft für sich, aber wenn Du einen vollständigen Satz an Unit-Tests für dein Programm hast, dann bist Du bei Änderungen an der Implementierung relativ sicher, dass die von Dir erwarteten Verhaltensweisen deiner Methode unverändert geblieben sind. Das schafft eine ganz neue Form von Qualität. Konzepte wie Continous Deployment wären ohne umfangreiche automatisiertes Tests unmöglich. Und mit Testbarkeit durch Unit-Tests fängt das alles an.

    Rolf


    1. Inversion of Control ↩︎

    1. Tach!

      Kleines Manko in PHP: Es gibt keine automatischen Property-Getter, und deshalb musst Du für öffentliche Eigenschaften, die auf dem Interface erscheinen sollen, get- und set-Methoden definieren

      Interfaces in PHP können nur Methoden spezifizieren. Es ist in der Hinsicht also nicht weiter relevant, dass es kein Äquivalent für die schönen C#-Propertys in PHP gibt. PHP-Interfaces sind also nur für die Definition von Verhalten (=Methoden) und nicht für den Zugriff auf Zustände (=Eigenschaften) verwendbar. Wenn man Zustandszugriffe über ein Interface in PHP definieren möchte, muss man das sowieso über Verhalten regeln, also lies_dies()/schreib_das().

      Ansonsten sind automatische Getter und Setter im Prinzip auch überflüssig, weil sie keinerlei Funktionalität hinzufügen, die nicht auch ein einfacher Eigenschaftenzugriff hat. Man muss eine Funktionalität also nicht zwingend nachbauen, die anderswo aufgrund von Konventionen und Programmteilen, die die Einhaltung dieser Konventionen voraussetzen, notwendig sind (wie Getter und Setter in Java).

      dedlfix.

      1. Kleines Manko in PHP: Es gibt keine automatischen Property-Getter, und deshalb musst Du für öffentliche Eigenschaften, die auf dem Interface erscheinen sollen, get- und set-Methoden definieren

        Interfaces in PHP können nur Methoden spezifizieren. (...) Wenn man Zustandszugriffe über ein Interface in PHP definieren möchte, muss man das sowieso über Verhalten regeln, also lies_dies()/schreib_das().

        Sag ich doch... Oder meinte ich zumindest. Interfaces können IMMER nur Methoden definieren, nicht nur in PHP. Manchmal sind die Methoden durch eine Property-Syntax überzuckert (wie in C#), aber Methoden sind es trotzdem. Ob ich nun in C# schreibe

        interface IKunz
        {
           string Name { get; set; }
           string Vorname;      // FEHLER - GEHT NICHT!
        }
        

        oder in PHP

        interface IKunz
        {
           public function getName();
           public function setName(string $name);   // 'string' ist PHP 7
           public $Vorname;      // FEHLER - GEHT NICHT!
        }
        

        ist technisch exakt das gleiche. C# versteckt es nur hinter einer anderen Syntax (die übrigens erst in .net 2 auf die Autoproperties ausgedehnt wurde)

        Die entscheidende Information ist, dass das der einzige Weg ist und die Bekanntgabe eines Eigenschaftszugriffs - wie string Vorname; nicht möglich ist. Und das ist keine PHP Eigenschaft, sondern liegt im Wesen von Interfaces. Wenn ich auf dem Interface deklarieren könnte, dass das Objekt eine Eigenschaft "Vorname" hat und diese Eigenschaft NICHT per Methodenaufruf gekapselt würde, dann hätte man beim Implementieren des Interface nicht mehr die Wahl, ob Vorname ein eigenes Property ist oder der Teil hinter dem Komma von "Merkel, Angela".

        Ich gebe zu, das kam in meinem Beitrag von oben nicht klar herüber. Aber genau diese Eigenschaft von Interfaces macht die Abstraktion, die sie anbieten, erst sinnvoll.

        Und wenn ich ein Objekt vor mir habe, das IKunz implementiert, dann ist es nicht korrekt, Geheimwissen anzuwenden und am Interface vorbei auf andere, zufällig bei dieser Implementierung vorhandene Klassenelemente zuzugreifen, egal ob Methode oder Property. PHP erlaubt mir das, während Java oder C# mir auf die Fingerchen klopfen würden. Im folgenden PHP Beispiel funktioniert liesName ganz prima und gibt "zu Diensten" aus, obwohl ich mit Type Hint angegeben habe, dass da ein IKunz vorliegt (PHP 5.6, ich habe kein 7er hier).

        interface IKunz
        {
           public function getName();
        }
        
        class Kunz implements IKunz
        {
           public function getName() { return "Konrad von Hinzensberger"; }
           public function greeting() { return "zu Diensten"; }
        }
        
        function liesName(IKunz $k)
        {
           // PROGRAMMING ERROR - DON'T DO THIS AT WORK !
           echo "Ich lese: " . $k->getName() . ", " . $k->greeting() . "\n";
        }
        
        $ik = new Kunz();
        liesName($ik);
        

        Rolf

        1. Tach!

          Sag ich doch... Oder meinte ich zumindest. Interfaces können IMMER nur Methoden definieren, nicht nur in PHP.

          Sag niemals IMMER! ;) Interfaces in Typescript können Eigenschaften. Aber aufgrund des darunterliegenden Javascript gehen da sowieso die wunderlichsten Dinge.

          dedlfix.

          1. schauder Wer hat denn da den Microsofties ins Hirn gesch...aut?

            1. Tach!

              schauder Wer hat denn da den Microsofties ins Hirn gesch...aut?

              Kein Geringerer als Meister C# persönlich: Anders Hejlsberg.

              Das Problem ist ja nicht, dass Typescript solche Dinge hat, sondern dass es offensichtlich notwendig ist, solche Dinge in Typescript einzubauen, weil Javascript das unumgänglich macht. Und Typescript ist schon eine derartige Wohltat gegenüber Javascript, dass man über solche Dinge nicht nur einfach hinwegsieht, sondern sie aktiv nutzt. In meinem Datenmodel sind zum Beispiel keine POCOs sondern POTIs zu finden. Völlig ausreichend, wenn die Instanzen meist nur klassenlose Objekte sind.

              dedlfix.

              1. Das Problem ist ja nicht, dass Typescript solche Dinge hat, sondern dass es offensichtlich notwendig ist, solche Dinge in Typescript einzubauen, weil Javascript das unumgänglich macht.

                Welche Probleme seht ihr denn, wenn man in Interfaces auch Definitionen von Eigenschaften zulässt? Das ist ja zunächst mal schlüssig, denn in TypeScript sind Funktionen ordinäre Daten. Wieso sollte ich also einen statischen Typcheck[1] für Funktionstypen anbieten und für andere Datentypen vorenthalten? Das wäre inkonsistent und würde die Sprache komplexer machen. Beides sehr hohe Preise und ich sehe noch keinen Vorteil, den man sich dafür erkauft.


                1. Der Hauptanwendungsfall für Interfaces ist meiner Meinung nach ad-hoc Polymorphismus mit statischen Typchecks auszustatten. ↩︎

                1. Tach!

                  Welche Probleme seht ihr denn, wenn man in Interfaces auch Definitionen von Eigenschaften zulässt?

                  Ich, keine. Ich hatte sogar schon wieder verdrängt, dass es in PHP keine Eigenschaften in Interfaces gibt. Andere Systeme jedenfalls verlangen andere Vorgehensweisen. Man sollte da nicht zu sehr Parallelen suchen oder fordern, auch wenn der innere Schweinehund lieber alles einheitlich haben möchte, um sich ja nicht so viele Unterschiede merken zu müssen.

                  dedlfix.

                2. Der Hauptanwendungszweck von Interfaces ist, den Nutzer einer Klasse von ihrer tatsächlichen Implementierung zu trennen. Er sieht nur das Interface, und wie es implementiert ist, hat ihn nicht zu interessieren. Das Interface stellt den Kontrakt dar, der bereitgestellt wird und den ich nutzen kann. Durch die Trennung zwischen Kontrakt und Ausführung des Kontrakts entsteht Austauschbarkeit und insbesondere die Möglichkeit zum Mocken und Unit-Testen. Statische Typchecks sind nur ein Aspekt des Ganzen. Mit einer passenden Remoting-Library darunter kann ich mir bei einer Factory ein Interface bestellen und sie schiebt mir, wenn es so konfiguriert ist, klammheimlich einen Remote-Aufruf unter. Oder eben nicht, wenn ich den Service lokal nutze. Sowas geht nur mit Interfaces (oder, ja, abstrakten Superklassen, die ich wie Interfaces nutze).

                  In Sprachen wie PHP oder JavaScript kann man Interfaces tatsächlich auf ein technisches Muster für vorhandene Klassenelemente reduzieren, weil die Bindung Aufruf->Implementierung zur Laufzeit erfolgt.

                  Für die Diskussion muss man bei „Eigenschaften“ genau hinsehen und zwischen Property und Field unterscheiden. Ein Field ist das nackige, unverfälschte Datenelement, das am Objekt hängt und nur einen Wert darstellt. Also das, was ich in PHP über $obj->Dings = 17 anspreche und annähernd das, was ich in JavaScript über obj = { Dings: 17 }; erzeuge. Dem entgegen steht ein Ding, das ich zur Abgrenzung mal Property nenne, das ich von der Syntax her wie ein Field behandle, wo die Zugriffe aber technisch auf einen Methodenaufruf abgebildet werden bzw. zumindest abgebildet werden können.

                  In JavaScript ist es so, dass Eigenschaften in zwei Facetten vorkommen. Als Data-Properties, die einen Wert besitzen und vom Verhalten her einem Field entsprechen, oder als Accessor-Properties, die Get- und Set-Methoden haben. Der Nutzer bekommt das überhaupt nicht mit. Die Syntax ist für ihn die gleiche. Die gleiche Mimik hat z.B. C# mit seiner get/set Syntax. Auch da ist für den Aufrufer ein Field von einem Property syntaktisch nicht zu unterscheiden (semantisch schon: bei readonly und call-by-reference).

                  Java gibt sich gar nicht erst die Mühe, hier irgendwas zu zuckern, da gibt's nur die getXxx und setXxx Konvention und das wird dann Property genannt...

                  D.h. eine Eigenschaft in einem TypeScript-Interface ist unproblematisch, weil bei der Implementation jederzeit ein Accessor-Property unterlegt werden kann. In Java stellt sich die Frage nicht. In C# ist es wie in Java, nur unter einer Zuckerkruste versteckt und man hat das Gefühl, als gäbe es Eigenschaften auf Interfaces.

                  PHP hat weder diese duale Darstellung von Data- und Accessor-Properties, noch den get/set Syntaxzucker. Wenn ich in ein PHP Interface eine Eigenschaft schreibe, bedeutet das zur Laufzeit den direkten Zugriff auf ein Field. Und DAS ist ein Problem, weil ich ein Field nicht mocken oder nach Bedarf durch einen Methode substituieren kann. Deswegen muss ich in PHP, genau wie in Java, ein interfacefähiges Property durch explizite Getter und Setter realisieren.

                  Rolf

                  1. Der Hauptanwendungszweck von Interfaces ist, den Nutzer einer Klasse von ihrer tatsächlichen Implementierung zu trennen. Er sieht nur das Interface, und wie es implementiert ist, hat ihn nicht zu interessieren. Das Interface stellt den Kontrakt dar, der bereitgestellt wird und den ich nutzen kann. Durch die Trennung zwischen Kontrakt und Ausführung des Kontrakts entsteht Austauschbarkeit und insbesondere die Möglichkeit zum Mocken und Unit-Testen. Statische Typchecks sind nur ein Aspekt des Ganzen.

                    Sie sind der Aspekt von Interfaces. Den gesamten Rest, den du beschreibst, darft du Polymorphie zu Gute rechnen. In Java sind Interfaces eben eine Möglichkeit Polymorphie zu realisieren.

                    Sowas geht nur mit Interfaces (oder, ja, abstrakten Superklassen, die ich wie Interfaces nutze).

                    Gibt es dafür einen triftigen Grund? Vertikale Komposition, also Vererbung, sorgt für eine stärkere Kopplung der beteiligten Klassen als horizontale Komposition (durch Interfaces, Traits, Mixins...). Bei sehr kohärenten Zusammenhängen, kann man das machen. Im allgemeinen Fall würde ich zunächst davor zurückweichen. Und wie soll das in Sprachen ohne multipler Vererbung funktionieren?

                    In Sprachen wie PHP oder JavaScript kann man Interfaces tatsächlich auf ein technisches Muster für vorhandene Klassenelemente reduzieren, weil die Bindung Aufruf->Implementierung zur Laufzeit erfolgt.

                    Womit wir wieder bei der Polymorphie wären. Diesmal durch Duck-Typing.

                    PHP hat weder diese duale Darstellung von Data- und Accessor-Properties, noch den get/set Syntaxzucker. Wenn ich in ein PHP Interface eine Eigenschaft schreibe, bedeutet das zur Laufzeit den direkten Zugriff auf ein Field. Und DAS ist ein Problem, weil ich ein Field nicht mocken oder nach Bedarf durch einen Methode substituieren kann.

                    In PHP gibt es die "magischen" __get- und __set-Methoden, damit kannst du Zugriff auf Eigenschaften regeln.

                    Dein Argument mit dem Mock kann ich nicht nachvollziehen. Wieso solltest du Abhängigkeiten von Eigenschaften nicht auflösen können? Das Interface würde ja nur die Existenz und den Typen der Eigenschaft festlegen. Ich glaube, dass dieses Problem gar nicht existiert, aber selbst wenn, würde ich sagen, dass man in einem solchen Fall die Eigenschaft eben nicht per Interface erfordern sollte. Man verliert ja durch die Möglichkeit nichts. Man gewinnt nur Einfachheit, Konsistenz und Ausdrucksmöglichkeit hinzu.

                    Deswegen muss ich in PHP, genau wie in Java, ein interfacefähiges Property durch explizite Getter und Setter realisieren.

                    Mir ist klar, dass das so ist, nur wieso sollte das besser sein, als Eigenschaften auch in Interfaces zuzulassen?

                    1. (...) Statische Typchecks sind nur ein Aspekt des Ganzen.

                      Sie sind der Aspekt von Interfaces.

                      Da wir hier beide unsere Meinungen in den Raum stellen - und ich für meine Meinung keine reputable Belegquelle aus der Tasche ziehen kann - will ich dazu einfach mal dies sagen: Einigen wir uns darauf, dass wir uneinig sind.

                      Den gesamten Rest, den du beschreibst, darfst du Polymorphie zu Gute rechnen. In Java sind Interfaces eben eine Möglichkeit Polymorphie zu realisieren.

                      Wenn man den Blick nur auf dynamische Sprachen richtet (Javascript, PHP), sind Interfaces nur eine Liste von Hinweisen an die Entwicklungsumgebung (oder den Compiler, soweit einer nötig ist). Es gibt aber dazu noch die "statischen" Sprachen, und da brauche ich Interfaces als Konstrukt, um den Zeitpunkt der Methodenbindung vom Zeitpunkt des Compilierens oder Ladens zum Moment der Objekterzeugung zu verschieben. Möglicherweise gibt es statische Sprachen, die das auch ohne Interfaces können, die kenne ich dann nicht.

                      Polymorphie ist eine Voraussetzung für Mocks in Unittests oder Proxies in Remote-Diensten. Ohne Interface gibt's in den mir bekannten statischen Sprachen keine Polymorphie, daher sehe ich dort Interfaces als Voraussetzung für Unittests und Remote-Proxies an.

                      Sowas geht nur mit Interfaces (oder, ja, abstrakten Superklassen, die ich wie Interfaces nutze). Gibt es dafür einen triftigen Grund?

                      Sorry. Das habe ich falsch formuliert. "Die man an Stelle von Interfaces auch verwenden kann" hätte ich sagen müssen, und natürlich brauchst Du eine Sprache wie C++, um Interfaces komplett durch abstrakte Superklassen zu ersetzen. Das heißt jetzt nicht, dass es gut ist, das zu tun. Aber wenn ich sage "Das geht nur mit Interfaces", dann ist das als Absolutum falsch und irgendein Korinthenkacker hätte dann die abstrakten Superklassen als Einwand bringen können.

                      (In) PHP (kann ich) ein Field nicht mocken oder nach Bedarf durch einen Methode substituieren (...).

                      In PHP gibt es die "magischen" __get- und __set-Methoden, damit kannst du Zugriff auf Eigenschaften regeln.

                      Ja sicher. Aber das nennst Du doch wohl nicht Implementierung. Das ist eine armseliger, laufzeitverschwendender Notlösung. Für Unit-Tests wäre das wohl akzeptabel. Für Proxies z.B. nicht.

                      Dein Argument mit dem Mock kann ich nicht nachvollziehen. Wieso solltest du Abhängigkeiten von Eigenschaften nicht auflösen können?

                      Weil das eine Syntax-Eigenschaft vieler Programmierersprachen, auch PHP, ist. Aus $a->Dings generiert er einen Zugriff auf ein Field, und keinen Methodenaufruf getDings(). Und den kannst du nur mit magischen Methoden umleiten. Auf die Eigenschaft in diesem Fall "am Interface vorbei" zuzugreifen beseitigt die Idee der Trennung von Deklaration und Implementation und ist daher beim Arbeiten mit Interfaces abzulehnen. Bei einem Remoting-Proxy KANNST Du nicht am Interface vorbei. Deswegen müssen Properties durch Methodenaufrufe dargestellt werden. Weil Field-Zugriffe im allgemeinen direkt auf den Objektspeicher gehen und daher nicht umgeleitet werden können. __get() ist da für mich keine Lösung, sondern eine Schwachsinnsidee von Rasmus L.

                      Rolf

                      1. Polymorphie ist eine Voraussetzung für Mocks in Unittests oder Proxies in Remote-Diensten. Ohne Interface gibt's in den mir bekannten statischen Sprachen keine Polymorphie, daher sehe ich dort Interfaces als Voraussetzung für Unittests und Remote-Proxies an.

                        Generic Types kennst du bestimmt auch, damit realisiert man in OO Sprachen parametrische Polymorphie. In funktionalen Sprachen entsprechen Typeclasses ungefähr Interfaces und Union-Types ungefähr den Generics. Alle Features dienen der Realisierung von statisch typgecheckter Polymorphie. Das nur um meine Perspektive darauf nochmal zu erläutern, und wieso ich denke dass Polymorphie der kleinste gemeinsame Nenner ist und Interfaces nur ein Spezialfall.

                        In PHP gibt es die "magischen" __get- und __set-Methoden, damit kannst du Zugriff auf Eigenschaften regeln.

                        Ja sicher. Aber das nennst Du doch wohl nicht Implementierung. Das ist eine armseliger, laufzeitverschwendender Notlösung. Für Unit-Tests wäre das wohl akzeptabel. Für Proxies z.B. nicht.

                        Naja, wenn du von Netzwerk-Proxies spricht, wie in deinem ersten Beispiel, kann man den Laufzeit-Overhead für das ausführen einer magischen Methode wohl vernachlässigen. Da ist mit Sicherheit Netzwerk-IO dein Flaschenhals. Aber natürlich gibt es einen Overhead.

                        Dein Argument mit dem Mock kann ich nicht nachvollziehen. Wieso solltest du Abhängigkeiten von Eigenschaften nicht auflösen können?

                        Weil das eine Syntax-Eigenschaft vieler Programmierersprachen, auch PHP, ist. Aus $a->Dings generiert er einen Zugriff auf ein Field, und keinen Methodenaufruf getDings(). Und den kannst du nur mit magischen Methoden umleiten.

                        Vielleicht, kannst du mir an folgendem (notwendigerweise pathologischem) Beispiel mal das Problem erklären:

                        interface Persistable {
                          $database : PDO;
                          function persist ();
                        }
                        
                        class Model implements Persistable {
                          // ...
                        }
                        
                        class PersistenceTest extends \PHPUnit\Framework\TestCase {
                          public function testPersistence () {
                             // Mock a database-connection
                             $pdo = $this->getMockBuilder(\PDO::class)->setMethods(['commit'])->getMock();
                        
                             // Expect that the commit-method is called on the connection
                             $pdo->expects($this->once())->method('commit');
                        
                             // Inject the mocked database-connection into our test-candidate
                             $model = new Model();
                             $model->database = $pdo;
                             $model->persist();
                          }
                        }