OOP und wie es richtig geht??? *g*

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

  • OOP und wie es richtig geht??? *g*

    Hallo Forum,

    nun kurz zu meinen Erfahrungen, vor knapp 1,5 Jahren habe ich das erste mal selbst prozedurale Scripte geschrieben, nach 6 Monaten habe ich das dann abgehackt und mein Script versucht mit OOP zu realisieren.
    In dieser Zeit kamen einige Scripte (Klassen) zustande die zwar ihren Dienst tun aber mir irgend wie immer noch sehr prozedural erscheinen. Nun hatte ich ein eigenes Controller-system mit einem routing das für die Steuerungen sorgte, jetzt habe ich noch mal von vorne angefangen und habe jetzt ein MVC-System das auch den MVC-prinzip nach kommt.

    Ich könnte jetzt relativ fix meine bestehende Scripte via copy & paste in das neue MVC einbauen würde aber immer noch nicht den Sprung zu richtigem OOP schaffen. Ich könnte jetzt etliche Scripts posten um die Problematik zu zeigen aber ich werde versuchen es kurz und knapp zu beschreiben.

    Das größte Problem ist wohl die Kommunikation der Klassen untereinander, im alten Script habe ich eine merge.php in der sämtliche .php dateien (Klassen) per require(); eingebunden und instanziert werden, meine Klassen innerhalb des MVC-Systems (also Kontroller und Modelle) erhalten dann via global $db, $translator; (usw) den Zugriff. Nun heißt es "globals are devil" *g*

    Auch jetzt habe ich bestimmt gut 3 Stunden gegoogelt und rum gelesen wie ich dieses Problem lösen kann, klar es gibt Vererbung die ich ja schon nutzte (mehr dazu gleich), dann iwas mit pattern, mehrschichtigkeit usw. usw. usw. doch leider finde ich kein Tutorial das mal auch nur ansatzweise ein praktikables Beispiel zusammen baut.

    Vllt. bekommen wir das ja hin, um dann auch mal los legen zu können und das erste Problem zu lösen (globals), hier mal meine aktuell wohl wichtigste Datei:

    front.php
    PHP-Code:
    /**
     * This is the "base controller class". All other "real" controllers extend this class.
     */
    class frontController
    {
        public 
    $db null;
        
        function 
    __construct()
        {
            
    $this->openDatabaseConnection();
        }
        
        private function 
    openDatabaseConnection()
        {
            
    $options = array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJPDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING);
            
    $this->db = new PDO(DB_TYPE ':host=' DB_HOST ';dbname=' DB_NAMEDB_USERDB_PASS$options);
        }

        public function 
    loadModel($model_name)
        {
            require 
    'plugins/'.__route_plug__.'/' strtolower($model_name) . '.model.php';
            
    $className $model_name.'Model';
            
    // return new model (and pass the database connection to the model)
            
    return new $className($this->db);
        }


    Nun gut hier habe ich jetzt zumindestens die Datenbankverbindung für die Kontroller und Models bereit gestellt so das ein global $db; nicht mehr notwendig ist denn der Zugriff erfolgt jetzt via $this->db->quer('bsp'); Auch dem model wird die $db-Instanz weiter gereicht.

    Soweit so gut, jetzt könnte ich das natürlich so fortsetzten bei weiteren klassen die Global benötigt werden "meineMail, übersetzter, tools, requestVerarbeitung, cache, usw. usw." da würden ein paar zusammen kommen die ich schon geschrieben habe. Jedoch ist das nicht unbedingt OOP, denn ich müsste alles oben als Eigenschaften hard coden.

    Auch Modulare-erweiterungen sind so eher schlecht zu realisieren.
    Der frontController müsste atm auch alle Module laden und die $db weiterreichen, nicht zu vergessen das es ja nicht nur bei $db bleiben würde.


    Spontan würde ich das jetzt glaube ich so lösen das ich oben die Eigenschaft $global = array(); anlegen würde und diese mit Instanzen füllen, wie:

    PHP-Code:
    /**
     * Ich habe eine Classfactory geschrieben die Dateien lädt und eine neue instanz startet...
     * Hier müsste ich natürlich jetzt das aktuelle global array jedes mal mit übergeben damit bis dahin 
     * instanzierte sachen bereits genutzt werden können.
     */
    $this->global['db'] = ClassFactory::init('PDO''fw');
    $this->global['sett'] = ClassFactory::init('settings''fw'$this->global);
    $this->global['cache'] = ClassFactory::init('cache''fw'$this->global);
    $this->global['wwm'] = ClassFactory::init('wwm''fw'$this->global); // mein world wide manager *g*
    $this->global['link'] = ClassFactory::init('link''fw'$this->global);
    $this->global['cats'] = ClassFactory::init('categories''fw'$this->global);
    $this->global['hook'] = ClassFactory::init('hooks''fw'$this->global); 
    So müsste der Kontroller nur eine Variable weiter geben und nicht wie oben beschreiben eine lange Liste an Eigenschaften.

    Das sind jetzt nicht mal frei erfundene Sachen sondern Systeme die ich tatsächlich geschrieben habe und benötigt werden (global), so könnte man es natürlich auch per Funktionen dynamisch erweitern, klar, aber ich denke mein Problem mit der Kommunikation ist deutlich geworden und würde mich echt sehr über Tipps freuen, nach so einer langen Entwicklungszeit und ein paar tausend Zeilen, wäre es wirklich schön, den letzten oder auch vorletzten Schritt mit euch meistern zu können.


    MFG: Paykoman

  • #2
    Hey Paykoman,

    du sprichst eine Reihe typischer Herausforderungen bei der Arbeit mit Klassen und Objekten an. Statt dir hier fertige Lösungen zu präsentieren, versuche ich mal verschiedene Lösungsansätze zu motivieren:
    • require: Du sprichst von einer merge.php-Datei, die dir alle benötigten Objekte nachlädt. PHP bietet dir hierfür das Hilfsmittel der Autoloader. In diesem Zusammenhang ist der PSR-0 äußerst wichtig. Dieser beschreibt einen Standard, wie du deine Klassen benennst und im Dateisystem ablegst, um mit anderen Frameworks konform zu sein. Dann ist der SplClassLoader auch direkt für dich einsatzbar.
    • Globale Variablen: Von überall aus zugreifbare Variablen sollten in der Tat vermieden werden, das siehst du schon ganz richtig. Der Grund besteht vor allem darin, dass du keine direkte Kontrolle hast, welches Objekt wann auf welche globalen Variablen zugreift und diese evtl. ändert. Weiter verstößt du gegen die in der OOP gewünschte Kapselung von Komponenten. Das macht dir das Leben dann schwer, wenn du einzelne Objekte wiederverwenden willst. Stell dir vor, du entschließt dich, eine zweite Datenbankverbindung zu öffnen. Wie sollen deine Objekte jetzt entscheiden können, welche Verbindung zu verwenden ist? Eigentlich müsstest du jedem Objekte entsprechende Eigenschaften bereitstellen, über die die benötigten Abhängigkeiten aufgelöst werden. So sollte dein FrontController keine openConnection Methode besitzen um die Verbindung selbst zu öffnen, sondern ein Konstruktorargument oder einen Setter, um die Datenbank von außen bereitstellen zu können.
    • Objektinitialisierung:Du hast - wenn du deine globalen Variablen einstampfst und gegen Konstruktorargumente/Setter tauschst - natürlich das Problem, dass du die Abhängigkeiten deiner Objekte alle "per Hand" setzen und im Zweifel an Unterobjekte weiterreichen musst. Das Stichwort, um mit diesem Problem umzugehen, lautet Dependency Injection. Einige Frameworks (z.B. Symfony2) bieten dir entsprechende Implementierungen an. Schau dich da mal um.


    Generell kann ich dir noch als Tipp mitgeben: Versuch nicht, das Rad neu zu erfinden. Es gibt einen Haufen sehr gute Frameworks da draußen, die von sehr fähigen Menschen entwickelt wurden. Für die Übung ist das Schreiben solcher eigenen Komponenten sicher sehr hilfreich - um aber wiederverwendbaren, gut strukturierten und vor allem sicheren Code zu verwenden, solltest du mittelfristig auf ein bereits vorhandenes Framework umsteigen

    Kommentar

    Lädt...
    X