Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 15 von 36

Thema: [Workshop] Mein erstes OOP-Projekt

  1. #1
    TP-Special Mod Avatar von steffenk
    Registriert seit
    Feb 2005
    Ort
    Haan / NRW
    Beiträge
    12.869

    [Workshop] Mein erstes OOP-Projekt

    hier startet ein neuer Workshop von Strogij ...

    TYPO3 · MySQLDumper · dislabs
    ·
    manche Mühlen mahlen schneller ...
    "Ich habe Rücken"
    Horst Schlämmer

  2. #2
    Guest
    Registriert seit
    Aug 2002
    Beiträge
    2.233
    1 Einführung


    1.1 Grundsätzliches zum Workshop

    Ich habe es mir so gedacht, dass ich anhand eines Beispielprojektes Stück für Stück eine OOP-Benutzerschnittstelle erstellen werde. Der Schwerpunkt dieser Aufgabe ist die Vermittlung der Denkweise, die man für OOP für seine Projekte braucht. Ich werde versuchen so simpel und eindeutig wie möglich zu sein, werde auf komplexeren Sachen möglichst verzichten, um keine Verwirrung zu erregen. Auch werde ich nicht so tief gehen, und die einzelnen Methoden, Funktionen entwickeln; die Konzentration soll allein der OOP gewidmet werden.

    Für den weiteren Verlauf habe ich mir was mehr oder weniger Besonderes ausgedacht: Jeder kann mitwirken, jeder kann die Schnittstelle erweitern, jeder kann die Schnittstelle auf seine Weise benutzen. Das soll etwas Aufmunterung und vor allem Praxis in die Bude bringen. Näheres dazu erfährst Du am Ende.

    Eine wichtige Frage wäre noch, für wen dieser Workshop nun geeignet wäre? In erster Linie sind es die Einsteiger, die bis jetzt ohne Klassen und Co. ausgekommen sind, und deren Interesse zur OOP (zur Praxis) nun gestiegen ist.

    Hinweis: Die Benutzerschnittstelle wird für PHP 5 entwickelt.

    1.2 Was benötigt wird

    Wichtige Voraussetzung ist auf jeden Fall der Wunsch, OOP verstehen zu wollen. Wie bereits erwähnt, brauchen wir PHP 5 auf dem Webserver; eine Datenbank wird nicht benötigt, denn für unser Projekt werden wir der Übersicht halber einfach ein kleines Script mit Musterdaten erstellen. Die Dokumentation auf php.net - versteht sich von selbst. Für uns ist besonders dieses Kapitel enorm von Bedeutung.


    2 Der Start


    1.1 Vorbereitungen

    Richtige Planung ist die halbe Miete. Man sieht immer wieder, wie wenig Aufwand manche Entwickler in die Planung eines Projekts stecken, gerade bei PHP. Das liegt wohl daran, dass bei PHP auch keine Notwendigkeit besteht. Bei Programmiersprachen mit einer Bibliothek, die auf Klassen aufbaut, ist es schon anders, da muss man eben durch. Aber wenn es nicht notwendig ist, wozu dann die Mühe machen und Klassen entwerfen?

    Auf den Punkt gebracht wurden die Klassen und die ganze OOP für den Menschen entwickelt. Die OOP soll die Programmierung erleichtern. Der Entwickler soll den Code schneller, logischer, sicherer entwerfen können. Man soll eindeutige Strukturen, Aufteilungen haben, um so wenig Verwirrung wie möglich zu schaffen.

    Nun gut, wir wollen uns unser Projekt ansehen: Ein kleines CMS soll entstehen. Der User soll sich einloggen können, Bilder hochladen. Ein Rang-System regelt die Möglichkeiten der einzelnen User. Also eine Galerie mit einigen Extras.

    Jetzt ist zu überlegen, wie man das Projekt aufteilen könnte. Man erstellt z.B. eine Liste mit Oberbegriffen:

    • Userverwaltung
    • Rangsystem
    • Bildermanipulation/-verwaltung

    Das, was wir hier haben lässt sich noch weiter aufteilen, in einzelne Klassen. Doch zuvor erstellen wir Ordner:

    • Ordner „Include“
    • Ordner „Include/Klassen“
    • Ordner „Include/Funktionen“ (Für globale Funktionen)


    1.2 Die kleine Datenbank zum Testen

    Es wird eine PHP-Datei mit folgendem Inhalt erstellt:

    PHP-Code:
    <?php
    /* db.inc.php */

    $db_name = array('1' => 'Max''2' => 'Hans''3' => 'Werner''4' => 'Siegfried''5' => 'Tom');
    $db_pass = array('1' => '123''2' => '345''3' => '567''4' => '789''5' => '987');
    $db_rang = array('1' => 1'2' => 0'3' => 1'4' => 3'5' => 2);
    ?>
    Man sieht schon, dass es sehr einfach ist, soll es auch. Der Index stellt die ID dar, über welche jeder Datensatz angesprochen werden kann.

    Diese Datenbank wird immer vor den ganzen Klassen-Dateien eingebunden, weil die Klassen damit direkt arbeiten. Es wird außerdem nicht möglich sein, die Datensätze dauerhaft zu manupulieren oder zu löschen. In folgenden Beispielen werden wir diese Datensätze zum Testen lediglich geändert ausgeben.

    Die Datei speicherst Du bitte im Ordner „Include“ ab.

    1.3 Motivation

    Hinweis: Ab jetzt werden Ausdrücke aus OOP verwendet, deren Bedeutungen als Voraussetzung benötigt werden. Solltest Du Schwierigkeiten haben, so erweitere dein Wissen z.B. mit Hilfe von Links im Kapitel „Hilfreiche Links zum Thema OOP“.

    Gleich nehmen wir uns erstmal die Userverwaltung vor, doch zuvor ewas Grundlegendes:

    Es ist immer zu überlegen, wie die Oberkategorie in Klassen aufgeteilt werden soll. Bei unserem kleinen Projekt ist es nicht so aufwendig, dass wir komplexe Diagramme anfertigen sollten, aber hier einige Tips für die Zukunft: Als Hilfeleistung kann man die Substantive der jeweiligen Kategorie aufzählen. Bei der Kategorie Hausbau wären es z.B.: Baumaterial, Kosten, gesetzliche Regelung, Stromversorgung usw.

    Eine logische Verbindung mit Hilfe von Klassen herzustellen ist jetzt die Kunst, die sich mit der Zeit entwickelt; wobei das jetzt nicht auf die Programmierung ankommt, sondern auf einen viel wichtigeren Teil - den Entwurf der Software.

    Ich möchte aus denen, die mit OOP arbeiten wollen, die falschen Gedanken herausprügeln! OOP ist nicht mit Schleifen, Bits oder Bytes zu vergleichen, hier kann keine Lösung falsch oder richtig sein. Es ist eine andere Denkweise nötig, um an die OOP heranzugehen als an die Möglichkeiten einer Programmiersprache. OOP ist zum Beschreiben des Problems da, das Arbeiten mit Objekten kommt erst später. Wer jetzt noch beim Entwurf eines OOP-Projekts mit Fragen wie „Wie kann ich in Klassen mit einer while-Schleife die Datenbankeinträge auslesen?“ ankommt, bekommt was auf die Nuss.

    Immer gut ist eine Zeichnung, wo sich dann die einzelnen Unterkategorien (die besagten Substantive) befinden. Später knüpft man Verbindungen zwischen einzelnen Unterkategorien (meistens sind es gleich Klassen) und überlegt eine passende Beziehungsform (Vererbung, Abstraktion usw.). Was im Falle des Hausbaus als logisch erscheint ist u.a. die Beziehung zwischen Kosten und Baumaterial; es ist klar, das Material wird die Kosten steigen lassen, also könnte ein Objekt der Klasse „Baumaterial“ ein Objekt der Klasse „Kosten“ besitzen, und beim Bestellen neuer Ware automatisch das Guthaben reduzieren.

    Du merkst vielleicht schon, dass die OOP die Ideen des Menschen besser umsetzen kann als Code-Zeilen, die leicht zu einem Salat werden, da jetzt sprachliche Begriffe (für die Klassen), und gut nachvollziehbare Verbindungen verwendet werden. Es wird nicht so sein, dass deine ersten Projekte gleich eine gute OOP-Struktur haben werden; wie gut sie aber werden können hängt von dir ab. Es kommt oft vor, dass der Nachbar deine Idee zur Umsetzung anguckt und einen anderen/besseren Weg vorschlägt - da solltest Du auf jeden Fall Neugier zeigen. Spaß sollte es machen, Überlegungen während der Zugfahrt zu verschiedenen Problemen des Lebens (Verwalten einer CD-Sammlung, Verkauf von Bierkisten und -flaschen...) und deren OOP-Lösungen ist wärmstens zu empfehlen.

    Für den Entwurf der Software mit OOP gibt es sogar eigene Beschreibungssprachen wie UML.


    3 Unser Projekt


    3.1 Gesagt, getan. Unser Projekt in der Praxis

    Um auf unser Projekt mit der Galerie zurückzukommen, habe ich Folgendes in Aussicht:

    Zu jeder Oberkategorie wird es schlicht und einfach eine Klasse geben. Da „Rangsystem“ mit „User“ zusammenhängt, wird die Klasse „Rang“ ein Element der Klasse „User“, „User::rang“ brauchen, um passende Optionen zu erlauben. Die Klasse für die Bildverarbeitung wird am unabhängigsten gehalten, sie wird einige Methoden für das Arbeiten mit Bildern anbieten.

    Wir werden jetzt eine Klasse „User“ entwerfen, die so aussieht:

    PHP-Code:
    <?php
    /* user.class.php */

    class User
        
    {
        private 
    $id// Für die Datenbank
        
    private $name;
        private 
    $passwort;
        private 
    $rang;

        function 
    __construct($id)
            {
            global 
    $db_name;
            global 
    $db_pass;
            global 
    $db_rang;
            
    // Werte aus der Datenbank holen und der Klasse zuweisen:
            
    $this->id $id;
            
    $this->name $db_name[$id];
            
    $this->passwort $db_pass[$id];
            
    $this->rang $db_rang[$id];
            }
        
        final public function 
    get_id() { return $this->id; }
        final public function 
    get_name() { return $this->name; }
        final public function 
    get_passwort() { return $this->passwort; }
        final public function 
    get_rang() { return $this->rang; }

        final public function 
    change_pass($pass_alt$pass_neu)
            {
            
    // Wir ändern unser Passwort:
            
    if ($pass_alt == $this->passwort)
                {
                
    $db_pass[$id] = $pass_neu;
                
    $this->passwort $pass_neu;

                return 
    true;
                }
                else
                    {
                    return 
    false;
                    }
            }
        }
    ?>
    So, wir haben nun einen Konstruktor, der die ID als Argument erwartet, um den richtigen Datensatz in der Datenbank zu erwischen. Danach werden die Klassenelemente mit den passenden Daten aus der Datenbank initialisiert.

    Die folgenden vier Methoden (get_id()...) erscheinen vielleicht absurd, aber es hat einen Grund: Da wir eine Schnittstelle entwickeln, soll diese auch möglichst sicher sein, denn die soll ja auch oft gebraucht werden. Das heißt hätte ich die Klassenelemente auf public gesetzt und keine Methoden erstellt, könnte ein Programmierer die Elemente aus Versehen oder ohne über die Konsequenzen nachgedacht zu haben ändern, und schon hat man ein Loch im System. Man stelle sich nur vor, dass sich die ID plötzlich ändert - das könnte unerwartete Folgen beim weiteren Arbeiten mit dem Objekt mit sich ziehen. Eine ähnliche Möglichkeit bietet die __get()-Methode, auf die habe ich allerdings in diesem Fall verzichtet, da sie einfach zu allgemein ist.

    Zu dem final bleibt noch zu sagen, dass dies ebenfalls eine Sicherheitsmaßnahme ist, und zwar sollen diese final-Methoden nicht mehr von einer Kindklasse überladen werden können.

    Die Klasse „User“ kommt nun als „user.class.php“ in den Ordner „Include/Klassen/“.

    Als Nächstes wäre das Rangsystem am Zug. Man bedenkt, dass das Rangsystem in Verbindung mit Usern steht. Jeder User hat einen bestimmten Wert für das Rangsystem. Das Rangsystem muss also mit diesem Wert was anfangen können, eine Beziehung zwischen den Klassen wird entstehen:

    PHP-Code:
    <?php
    /* rang.class.php */

    class Rang
        
    {
        private 
    $rang;

        function 
    __construct($rang)
            {
            
    $this->rang $rang;
            }

        final public function 
    avatar_upload()
            {
            
    // Ist man mit dem Rang berechtigt, ein Benutzerbild anzulegen?
            
    switch ($this->rang)
                {
                case 
    4:
                return 
    true;

                break;

                case 
    3:
                return 
    true;

                break;

                default:
                return 
    false;
                }
            }
        
        final public function 
    big_pictures_upload()
            {
            
    // Nur bei $this->rang == 4 kann man große Bilder hochladen
            
    return $this->rang == true false;
            }
        }
    ?>
    Die Beziehung zwischen den beiden Klassen besteht darin, dass die Klasse „Rang“ einen Wert von „User“ erwartet, nämlich „User::rang“.

    Man hat in OOP viele Arten von Beziehungen: z.B. eine Vererbung, die in diesem Fall erstens die Flexibilität vernachlässigen würde (man müsste immer ein Objekt vom „User“ haben, um im „Rang“ zu arbeiten), und zweitens wäre es leichtsinnig, unnötige Methoden und Elemente von „User“ mit sich zu schleppen. Ins Detail zu gehen, wann und wo man welche Beziehung verwenden sollte/könnte würde jetzt den Ramen sprengen; die Handhabung in Sachen Vererbung kommt mit der Zeit, mit der Praxis, weshalb wir auch klein anfangen.

    Wir haben also den Konstruktor mit einem Argument - dem Rang-Wert „User::rang“. Anhand dieses Wertes funktionieren auch die beiden Methoden „Rang::avatar_upload()“ und „Rang::big_pictures_upload()“. Beide Methoden sind wieder als final gekennzeichnet. Bevor wir nicht wissen, wie sich eine mögliche Kindklasse in der Zukunft verhält, kann final auch nicht verkehrt sein.

    „Rang::avatar_upload()“ prüft, ob mit dem vorgegebenen Rang ein Upload eines Avatars (Benutzerbildes) möglich wäre.

    „Rang::big_pictures_upload()“ prüft, ob mit dem Rang große Bilder hochgeladen werden können.

    Die Klasse „User“ bitte als „rang.class.php“ in den Ordner „Include/Klassen/“ legen.

    Nun haben wir zwei von vier Bereichen abgedeckt, fehlt nur noch die Bildverwaltung als Klasse „Bild“:

    PHP-Code:
    <?php
    /* bild.class.php */

    class Bild
        
    {
        private 
    $bildgroesse;
        private 
    $bildhoehe;
        private 
    $bildbreite;
        public const 
    $breite_thumbnail 150// Die Breite als Thumbnail

        
    function __construct($bild)
            {
            
    // Ermitteln der Größe, Höhe, Breite.
            // Um auf das Wesentliche einzugehen, definiere ich einfach feste Werte:
            
    $this->bildgroesse 512// 512 kb
            
    $this->bildghoehe 800// 800 px
            
    $this->bildbreite 600// 600 px
            
    }
        
        final public function 
    get_bildgroesse() { return $this->bildgroesse; }
        final public function 
    get_bildhoehe() { return $this->bildhoehe; }
        final public function 
    get_bildbreite() { return $this->bildbreite; }
        
        
    // Gibt die Ausmaße in Megapixel aus:
        
    final function get_megapixel()
            {
            return 
    round($this->bildghoehe $this->bildbreite 1000000);
            }
        
    // Gibt die Höhe aus, die ein Thumbnail bei der Bildgröße haben würde
        
    final function get_thumbnail_height()
            {
            return 
    intval($this->breite_thumbnail $this->bildhoehe $this->bildbreite);
            }
        }
    ?>
    Die Klasse kommt in den Ordner „Include/Klassen/“ mit dem Dateinamen „bild.class.php“

    Wir sehen hier das konstante Element „$breite_thumbnail“ - es ist public, da eine Änderung des Wertes ausgeschlossen ist.

    Die Klasse „Bild“ repräsentiert die Daten eines Bildes. Es ist unumgänglich, den eindeutigen Sinn einer Klasse vorab zu definieren. Die Versuchung könnte hier bspw. sein, dass man eine Methode schreiben würde, um gleich einen Thumbnail zu erzeugen. Das gefällt allerdings der Klasse „Bild“, die die Daten eines Bildes verwalten soll gar nicht, die Überlegung wäre nicht passend. Eine Lösung dafür wäre eine globale Funktion, die ein Objekt der Klasse „Bild“ erwartet (Ausgansbild), und als Rückgabewert ebenfalls ein „Bild“-Objekt von dem erzeugten Thumbnail liefert:

    PHP-Code:
    <?php
    // bild.func.php

    // Erstellt einen Thumbnail
    function create_thumbnail(Bild $ausgangsbild// Ein neues Feature in PHP 5 - Type Hinting
        
    {
        
    // Wir erstellen hier lediglich ein neues Objekt, ohne tatsächlich ein Bild zu erstellen
        
    $breite $ausgangsbild->breite_thumbnail;
        
    $hoehe $ausgangsbild->get_thumbnail_height();
        
    $name 'bezeichnung_neues_bild.jpeg';

        
    // Hier würde man das neue Bild erstellen

        
    return new Bild($name);
        }
    ?>
    So ähnlich machen wir das mit der Registrierung eines neuen Users. Wir schreiben eine Funktion, die die benötigten Daten in die Datenbank aufnimmt. Es ist unsinnig, unlogisch für einen einzelnen Vorgang eine Klasse zu entwerfen. Der Rückgabewert dieser Funktion wird ebenfalls ein Objekt der Klasse „User“ sein:

    PHP-Code:
    <?php
    // user.func.php

    // Erstellt einen neuen User
    function register_user($name$passwort$rang)
        {
        global 
    $db_name;
        global 
    $db_pass;
        global 
    $db_rang;
        
    // Die ID herausfinden
        
    $neue_id sizeof($db_name);
        
    // Hier befüllen wir unsere Datenbank:
        
    $db_name[$neue_id] = $name;
        
    $db_pass[$neue_id] = $passwort;
        
    $db_rang[$neue_id] = $rang;

        return new 
    User($neue_id);
        }
    ?>
    Die beiden Funktionen kommen in den Ordner „Include/Funktionen/“. Die Dateien heißen „bild.func.php“ und „user.func.php“.

    Das, was wir bis jetzt haben reicht bereits für einige Operationen. Im nächsten Kapitel werden wir etwas mit der Schnittstelle scripten.


    4 Die Benutzung der Schnittstelle


    4.1 Bemerkungen

    Die Dateien, die ich jetzt vorstelle sind als Demos gedacht. Sie sollen zeigen, wie unsere Schnittstelle benutzt werden kann. Es wird ein Script zur Regisitrierung und eins zum Überprüfen des Rangs vorgestellt.

    4.2 Registrierung eines Users

    PHP-Code:
    <?php
    // register.php

    // Die Datenbank:
    require_once "Include/db.inc.php";
    // Klasse „User“
    require_once "Include/Klassen/user.class.php";
    // Funktion „User“
    require_once "Include/Funktionen/user.func.php";

    if (isset(
    $_POST['submit']))
        {
        
    $user register_user($_POST['name'], $_POST['pass'], 0); // Rang = 0 für einen neuen Standard-User
    ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
    </head>

    <body>
    <p>Danke für die Registrierung. Deine Daten sind:</p>
    <p>Name: <?php echo $user->get_name(); ?></p>
    <p>Passwort: <?php echo $user->get_passwort(); ?></p>
    </body>
    </html>
    <?php }
        else
            {
    ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
    </head>

    <body>
    <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
    <p>Name: <input type="text" name="name" /></p>
    <p>Passwort: <input type="text" name="pass" /></p>
    <input type="submit" name="submit" />
    </form>
    </body>
    </html>
    <?php ?>
    4.3 Das Profil eines Users checken

    PHP-Code:
    <?php
    // check.php

    // Die Datenbank:
    require_once "Include/db.inc.php";
    // Klasse „User“ und „Rang“
    require_once "Include/Klassen/user.class.php";
    require_once 
    "Include/Klassen/rang.class.php";

    ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
    </head>

    <body>
    <h1>Prüfe hier, welchen Rang ein User hat</h1>
    <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
    <p>Name: <input type="text" name="name" /></p>
    <input type="submit" name="submit" />
    </form>
    <p><?php
    if (isset($_POST['submit']))
        {
        
    // ID suchen:
        
    if (($id array_search($_POST['name'], $db_name)) === false)
            {
            echo 
    '<p>Benutzername nicht vorhanden</p>';
            }
            else
                {
                
    $user = new User($id);
                
    $rang = new Rang($user->get_rang());

                echo 
    '<p>Darf '.$user->get_name().' ein Avatar besitzen? <b>'.($rang->avatar_upload() ? 'Ja' 'Nein').'</b></p>';
                echo 
    '<p>Darf '.$user->get_name().' gro&szlig;e Bilder hochladen? <b>'.($rang->big_pictures_upload() ? 'Ja' 'Nein').'</b></p>';
                }
        }
    ?></p>
    </body>
    </html>
    Hinweis: $db_name aus „db.inc.php“ hat die ganzen Namen, die in Frage kämen, gespeichert.

    4.4 Zusammenfassung

    Ich habe nun zwei Scripte erstellt, die die Schnittstelle benutzen. Bitte vergleiche die Übersicht des Codes mit einem möglichen Code ohne OOP. Stelle vor, wie leicht man mit diesen Objekten hantieren kann, ohne jedes mal Gedanken über eine Problemlösung zu machen, die dann meistens auch nur einmal benötigt wird. Ferner achte auch auf die Fehler, die hier ohne OOP leicht entstehen könnten.

    Das Ende dieses Kapitels ist auch das Ende der Unterrichtsstunde. Demnächst geht es um eine Erweiterung unserer Benutzerschnittstelle, wo jeder mit seinen Ideen mitwirken kann. Zuvor gibt es eine Art Hausaufgabe, die Du zur Übung alleine lösen solltest.


    5 Zum Üben


    5.1 Login

    Zum Einloggen brauchen wir natürlich die Datenbank und die Klasse „User“ einzubinden. Wie man anhand eines Namens die ID herausfindet, kann man der „check.php“ entnehmen. Man merkt, dass die ID oft gebraucht wird, man könnte dafür eine Funktion schreiben. Die Aufgabe lautet also eine Funktion fürs Einloggen und eine, die die ID liefert.

    5.2 Profil bearbeiten

    Profil bearbeiten, mit anderen Worten das Ändern der Daten wie Name, Passwort (dafür haben wir eine Funktion), Avatar.

    5.3 Die Bilder

    Mit Bildern wurde in der Demo nichts gemacht. Du brauchst keine echten Bilder hochladen; es reicht, wenn Du mit Klassen rumspielst und die Ausgaben notierst.

    5.4 Admin-Bereich

    Was mit dem Admin-Bereich gemeint ist, ist jedem klar. Der Rang-Wert bei einem Admin ist sagen wir mal 4.


    6 Deine Beteiligung


    6.1 Richtlinien

    Wie schon erwähnt, kann sich jeder an dem Projekt beteiligen. Wichtig ist, dass man es mit/wegen OOP macht. Spielereien wie das Einbinden einer SQL-Datenbank oder Ähnliches sind hier also fehl am Platz. Es sind Klassen, Funktionen zu entwerfen, die unsere Schnittstelle mächtiger machen. Es dient einfach als Training.

    Vorgestellt können die Erweiterungen gleich hier. Möglichst gut strukturiert und dokumentiert, damit jeder in deine Arbeit schnell reinsteigen und diese beurteilen kann.

    Im Anhang findest Du alle Dateien, die hier vorgekommen sind.

    7 Hilfreiche Links zum Thema OOP (bei PHP 5)

    http://www.php.net/manual/de/language.oop5.php (etwas schwierig für blutige Anfänger)
    http://www.professionelle-softwareen...5.de/index.php
    ...

    OOP allgemein
    http://de.wikipedia.org/wiki/Oop
    ...

    Falls jemand interessante Links über OOP in Verbindung mit PHP 5 kennt, erweitere ich die Liste gerne.


    8 Schlusswort


    Ich hoffe, dass dieser Artikel etwas Hilfe für die zukünftige Arbeit mit OOP-Projekten bereitet hat. Entwickelt wie ich schon gesagt habe ähnliche Projekte, damit die Handhabung besser wird. Es ist einfach Übung erforderlich, weshalb ich auch auf die Weiterentwicklung von euch bestehe.
    Angehängte Dateien Angehängte Dateien
    Geändert von Strogij (18.12.2005 um 20:49 Uhr)

  3. #3
    Guest
    Registriert seit
    Aug 2002
    Beiträge
    2.233
    Zu sp&#228;ter Stunde fiel mir ein einfaches, gut nachvollziehbares Beispiel f&#252;r die abstrakten Klassen und die Vererbung ein.

    Man stelle sich die geometrischen Figuren wie Recht- und Dreieck vor. Beide Figuren haben Gemeinsamkeiten: Beide haben u.a. eine Fl&#228;che, nur die Formel (in unserem Fall die Methode) sieht bei jeder Figur anders aus:
    PHP-Code:
    <?php
    // Eine abstrakte Klasse:
    abstract class Geo_Figur
        
    {
        
    // Hier eine Methode, die in Kindklassen definiert werden muss
        // Sie muss wie die Klasse selbst als abstract gekennzeichnet werden
        // Außerdem kann von einer abstrakten Klasse kein Objekt erstellt werden
        // Näheres über abstrakte Klassen erfährst du auf
        // http://www.php.net/manual/de/language.oop5.abstract.php
        
    abstract protected function flaeche();
        }

    // Kindklasse von Geo_Figur
    class Rechteck extends Geo_Figur
        
    {
        private 
    $a 0;
        private 
    $b 0;

        public function 
    __construct($a$b)
            {
            
    $this->$a;
            
    $this->$b;
            }
        
        
    // Hier wird die abstrakte Methode definiert
        
    public function flaeche()
            {
            return 
    $this->$this->b;
            }

        
    // Rechteck::ist_quadrat() prüft nach, ob es sich um ein Quadrat handelt
        // Hierbei handelt es sich um eine spezielle Methode der Klasse Rechteck
        
    public function ist_quadrat()
            {
            return 
    $this->== $this->true false;
            }
        }

    // Kindklasse von Geo_Figur
    class Dreieck extends Geo_Figur
        
    {
        private 
    $a 0;
        private 
    $b 0;
        private 
    $c 0;

        public function 
    __construct($a$b$c)
            {
            
    $this->$a;
            
    $this->$b;
            
    $this->$c;
            }
        
        
    // Hier wird die abstrakte Methode wieder definiert
        
    public function flaeche()
            {
            return 
    $this->$this->$this->2;
            }
        }

    ##### Die Benutzung #####

    $rechteck1 = new Rechteck(57);
    $quadrat1 = new Rechteck(55);
    $dreieck1 = new Dreieck(723);

    echo 
    '<p>Fläche von $rechteck1 beträgt: '.$rechteck1->flaeche().'</p>';
    echo 
    '<p>Ist $rechteck1 ein Quadrat? '.($rechteck1->ist_quadrat() ? 'Ja' 'Nein').'</p>';

    echo 
    '<p>Fläche von $dreieck1 beträgt: '.$dreieck1->flaeche().'</p>';
    ?>
    Falls jemand Fragen hat, kann er sie nat&#252;rlich hier stellen. Viel Spa&#223;.
    Geändert von Strogij (09.11.2005 um 15:38 Uhr)

  4. #4
    TP-Specialist Avatar von theo
    Registriert seit
    Apr 2002
    Ort
    743, evergreen terrace
    Beiträge
    2.346
    hallo sergej,

    erstmal vielen dank fuer diesen workshop!!!
    ... auch wenn er das bild meiner eigenen faehigkeiten in sachen oop etwas ins wanken gebracht hat.

    mal die ganzen features von php5 aussen vor gelassen: was mich nach wie vor (auch nach unseren letzten gespraechen im icq) brennend interessiert, ist die logische abgrenzung der klassen untereinander bzw. vor allem die "ausgliederung" bestimmter funktionen. ab wann ist es sinnvoll, eine funktion ausserhalb einer oder mehrerer klassen in eine datei als reine funktion zu legen?

    hardy
    /b{2}|[^(bb)]/

    [Workshop] Nested sets

  5. #5
    TP-Specialist Avatar von mike
    Registriert seit
    Jan 2002
    Ort
    TP/Dynamik
    Beiträge
    2.876
    Hi Hardy!

    Is wohl ein philosophischer Ansatz, wie du dein Projekt angehen willst.
    Mach ich jetzt das Projekt in OOP oder strukturiert...
    Je nach Entscheidung sehe ich hier die Notwendigkeit, diese auch Projektübergreifend einzusetzen, der Durchgängigkeit halber.
    Du kannst ja dann auch eine Klasse erstellen, die dann alle 'wilden' Funktionen beinhaltet und diese dann statsich verwenden.
    Ein Mischmasch führt über kurz oder lang zur eigenen Konfusion, weil du vollkommen den Überblick verlierst (selber schon des öfteren passiert)

    Den größten Vorteil von oop in php 4x sehe ich darin, Funktionennamen zu kapseln um hier ein nachvollziebares Konzept zu realisieren.
    Beispiel:
    kunde->save();
    produkt->save();

    da tust du dir mit Funktionen schon ein bissl schwerer, weil du diese dann unique benennen musst.
    Konsequent durchgezogen entstehen so saubere und gut wiederverwendbare Schnittstellen, für die du dir dann im laufe eines größeren Projekts noch sehr dankbar sein wirst, da es so die Lesbarkeit des codes massiv erhöht.

    wie gesagt. Alles eine Frage der Ansichten und des Geschmacks
    Gehelft? Hier kannst du dich bedanken.

    mike

  6. #6
    TP-Specialist Avatar von theo
    Registriert seit
    Apr 2002
    Ort
    743, evergreen terrace
    Beiträge
    2.346
    hallo mike,

    lang, lang ist´s her ...

    in der letzten zeit hab ich all meine projekte mit oop umgesetzt. dabei sind ein paar sehr vorteilhafte klassen entstanden, die ich immer wieder mit freuden einsetze. denke da nur an meine formularklasse, die ich aus reinem hass auf die staendig auftauchenden formulare geschrieben habe. seit dem dauert ein kontaktformular schrecklich lange 2-3min.
    oop als selbstverteidigung

    aber jetzt hab ich nach moeglichkeit viele funktionen in einer klasse unterbringen wollen und war auch noch stolz darauf, wenn es gelungen war. und nun kommt sergej mit seinem workshop und meine oop-welt verfaellt zum klassenkampf.

    da es in den meisten faellen nicht nur loesungen fuer jeden geschmack und in jeder farbe gibt sondern haeuftig eine "zwingende" logik hinter den sachen steht, suche ich zunaechst diese.
    vielleicht gibt es auch ein anderes tut, in dem das beschrieben wird, dann lass ich mir auch gern eine rtfm-antwort mit einem lecken link gefallen.

    hardy (der weiterhin auf der suche nach dem heiligen gral der oop ist)
    /b{2}|[^(bb)]/

    [Workshop] Nested sets

  7. #7
    TP-Specialist Avatar von mike
    Registriert seit
    Jan 2002
    Ort
    TP/Dynamik
    Beiträge
    2.876
    jetzt schwenken wir aber schon ein wenig ins THEOretische (musste auch wieder mal sein ), das sich mit dem oop Praradigma ansich auseinandersetzt. Also vom warum zum wie...
    Also wenn du dich wirklich in diese Richtung weiterbilden willst, kann ich dir nur w&#228;rmstens empfehlen: weg von PHP, installier dir den Tomcat und programmiere in Java. (alternativ C# oder sonst irgendeine Sprache, die Objektorientierung auch in der Syntax umsetzt)
    Literatur gibt es dann f&#252;r diese Bereiche zuhauf.
    PHP hat hier halt den Nachteil, dass der Funktionsumfang einfach durch Funktionsaufrufe abgebildet ist. In den oben erw&#228;hnten Sprachen ist die ganze Sprache selbst in Objekten abgebildet und du kommst gar nicht in Versuchung einfach print() zu schreiben.
    Die n&#228;chste Hemmschwelle zu vern&#252;nftiger OOP bei PHP ist das Laufzeitverhalten. Objekte existieren nur zum Aufruf des Scripts und werden nach Beendigung wieder zerst&#246;rt.
    Wenn du mal die Vorz&#252;ge eines schnuckeligen Javabeans das im Sessionkontext oder sogar Applikationskontext l&#228;uft genossen hast, f&#228;ngst mit PHP zum heulen an und beisst dir oft eine Ecke aus dem Tisch.

    Also. Ran an den Kater, Eclipse rauf SDK downgeloadet und loslegen
    Gehelft? Hier kannst du dich bedanken.

    mike

  8. #8
    TP-Specialist Avatar von theo
    Registriert seit
    Apr 2002
    Ort
    743, evergreen terrace
    Beiträge
    2.346
    ohne deinen rat, der mir bislang immer weitergeholfen hat, in den wind schlagen zu wollen ... aber gibt es nicht einen besseren weg die oop zu verstehen, als eine weitere "fremdsprache" zu lernen?
    wenn ich nach all den jahren php einen qualitaetssprung machen und mich "programmiertechnisch evolitionaer" weiterentwickeln will, kann doch die antwort kein joviales schulterklopfen verbunden mit dem rat "lern in java programmieren, dann kannst du es" sein. wenn ich die zeit tatsaechlich haette, dann wuerde ich ueber meinen python-buechern sitzen und eine wirklich "erotische" syntax lernen.
    aber ich will es gern jetzt wissen und was waere geeigneter als gerade dieser rahmen und ein workshop zu diesem thema?!

    viele gruesse
    von einem schurken
    der es auf die harte tour lernen will
    /b{2}|[^(bb)]/

    [Workshop] Nested sets

  9. #9
    Guest
    Registriert seit
    Aug 2002
    Beiträge
    2.233
    @theo: Der Vorschlag von mike mit einer OOP-Sprache ist nicht unbedingt verkehrt, mit Sicherheit bestätigen kann ich es allerdings nicht. Selbst bei Java gibt es Fälle, wo die Klassen im Großen und Ganzen Schrott sind. D.h. wo die Benutzung der Klassen über 7 Ecken geht, das verwirrt auf die Dauer und ist auch keine große Hilfe im Vergleich zu der gewohnten Programmierung.

    In diesem Workshop geht es eher um den Entwurf eigener Klassen. Wie wird aus einem Problem eine OOP-Benutzerschnittstelle? Dazu braucht man erstmal ein gewisses Problem, was man dann unterteilt. Versuche einfach mal, ohne an die Programmierung zu denken eine Skizze mit Begriffen zu machen, wie ich es mit dem Hausbau gemacht habe. Danach postest du diese Skizze hier, wäre bestimmt für viele hilfreich den Prozess zu beobachten.

    Als Motivation zitiere ich mich einfach selbst:
    Es kommt oft vor, dass der Nachbar deine Idee zur Umsetzung anguckt und einen anderen/besseren Weg vorschlägt - da solltest du auf jeden Fall Neugier zeigen.

  10. #10
    TP-Specialist Avatar von theo
    Registriert seit
    Apr 2002
    Ort
    743, evergreen terrace
    Beiträge
    2.346
    bevor ich meinen picasso der oeffentlichkeit und mich damit der laecherlichkeit preisgebe hier noch ein hoffentlich hilfreicher link:
    http://www.professionelle-softwareen...erste_auflage/
    abschnitt II beschaeftigt sich mit meinem problem (das ich vielleicht mit dem ein oder anderen hier teile).
    /b{2}|[^(bb)]/

    [Workshop] Nested sets

  11. #11
    TP-Specialist Avatar von mike
    Registriert seit
    Jan 2002
    Ort
    TP/Dynamik
    Beiträge
    2.876
    jo, hast auch wieder recht, auch oop kann man übertreiben *aufeinbüschelhaareimmülleimerschau*
    Und schliesslich und endlich ist ja auch eine Zahl ein Objekt, oder nicht?
    ...zwar ein abstraktes, aber immerhin

    @theo: Ich leg dir auch noch das Buch 'Code Complete' ans Herz. Dreht sich zwar nicht um OOP im speziellen, aber es ist imho ein Refernzwerk, wenn es darum geht, Projekte sauber abzuwickeln.

    @DieHardy: hab mir von dir doch eh nix anderes erwartet.
    Gehelft? Hier kannst du dich bedanken.

    mike

  12. #12
    TP-Special Mod Avatar von steffenk
    Registriert seit
    Feb 2005
    Ort
    Haan / NRW
    Beiträge
    12.869
    Ich m&#246;chte mal auf ein typisches OOP-Projekt hinweisen: Typo3

    Das Projekt ist so komplex, das es ohne OOP gar nicht l&#246;sbar w&#228;re.
    Hier ist eine gute Strukturierung lebenswichtig.
    Alle Klassen sind nach Funktionsweise angelegt, d.h. wenn man eine Funktion sucht, weiss man schon, in welcher Klasse man suchen muss.
    Die Kapselung hat den riesen Vorteil, das man bei Erweiterungen nicht alle Inhalte kennen muss, da man nie ins Gehege kommt. Eine Funktion save kann in allen Klassen enthalten sein, man kann wieder eine neue in der eigenen Klasse anlegen.

    Sehr vorteilhaft ist auch der direkte Aufruf von Klassenmethoden ohne Initialisierung:
    Klasse::Funktion

    Ich muss Strogij loben f&#252;r den wertvollen Workshop und w&#252;rde es begr&#252;ssen, wenn es nicht zu einer philosophischen Abhandlung kommt sondern Praxisnahe Beispiele und Fragen bringt - da haben alle doch am meisten von.
    @Mike - welcome back on Board

    TYPO3 · MySQLDumper · dislabs
    ·
    manche Mühlen mahlen schneller ...
    "Ich habe Rücken"
    Horst Schlämmer

  13. #13
    TP-Specialist Avatar von theo
    Registriert seit
    Apr 2002
    Ort
    743, evergreen terrace
    Beiträge
    2.346
    Zitat Zitat von St@eff.en
    ... und würde es begrüssen, wenn es nicht zu einer philosophischen Abhandlung kommt sondern Praxisnahe Beispiele und Fragen bringt - da haben alle doch am meisten von.
    ich zieh mir das maentelchen mal an ...
    aber hast du nicht angst, dass zum schluss ausser einer kleinen "elite" hier keiner beim workshop mitmacht, wenn die grundlagen nicht voellig klar sind?!
    mir geht es hier auch nicht ums theo-retisieren (um den nochmal aufzugreifen) sondern ums verstehen.
    aber gehen wir mal von mir weg und davon aus, dass diese statistik repraesentativ ist. und wenn wir uns dann noch darauf einigen koennen, dass wirkliche oop erst seit php5 moeglich ist, dann duerften da draussen noch mehr honks wie ich rumrennen.
    wenn ich weiss warum sergej etwas wie gemacht hat, dann bin ich mit wehenden fahnen dabei!

    so ... jetzt schwinge ich wieder den pinsel und mach meine hausaufgabe fertig
    /b{2}|[^(bb)]/

    [Workshop] Nested sets

  14. #14
    TP-Special Mod Avatar von steffenk
    Registriert seit
    Feb 2005
    Ort
    Haan / NRW
    Beiträge
    12.869
    Das ist schon klar theo - aber oop gibts ja auch schon vor php5. Und Klassen sind ein Teil von OOP und daher f&#252;r jeden n&#252;tzlich.
    Gerade diese grossen theoretischen Abhandlungen schaffen den Respekt, so das sich sich eben nur die Elite dran traut. Dabei geben sich die "Erkl&#228;rer" solche M&#252;he, praxisnahe Beispiele zu finden.

    Ich will auch mit dem Vorurteil reinen Tisch machen, OOP w&#228;re nur was f&#252;r Freaks. Die Grundz&#252;ge beutzt fast jeder ohne sich dessen bewusst zu machen, und so f&#252;rchterlich kompliziert ist das auch nicht. Wenn man mal die Vorteile kennengelernt hat, m&#246;chte man garnicht mehr anders vorgehen

    Aber richtig, es soll keine Elitediskussions entstehen, ich begr&#252;sse alle, die einfach mal versuchen zu verstehen worum es geht und nur mal versuchen sich da rein zu denken, bei Unklarheiten hier auch fragen - das trifft den Nerv aller php-Programmierer

    TYPO3 · MySQLDumper · dislabs
    ·
    manche Mühlen mahlen schneller ...
    "Ich habe Rücken"
    Horst Schlämmer

  15. #15
    TP-Specialist Avatar von mike
    Registriert seit
    Jan 2002
    Ort
    TP/Dynamik
    Beiträge
    2.876
    Vielleicht noch ein Wort zu den abstrakten Klassen: man möge mich schlagen, aber haben die in PHP Sinn? Ist es nicht so, dass diese eigentlich nur in typsicheren Sprachen wirklich sinnvoll sind?
    Beispiel zu S. Geo_Figur, was man dann mit so einer Klasse in einer typsicheren Sprache machen kann bzw. muss.

    Vorausgesetzt, ich will mir einen Haufen Dreiecke und Rechtecke sammeln, dann baue ich in einer typsicheren Sprache ein Array auf, das den Typ des Basiswerts besitzt:

    bsp:
    Code:
    Geo_Figur figurenHaufen [] = 10; //bau mir ein Array von 10 Feldern
    Ich brauch mir zu dem Zeitpunkt keine Sorgen machen, ob ich hier ein Dreieck oder ein Rechteck reinpatze.

    im Programm kommt dann die tatsächliche Zuweisung ins Array:
    Code:
    figurenHaufen[1] =  new Rechteck(5, 7);
    figurenHaufen[2] =   new Rechteck(5, 5);
    figurenHaufen[3] =  new Dreieck(7, 2, 3);
    Soweit ich mich da noch an die THEOrie (hehe ) erinnern kann, handelt es sich dabei dann um eine 'späte Bindung'.
    Denn jetzt kommt der Vorteil einer solchen Basisklasse wunderbar zum Tragen.
    Aufgrund der Tatsache, dass Strogij in seiner Klasse bereits alle Funktionen definiert hat, die wir in weiterer folge benötigen, kennt figurenHaufen diese ebenfalls schon und kann sie verwenden. Was diese Funktionen wirklich machen, ja das hat aber dann das konkrete Objekt (Rechteck, Dreieck...) implementiert.

    also funktioniert jetzt z.b. sowas:
    Code:
    for ( int i = 0; i < 10; i++ )
    {
      show figurenHaufen[i].flaeche();
    }
    Was jedoch nicht funktionieren würde wäre dies:
    Code:
    for ( int i = 0; i < 10; i++ )
    {
      show figurenHaufen[i].ist_quadrat();
    }
    Da hier nur Quadrat diese Funktion beinhaltet würde dies bei einem Dreieck im Array zu einem Fehler führen.

    In PHP is das ganze ja schon mal wieder viel einfacher, da sich diese Nutte nicht um Typen kümmert also brauch ich auch keine Deklaration dahingehend, dass ich irgendwann mal die Basisklasse bekanntmache.

    Code:
    $figurenHaufen = Array();
    $figurenHaufen[1] =  new Rechteck(5, 7);
    $figurenHaufen[2] =   new Rechteck(5, 5);
    $figurenHaufen[3] =  new Dreieck(7, 2, 3);
    
    for ( $i = 0; $i < 10; $i++ )
    {
      echo figurenHaufen[$i].flaeche();
    }
    Also sehe ich hier bis auf die Tatsache, dass ich eine abstrakte Klasse nicht irrtümlicherweise instanzieren kann, in PHP keinen sinnvollen Einsatz dafür.
    Bin aber lernfähig und lass mich gern vom Gegenteil überzeugen.


    Vererbung in dem Sinne verwende ich in PHP nur dann, wenn ich Klassen zusammenfassen kann und gemeinsame Funktionen in eine Basisklasse auslagern kann.

    Wie z.B. ich will nicht nur die Fläche, sondern z.b. diese auch anmalen also definiere ich eine funktion getColor($R,$G,$B) bereits in der Basisklasse als public und implementiere in der Basisklasse bereits die Funktionalität.
    Jetzt braucht sich weder Dreieck noch Rechteck Sorgen machen, wie zum Teufel sie sich ihre Fläche anmalen sollen.

    Und zum Abschluß vielleicht noch eine Verständnisaufgabe in die Runde: wie würdet es ihr in dem Beispiel machen, um dieses Figurendings um die Funktionalität getUmfang() zu erweitern?
    Wo würde diese Funktion hinpassen? Basis? Dreieck/Rechteck?

    Sorry, S. dass ich dir da jetzt ein bissl dazwischengefunkt hab

    Mike
    Gehelft? Hier kannst du dich bedanken.

    mike

Seite 1 von 3 123 LetzteLetzte

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)


Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)

     

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51