TP Underground Lounge 07/08
-


Hinweise


Antwort
 
LinkBack Themen-Optionen Thema durchsuchen
Alt 07.11.2005, 19:35   #1
TP-Special Mod
 
Benutzerbild von steffenk
 
Registriert seit: Feb 2005
Ort: Haan / NRW
steffenk lebt für das TP und seine Usersteffenk lebt für das TP und seine Usersteffenk lebt für das TP und seine Usersteffenk lebt für das TP und seine Usersteffenk lebt für das TP und seine Usersteffenk lebt für das TP und seine Usersteffenk lebt für das TP und seine Usersteffenk lebt für das TP und seine User

[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
steffenk ist gerade online   Mit Zitat antworten


Alt 07.11.2005, 19:48   #2
TP-Specialist
 
Registriert seit: Aug 2002
Strogij hilft, wo's gehtStrogij hilft, wo's geht
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
Dateityp: zip Workshop - OOP-Projekt.zip (4,3 KB, 166x aufgerufen)

Geändert von Strogij (18.12.2005 um 20:49 Uhr).
Strogij ist offline   Mit Zitat antworten
Alt 09.11.2005, 03:39   #3
TP-Specialist
 
Registriert seit: Aug 2002
Strogij hilft, wo's gehtStrogij hilft, wo's geht
Zu später Stunde fiel mir ein einfaches, gut nachvollziehbares Beispiel fü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ä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ürlich hier stellen. Viel Spaß.

Geändert von Strogij (09.11.2005 um 15:38 Uhr).
Strogij ist offline   Mit Zitat antworten
Alt 09.11.2005, 10:19   #4
TP-Specialist
 
Benutzerbild von theo
 
Registriert seit: Apr 2002
Ort: 743, evergreen terrace
theo macht sich hier sehr viel Mühe
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
gutes webdesign
theo ist offline   Mit Zitat antworten
Alt 09.11.2005, 10:46   #5
TP-Specialist
 
Benutzerbild von mike
 
Registriert seit: Jan 2002
Ort: TP/Dynamik
mike bringt sich richtig ein
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
mike ist offline   Mit Zitat antworten
Alt 09.11.2005, 12:08   #6
TP-Specialist
 
Benutzerbild von theo
 
Registriert seit: Apr 2002
Ort: 743, evergreen terrace
theo macht sich hier sehr viel Mühe
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
gutes webdesign
theo ist offline   Mit Zitat antworten
Alt 09.11.2005, 12:38   #7
TP-Specialist
 
Benutzerbild von mike
 
Registriert seit: Jan 2002
Ort: TP/Dynamik
mike bringt sich richtig ein
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ä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ür diese Bereiche zuhauf.
PHP hat hier halt den Nachteil, dass der Funktionsumfang einfach durch Funktionsaufrufe abgebildet ist. In den oben erwähnten Sprachen ist die ganze Sprache selbst in Objekten abgebildet und du kommst gar nicht in Versuchung einfach print() zu schreiben.
Die nächste Hemmschwelle zu vernünftiger OOP bei PHP ist das Laufzeitverhalten. Objekte existieren nur zum Aufruf des Scripts und werden nach Beendigung wieder zerstört.
Wenn du mal die Vorzüge eines schnuckeligen Javabeans das im Sessionkontext oder sogar Applikationskontext läuft genossen hast, fä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
mike ist offline   Mit Zitat antworten