Folien



(letzte Synchronisation der PDF-Präsentation: 02.08.2017)

Falls keine PDF-Präsentation zu sehen ist, klicken Sie zum Download hier: Direktdownload PDF-Präsentation

Under construction - Muss noch aufgeteilt werden!

Klassen können Oberklassen/Basisklassen (Eltern) und Unterklassen (Kinder) haben. Ein Kind erbt alles (Attribute, Methoden) von den Eltern, sofern es innerhalb der Kind-Klasse nicht anders definiert wurde. Um eine Klasse als Unterklasse einer anderen zu definieren, benutzt man extends.

Terminologie: Basisklasse, Oberklasse, Unterklasse, Superklasse, Subklasse

Wir einigen uns auf folgende Terminologie:

Basisklasse (synonym zu Oberklasse, Superklasse, Elternklasse)
Unterklasse (synonym zu Subklasse, Kindklasse)

Beispiel: Definieren einer (Basis-)Klasse “Tier” und einer Unterklasse “Hund”

PHP-Code
  class Tier { public $hungrig = 'Ich habe Hunger.';   function fressen($nahrung) { $this->hungrig = 'Ich habe keinen so großen Hunger.'; } }   class Hund extends Tier { function fressen($nahrung) { if($nahrung == 'Knochen') { $this->hungrig = 'Jetzt bin ich schön satt.'; } else { echo 'Wuff wuff, ich mag nur Knochen!!'; } } }  

Die Methode fressen wird durch die Unterklasse überschrieben, da der Hund nur Knochen mag. Der anfängliche Zustand von “hungrig” bleibt bestehen und kann deshalb von der Basisklasse “Tier” geerbt werden.

Das Funktionieren können wir überprüfen, indem wir den Hund mit Knochen oder etwas anderem füttern:

PHP-Code
  // $hund mit einem Salatkopf füttern echo "<em>Der Hund bekommt jetzt einen Salatkopf.</em><br />"; $hund->fressen('Salatkopf'); echo $hund->hungrig;   // $hund mit einem Knochen füttern echo "<em>Der Hund bekommt jetzt einen Knochen.</em><br />"; $hund->fressen('Knochen'); echo $hund->hungrig;  

Komplettes Listing: Klassen Tier, Hund definieren; Objekt $hund erzeugen und füttern

PHP-Code
  class Tier { public $hungrig = 'Ich habe Hunger.<br />';   function eat($food) { $this->hungrig = 'Ich habe keinen so großen Hunger.<br />'; } }   class Hund extends Tier { function fressen($nahrung) { if($nahrung == 'Knochen') { $this->hungrig = 'Jetzt bin ich schön satt.<br />'; } else { echo 'Wuff wuff, ich mag nur Knochen!! Gib mir etwas anderes!<br />'; } } }   // Objekt $hund instanziieren $hund = new Hund;   // Anfangszustand des Objekts ausgeben echo $hund->hungrig;   // $hund mit einem Salatkopf füttern echo "<em>Der Hund bekommt jetzt einen Salatkopf.</em><br />"; $hund->fressen('Salatkopf'); echo $hund->hungrig;   // $hund mit einem Knochen füttern echo "<em>Der Hund bekommt jetzt einen Knochen.</em><br />"; $hund->fressen('Knochen'); echo $hund->hungrig;  

Scope Resolution Operator (::)

Offizielle Bezeichnung (auch in Fehlermeldungen): “Paamayim Nekudotayim” (hebräisch für “doppelter Doppelpunkt”), wird auch als “Gültigkeitsoperator” bezeichnet.

Funktionsweise des Scope Resolution Operators

Der Scope Resolution Operator erlaubt es, auf statische Eigenschaften und Methoden zuzugreifen.

Wenn ein Objekt instanziiert wird, werden u.U. Methoden oder Attribute der Basisklasse überschrieben (im Beispiel im Artikel wird die Methode fressen der Basisklasse Tier überschrieben durch die Methode fressen der Unterklasse Hund). Die überschriebene Methode kann aber aus dem Objekt heraus aufgerufen und benutzt werden. Dazu benutzt man Klasse::methode(); bzw. parent::methode();:

PHP-Code
  // Basisklasse: Tier class Tier { // Attribut $hungrig = Anfangszustand der Klasse Tier public $hungrig = 'Ich habe Hunger.<br />';   // Konstruktor: Wird bei der Instanziierung eines (Unter-)Objekts der Klasse Tier aufgerufen function __construct() { echo "Ich bin ein Tier.<br />"; }   // Methode fressen, gilt für alle Objekte der Klasse Tier: Was immer ein Tier frisst, danach ist es satt. function fressen($nahrung) { $this->hungrig = 'Ich habe keinen Hunger.<br />'; } }   // Unterklasse: Hund class Hund extends Tier { public $rasse;   // Konstruktor: Wird bei der Instanziierung eines Objekts $hund aufgerufen - Rasse muss bestimmt werden, d.h.: Jeder Hund hat zwangsläufig eine Rasse. Dieser Konstruktor überschreibt den Konstruktor der Klasse Tier. function __construct($rasse) { $this->rasse = $rasse;   // Da der Konstruktor der Klasse Tier durch den Konstruktor der Klasse Hund überschrieben wurde, müssen wir ihn explizit aufrufen: Tier:: __construct(); }   // Die Klasse Hund definiert eine Methode 'fressen' und überschreibt damit die Methode 'fressen' der Basisklasse Tier ... function fressen($nahrung) { if($nahrung == 'Knochen') { // ... trotzdem kann der Hund die überschriebene Methode fressen der Basisklasse Tier verwenden Tier::fressen($nahrung); // Möglich ist auch die pauschale Verwendung von parent::fressen($nahrung); - hier wird automatisch die Basisklasse ("Elternklasse") verwendet. } else { echo 'Wuff wuff, ich mag nur Knochen!! Gib mir etwas anderes!<br />'; } } }   // Objekt $hund instanziieren $hund = new Hund('Mops');   // Anfangszustand des Objekts ausgeben echo $hund->hungrig;   // $hund mit einem Salatkopf füttern echo "<em>Der Hund bekommt jetzt einen Salatkopf.</em><br />"; $hund->fressen('Salatkopf'); echo $hund->hungrig;   // $hund mit einem Knochen füttern echo "<em>Der Hund bekommt jetzt einen Knochen.</em><br />"; $hund->fressen('Knochen'); echo $hund->hungrig;   // Kontrollieren: Konstruktor der Unterklasse Hund echo "<br /><br />"; $hundsrasse = $hund->rasse; echo $hundsrasse;  

Wenn man eine statische Methode von außerhalb des Objekts aufrufen will, erhält man eine Fehlermeldung:

PHP-Code
  Dog::fressen('cookie');  

Fatal error: Using $this when not in object context

Methoden/Attribute als statisch deklarieren

“Mit dem Schlüsselwort static werden Methoden (ab PHP 5) oder Eigenschaften (ab PHP 4) einer Klasse als statisch deklariert. Statisch heißt, dass diese Methoden oder Eigenschaften verwendet werden können, ohne dass ein Objekt aus der Klasse erzeugt wurde.” (php-bar.de – static)Sie werden mit dem Scope Resolution Operator aufgerufen.

Beispiel 1: Hund mit Schlüsselwort “static” + Gültigkeitsoperator

PHP-Code
  class Hund { static $hungrig = 'Ich bin hungrig.';   static function fressen($nahrung) { if($nahrung == 'Knochen') { self::$hungrig = 'Ich bin satt.'; } else { echo 'Wuff, wuff, ich möchte nur Knochen.'; } } } Hund::fressen('Knochen'); echo Hund::$hungrig;  

self::$hungrig lässt sich auch ausdrücken durch Hund::$hungrig

Beispiel 2: Hund ohne Schlüsselwort “static”

Werden die Variablen und Methoden hier nicht als static deklariert, dann funktioniert der Scope Resolution Operator nicht, und der $hund muss als Objekt instanziiert werden:

PHP-Code
  class Hund { function fressen($nahrung) { if($nahrung == 'Knochen') { $this->hungrig = 'Ich bin satt.'; } else { $this->hungrig = 'Ich möchte lieber einen Knochen'; } } }   $hund = new Hund; $hund->fressen('Knochen'); echo $hund->hungrig;  

Anderes gutes Beispiel: Scope Resolution Operator bei phpbar.de

Abstrakte Klassen

Abstrakte Klassen werden nicht instanziiert, sondern dienen nur als Basisklassen für andere Klassen. In abstrakten Klassen können auch abstrakte Methoden definiert werden.

Beispiel:

PHP-Code
  abstract class Tier { public $hungrig = 'Ich bin hungrig';   abstract public function fressen($nahrung); }   class Hund extends Tier { function fressen($nahrung) { if($nahrung == 'Knochen') { $this->hungrig = 'Bin nicht mehr hungrig.'; } else { echo 'Wuff, wuff, ich will lieber einen Knochen.'; } } }   $hund = new Hund; $hund->fressen('Salat'); echo $hund->hungrig;  

Übungen

Alle Übungen finden Sie in der Materialsammlung (dort auch alle zusätzlichen Dateien wie Bilder, Klassendiagramme oder HTML-Vorlagen!).

Die aktuelle Übung können Sie hier als txt-File herunterladen.


***** Übungen: PHP/OOP - Vererbung *****

PHP/OOP_7: Vererbung - Vererbungsdiagramm analyiseren (Chipkarte)

Betrachten Sie das Klassendiagramm 10phpoop/oopphp07-bild-chipkarte.png

1) Welches sind "Elternklasse(n)", welches "Kindklasse(n)"?
2) Schreiben Sie eine Liste: Welche Attribute und Methoden hat die Klasse "Mensakarte"?
3) Sowohl "Chipkarte" als auch "Bibliothekskarte" haben eine Methode "statusAnzeigen()". Wie verhält sich diese Methode, wenn ein Objekt der Klasse Bibliothekskarte instanziiert wird?
4) Halten Sie es für sinnvoll, die Klasse Chipkarte abstrakt zu gestalten? Begründen Sie Ihre Antwort.




PHP/OOP_7-0: SEHR einfache Vererbungsaufgabe: Hund

Programmieren Sie eine Klasse Hund (Attribute: groesse, Methoden: bellen(), diese MEthode gibt aus: "Wuff Wuff") mit den Gettern und Settern (alt+einfügen!) und eine Unterklasse Jagdhund (mit der Methode fass()). Die Methode fass() gibt aus "Ich habe das Kaninchen geschnappt."
--- Brauchen Sie für die Klasse "Jagdhund" auch Getter und Setter?
--- Instanziieren Sie jeweils ein Objekt der beiden Klassen
--- Lassen Sie sich für das jeweilige Objekt die Attributwerte ausgeben und verwenden Sie die Methoden.
--- Erweitern Sie die Klasse Jagdhund so, dass für die Methode "fass()" ein Ziel als Parameter übergeben werden kann (z.B. "fass('Kaninchen')"); die Methode gibt dann "Ich habe das Kaninchen geschnappt" aus.




PHP/OOP_7-1: Einfache Vererbungsaufgabe: Artikelverwaltung

Sie programmieren die Produktverwaltung eines Warenwirtschaftssystems. Jedes Produkt hat eine Artikelnummer, einen Namen und einen Nettopreis, außerdem die entsprechenden Getter und Setter (alt+einfügen!). Besondere Produkte sind die Musik-CD, die noch die Laufzeit in Minuten und den Interpreten enthält, und das Kinderfahrrad, wo über die Methode "farbeSetzen(farbe:String)" beim Bestellen eine Farbe gewählt werden kann.

- Erstellen Sie ein Klassendiagramm zu dieser Situation.
- Programmieren Sie die Klassen. Weisen Sie allen Attributen Initialwerte zu. Alle Attribute und Methoden sind der Einfachheit halber erst mal public.
- Testen Sie, ob alles funktioniert, indem Sie
---- ein Objekt jeder Klasse instanziieren
---- für die Objekte die einzelnen Attributswerte ausgeben lassen
---- für die Objekte die einzelnen Methoden aufrufen




PHP/OOP_7-2: Vererbung im UML-Diagramm darstellen und programmieren

Sie verwalten in einem Programm die Mitarbeiter einer Firma. Alle Mitarbeiter haben einen Vornamen und einen Nachnamen und eine Personalnummer. Allen Mitarbeiter wird ein Gehalt ausgezahlt (zahleGehalt(gehalt)).
Die Mitarbeiter im Außendienst können außerdem einen Dienstwagen benutzen (leiheDienstwagen()). Man kann weiterhin abfragen, wie viele Außenkontakte sie hatten (getAussenkontakte()) - natürlich muss die Anzahl der Außenkontakte auch in einem Attribut gespeichert werden.
Die Mitarbeiter in der Managementetage bekommen einmal jährlich einen Bonus ausgezahlt (zahleBonus(bonus)). Außerdem können Sie die Personalnummer aller anderen Mitarbeiter herausfinden (durch Eingabe des Nachnamens (holePersonalnummer(nachname)). Die EDV ist noch nicht so ausgereift, deshalb wird als Antwort auf diese Aktion immer "Mitarbeiter nicht verfügbar" ausgegeben.
Die Mitarbeiter in der Lagerverwaltung haben keine besonderen Merkmale, die sie von anderen Mitarbeitern unterscheiden.

a)
Erstellen Sie ein UML-Diagramm zu dieser Situation.

b)
Programmieren Sie die Klassen. Testen Sie die Lauffähigkeit, indem Sie einige Mitarbeiter als Objekte instanziieren und die Methoden ausprobieren.




PHP/OOP_7-3: Vererbung programmieren - Pizzabringdienst

Sie programmieren entsprechend 10phpoop/oopphp07-bild-pizza.png ein Bestellsystem für einen Pizzabringdienst. Name (setName), Preis (setPreis) und Rabatt (setRabatt) werden vom System gesetzt; der Einfachheit halber machen Sie das von Hand (indem Sie an der korrekten Stelle die entsprechenden Setter mit beispielhaften Werten verwenden).
Saucentyp und Schärfegrad werden vom User gesetzt. Auch das machen Sie von Hand.
Probieren Sie aus, ob die Klassen so arbeiten wie erwartet. Versuchen Sie auch auf ein Objekt der Unterklassen die in der Oberklasse definierten Methoden anzuwenden.

Zusatzaufgabe a:
Erstellen Sie ein Formular, mit dem die Bestellung vorgenommen wird (sie werden dabei einige Vereinfachungen vornehmen müssen, z.B. dass es nur ein Produkt gibt oder- falls es mehrere gibt - dass die Produkte in einem Array mit Initialwert gespeichert sind).

Zusatzaufgabe b:
Erzeugen Sie eine Datenbanktabelle, in der die Pizzas inklusive Preis etc. gespeichert sind. Auf diese Tabelle wird bei Ausführen eines Bestellvorgangs zugegriffen.




PHP/OOP_7-4: Vererbung mit DB-Anbindung

Erweitern Sie Ihr Programm aus 7-3 so, dass bei der Instanziierung eines Mitarbeiters seine Daten aus einer DB geholt werden (Konstruktor!). Erweitern Sie auch das Klassendiagramm entsprechend!
Testen Sie die Funktionsweise, indem Sie einen Manager instanziieren und die Methode holePersonalnummer verwenden. Den Namen des Mitarbeiters geben Sie (wie in 7-2)  direkt im Programmcode in die Methode ein, also bspw.

PHP-Code
$manager1 = new Manager;   $name = 'huber'; $personalnummer = $manager1->getPersonalnummer($name); echo "<p>Mitarbeiter " . $name . " hat Personalnummer " . $personalnummer . "</p>\n";  

Beachten Sie, dass es grundsätzlich verschiedene Möglichkeiten gibt, dieses Problem zu realisieren.
Benutzen Sie den folgenden Tabellen-Code für die DB. Eine Klasse für die DB-Verbindung sollten Sie noch aus Aufgabe 6-2 haben.

Tabelle:

MySQL-Code
CREATE TABLE `mitarbeiter` ( `id` INT NOT NULL , `nachname` VARCHAR(45) NULL , `personalnummer` INT NULL , PRIMARY KEY (`id`) ); INSERT INTO `mitarbeiter` (`id`, `nachname`, `personalnummer`) VALUES ('1', 'huber', '17312214'); INSERT INTO `mitarbeiter` (`id`, `nachname`, `personalnummer`) VALUES ('2', 'maier', '31553212'); INSERT INTO `mitarbeiter` (`id`, `nachname`, `personalnummer`) VALUES ('3', 'zuckerberg', '48818828');  




PHP/OOP_7-5: Vererbung mit DB-Anbindung und Eingabemaske

Erweitern Sie Ihr Programm von 7-4 so, dass der Manager den Nachnamen des Mitarbeiters in ein Eingabefeld eingeben kann und dann die zugehörige Personalnummer bekommt.




PHP/OOP_7-6: Vererbungsaufgabe, Zusammenfassung (einfach)

- Programmieren Sie die Klassen "Logistikverwaltung" und "Paketverfolgung" wie im Klassendiagramm 10phpoop/oopphp07_bild_logistik-klasse.png gezeigt. Programmieren Sie die Getter und Setter von Hand!
- Erzeugen Sie zwei neue Objekte $paketverfolgung1 und $paketverfolgung2 der Klasse Paketverfolgung.
- Setzen Sie für die beiden Objekte zwei unterschiedliche Verfolgungsnummern, indem Sie den Setter benutzen.
- Lassen Sie sich die beiden Verfolgungsnummern ausgeben, indem Sie den Getter benutzen.

[Je nach Ihrem Kenntnisstand entscheiden Sie sich für eine der folgenden drei Aufgaben:]
- Formular SEHR EINFACH: Erzeugen Sie eine Oberfläche, über die durch Eingabe einer Transportnummer und die Eingabe einer Verfolgungsnummer ein neuer Transportvorgang "Paketverfolgung" angelegt werden kann. (Dazu müssen Sie eine zusätzliche Methode programmieren!) Durch das Absenden des Formulars wird ein neues Objekt der Klasse Paketverfolgung erzeugt, die entsprechenden Werte zugewiesen und zur Überprüfung ausgegeben ("Die Transportnummer des neu erzeugten Objekts beträgt 122, die Verfolgungsnummer ist 184.").
- Formular EINFACH:  Erweitern Sie die Unterklasse "Paketverfolgung" so, dass über den Konstruktor jedem neuen Objekt eine zufällige Paketverfolgungsnummer zugewiesen wird (php-Funktion rand(minwert, maxwert), bsp.: $zufallszahl = rand(1,100) erzeugt eine Zufallszahl zwischen 1 und 100).
Erzeugen Sie eine Oberfläche, über die durch Eingabe einer Transportnummer ein neuer Transportvorgang "Paketverfolgung" angelegt werden kann. Lassen Sie sich nach dem Absenden des Formulars die Transportnummer und die Paketverfolgungsnummer ausgeben.
- Formular MITTELSCHWIERIG: Gehen Sie wie in Aufgabe EINFACH vor mit dem Unterschied, dass bei Anlegen eines neuen Transportvorgangs der neue Transportvorgang in eine DB geschrieben wird.
- FORMULAR SCHWIERIG: Erzeugen Sie zwei Formulare:
--- Anlegen eines neuen Transportvorgangs (wie in Aufgabe MITTELSCHWIERIG)
--- Abfragen einer Paketverfolgungsnummer (durch Eingabe der Transportnummer)
Alle Daten werden aus der DB geholt bzw. in die DB geschrieben.