Werbung einblenden Werbung ausblenden


Home / Tutorials / PHP Handbuch / Objektorientierte Programmierung


Objektorientierte Programmierung
Eine Klasse erweitern

Objektorientierte Programmierung

Abstrakt läßt sich schnell erklären, was man unter objektorientierter Programmierung versteht. Ein Objekt ist eine Instanz einer Klasse. Eine Klasse wiederum ist eine Sammlung von Variablen und Methoden. Wer will kann es auch so sehen: Das Objekt verhält sich zur Klasse, wie Substantive natürlicher Sprachen zu dem Gegenstand, den sie bezeichnen. Der einzige Unterschied besteht darin, dass die einzelnen Deutschen sich unter Tisch (einer Klasse also) höchst unterschiedliche Dinge vorstellen. Der eine stellt sich was vor mit drei Beinen, der nächste mit vier, der übernächste mit fünf, der eine meint,die Tischplatte ist rund der nächste dreieckig, etc. etc. etc. Das geht in der Programmierung nicht so ohne weiteres. Will man die Grundklasse in der Programmierung modifizieren, muss schon genau festgelegt werden wie. Wer aber zu Ikea geht, und einen Tisch will, wird vom Verkäufer zu konkreten Objekten geführt, die alle die Eigenschaft haben, die die Klasse Tisch hat. Die Tischplatte wird einen gewissen Abstand zum Boden haben, die Platte wiederum wird auf mehreren wie auch immer gearteten Pfeilern ruhen, die Tischplatte wird mehr oder weniger horizontal sein etc. Der langen Rede kurzer Sinn. Das Konzept der objektorientierten Programmierung ist trivial. Jedes Substantiv in jeder natürlichen Sprache ist eine Klasse. Es verweist auf Objekte, die alle Eigenschaften und Methoden der Klasse haben. Allerdings nur diese. Ein Tisch, der Personen von A nach B befördert, würde nicht mehr zur Klasse Tisch gehören, sondern zur Klasse Fahrzeug. Der schnellste Weg, sich mit der objektorientierten Programmierung vertraut zu machen, ist ein Programm zu schreiben, dass den objektorientierten Ansatz nutzt. Das ist jetzt allerdings nicht mehr so trivial.

<?
class rechner
{
var $a;
var $b;
var $summe;
function setze_werte($c,$d)
{
$this->a=$c;
$this->b=$d;
}

function rechnen()
{
$this->summe=$this->a+$this->b;
return $this->summe;
}
}

$zeiger=new rechner;
$zeiger->setze_werte(40,60);
$ergebnis1=$zeiger->rechnen();
print "Das Ergebnis der ersten Addition ist2".
" <font color=blue>$ergebnis1</font><br>";

$zeiger2=new rechner;
$zeiger2->setze_werte(400,60);
$ergebnis2=$zeiger2->rechnen();
print "Das Ergebnis der ersten Addition ist".
" <font color=blue>$ergebnis2</font><br>";
?>

Wie deutlich sichtbar, definieren wir eine Klasse. Das heisst wir definieren, um das oben Gesagte wieder aufzugreifen, ein Substantiv. Die konkreten Objekte, die wir anschliessend generieren, haben dann alle die Eigenschaften, die die Klasse hat. Nicht mehr, aber auch nicht weniger. Unsere Klasse hat drei Variablen nämlich $a, $b und $summe. Folglich werden alle unsere Objekte auch diese drei Variablen haben, unabhängig davon, ob wir sie mit Inhalt füllen oder nicht. Weiter haben wir eine Funktion setze_werte. Die macht das, was der Name schon sagt. Mit ihr kann man dem Objekt Werte zuordnen, nämlich $a und $b. So ist da ja auch mit den Tischen. Dass ein Tisch zum Beispiel eine Farbe hat, ist klar. Aber niemand geht davon aus, dass alle Tische, die uns der IKEA Verkäufer zeigt, diesselbe Farben haben (Im Gegensatz zu Tomaten im übrigen. Da wären wir echt platt, wenn sie auf einmal lila sind.) Wir definieren also innerhalb der Klasse, welche Eigenschaften unsere Objekte, deren Struktur in der Klasse definiert wird, haben. Was uns wirklich verblüfft ist aber die Syntax der Funktion setze_werte(). Was uns nicht verblüfft ist die Tatsache, dass sie zwei Parameter übergeben bekomm ($c und $d). Da kennen wir schon aus dem Kapitel Funktionen . Verblüffend ist das:

$this->a=$c;
$this->b=$d;

Um diese Zeilen zu verstehen, müssen wir uns erst mal klar machen, dass in dem Beispiel oben zwei Objekte generiert werden, wobei jedes Objekt eigene Werte für $a und $b hat. Wir merken dass drastisch an der Tatsache, dass wir auch zwei verschiedene Ergebnisse erhalten (100 (40 +60) und 460 (400 +60)). Wir rufen also die selbe Klasse auf, initialisieren die Objekte aber mit unterschiedlichen Werten. Damit kann man sich schon fast denken, für was das $this steht. Es steht für das Objekt, mit $this->a=$c weisen wir also dem aufgerufenen Objekt für die Variable $a einen Wert zu. Jetzt kann man sich die Frage stellen, wie das genau funktionniert. In der Zeile

$zeiger=new rechner

bilden wir eine Instanz der Klasse rechner. Wir bilden also ein Objekt, dass alle Eigenschaften der Klasse rechner hat. Mit

$zeiger->setze_werte(40,60)

greifen wir auf die Funktion setze_werte() unseres Objektes zu. Unser Objekt hat die Funktion setze_werte(), weil ja die Klasse, zu der unser Objekt gehört, diese Funktion auch hat. Durch die spezielle Syntax mit dem Pfeil, wird beim Aufruf der Funktion setze_werte der Zeiger auf das Objekt gleich mitgeliefert. Dieser Zeiger auf das Objekt ist dann $this. $this und $zeiger verweisen also jeweils auf das selbe Objekt. Man könnte das Programm auch anders schreiben und ohne Verwendung von $this direkt auf die Variablen (Eigenschaften) des Objektes zugreifen. Das macht dann nocheinmal deutlich, dass $this und $zeiger auf das selbe Objekt verweisen.

<?
CLASS RECHNER
{
VAR $A;
VAR $B;
VAR $SUMME;

FUNCTION RECHNEN()
{
$THIS->summe=$a+$b;
return $this->summe;
}
}

$zeiger=new rechner;
$zeiger->a=40;
$zeiger->b=60;
$ergebnis1=$zeiger->rechnen();
print "Das Ergebnis der ersten Addition ist <FONT COLOR=BLUE>$ergebnis1</FONT><BR>";

$zeiger2=new rechner;
$zeiger2->a=400;
$zeiger2->b=60;
$ergebnis2=$zeiger2->rechnen();
print "Das Ergebnis der ersten Addition ist <FONT COLOR=BLUE>$ergebnis2</FONT><BR>";
?>

In diesem Beispiel haben wir uns die Funktion (Methode) setze_werte() geschenkt. Wir übergeben die Werte für die Eigenschaften des Objektes direkt.

$zeiger->a=400;
$zeiger->b=60;

Wie deutlich zu erkennen ist, wenn man das Skript laufen lässt, das Ergebnis genau das gleiche. Wir übergeben zwar die Werte direkt an das Objekt, holen es aber mit $this wieder raus. $zeiger und $this verweisen also auf dasselbe Objekt. Wer bis hierher gelesen hat, dem ist auch klar, warum dieser Code hier keinerlei Ergebnisse zeitigt.

<?
CLASS RECHNER
{
VAR $A;
VAR $B;
VAR $SUMME;

FUNCTION RECHNEN()
{
$SUMME=$THIS->a+$this->b;
}

function dividieren()
{
$d=$this->summe/2;
return $d;
}
}

$zeiger=new rechner;
$zeiger->a=40;
$zeiger->b=60;

$zeiger2=new rechner;
$zeiger2->a=400;
$zeiger2->b=60;
$ergebnis1=$zeiger->rechnen();
$ergebnis2=$zeiger2->rechnen();
$ergebnis3=$zeiger->dividieren();
$ergebnis4=$zeiger2->dividieren();

print "Das Endergebnis ist <FONT COLOR=RED>$ergebnis3</FONT><BR>";
print "Das Endergebnis ist <FONT COLOR=RED>$ergebnis4</FONT><BR>";
?>

Auch hier werden zwar Werte für $a und $b gesetzt und die Summe dieser beiden Zahlen wird auch ausgerechnet, aber das Ergebnis wird an $summe übergeben. Somit ist total unklar, zu welchem konkreten Objekt $summe gehört und foglich erscheint zweimal 0. Damit es funktionniert, muss auch das Ergebnis der Addition ebenfalls dem Objekt zugeordnet werden.

<?
CLASS RECHNER
{
VAR $A;
VAR $B;
VAR $SUMME;

FUNCTION RECHNEN()
{
$THIS->summe=$this->a+$this->b;
}

function dividieren()
{
$d=$this->summe/2;
return $d;
}
}

$zeiger=new rechner;
$zeiger->a=40;
$zeiger->b=60;

$zeiger2=new rechner;
$zeiger2->a=400;
$zeiger2->b=60;
$ergebnis1=$zeiger->rechnen();
$ergebnis2=$zeiger2->rechnen();
$ergebnis3=$zeiger->dividieren();
$ergebnis4=$zeiger2->dividieren();

print "Das Endergebnis ist <FONT COLOR=RED>$ergebnis3</FONT><BR>";
print "Das Endergebnis ist <FONT COLOR=RED>$ergebnis4</FONT><BR>";
?>

Es ist in der objektorientierten Programmierung üblich, schon bei der Instanziierung eines Objektes diesem Werte zuzuweisen. Das geschieht mit Hilfe eines Konstruktors. Eine Konstruktor ist eine spezielle Methode, die den gleichen Namen trägt wie die Klasse. Das Beispiel oben könnte folglich auch so geschrieben werden.

<?
CLASS RECHNER
{
VAR $A;
VAR $B;
VAR $SUMME;
FUNCTION RECHNER($A,$B)
{
$THIS->a=$a;
$this->b=$b;
}

function rechnen()
{
$this->summe=$this->a+$this->b;
}

function dividieren()
{
$d=$this->summe/2;
return $d;
}
}

$zeiger=new rechner(40,60);
$zeiger2=new rechner(400,60);
$ergebnis1=$zeiger->rechnen();
$ergebnis2=$zeiger2->rechnen();
$ergebnis3=$zeiger->dividieren();
$ergebnis4=$zeiger2->dividieren();

print "Das Endergebnis ist <FONT COLOR=RED>$ergebnis3</FONT><BR>";
print "Das Endergebnis ist <FONT COLOR=RED>$ergebnis4</FONT><BR>";
?>

Wir erhalten wieder das richtige Ergebnis: Für das erste Objekt 50 (40+60/2) und für das zweite Objekt 230 (400+60/2).

Eine Klasse erweitern



Wenn eine Klasse, die man braucht, mit einer anderen Klasse weitgehend identisch ist, aber eine Funktionalität fehlt, so ist es am günstigsten, man nimmt die eine Klasse und erweitert sie um die Funktion, die sie noch nicht hat. Unser Beispiel von oben könnten wir auch anders schreiben. Anstatt in der Klasse rechner die Funktion dividieren hinzuzufügen, könnte man auch auch eine neue Klasse schreiben und die Funktionen aus der Klasse rechner einfach an diese neue Klasse vererben.

<?
CLASS RECHNER
{
VAR $A;
VAR $B;
VAR $SUMME;
FUNCTION RECHNER($A,$B)
{
$THIS->a=$a;
$this->b=$b;
#print $this->a;
}

function rechnen()
{
$this->summe=$this->a+$this->b;
}
}

class divisio extends rechner
{
function dividieren()
{
$d=$this->summe/2;
return $d;
}
}

$zeiger=new divisio(40,60);
$zeiger2=new divisio(400,60);
$ergebnis1=$zeiger->rechnen();
$ergebnis2=$zeiger2->rechnen();
$ergebnis3=$zeiger->dividieren();
$ergebnis4=$zeiger2->dividieren();

print "Das Endergebnis ist <FONT COLOR=RED>$ergebnis3</FONT><BR>";
print "Das Endergebnis ist <FONT COLOR=RED>$ergebnis4</FONT><BR>";
?>

Das ist natürlich in so einem kleinem Beispiel nicht besonders witzig, zeigt aber das Prinzip. Es würde wenig Sinn machen, eine Funktion, die nur in einem Spezialfall gebraucht wird, in die Klasse rechner zu schreiben. In so einem Fall ist es besser, die Basisklasse zu erweitern. Wie deutlich zu erkennen, hat die Klasse, divisio selbst keinen Konstruktor. Sie erbt diesen von der Basisklasse, also von Rechner. Man hätte den Konstruktor auch in die Kindklasse verlegen können, wie das Beispiel unten zeigt. Allerdings ist das völlig sinnlos, weil damit die Elternklasse, die die eigentlich bedeutsame ist, unbrauchbar gemacht wird.

<?
CLASS RECHNER
{
VAR $A;
VAR $B;
VAR $SUMME;

FUNCTION RECHNEN()
{
$THIS->summe=$this->a+$this->b;
}
}

class divisio extends rechner
{
function divisio($a,$b)
{
$this->a=$a;
$this->b=$b;
}
function dividieren()
{
$d=$this->summe/2;
return $d;
}
}

$zeiger=new divisio(40,60);
$zeiger2=new divisio(400,60);
$ergebnis1=$zeiger->rechnen();
$ergebnis2=$zeiger2->rechnen();
$ergebnis3=$zeiger->dividieren();
$ergebnis4=$zeiger2->dividieren();

print "Das Endergebnis ist <FONT COLOR=RED>$ergebnis3</FONT><BR>";
print "Das Endergebnis ist <FONT COLOR=RED>$ergebnis4</FONT><BR>";
?>

Für ein interessanters Beispiel für objektorientierte Programmierung siehe Gästebuch:die objektorientierte Variante

vorhergehendes Kapitel