[Tutorial] Einblick in die OoP - Teil 2

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • [Tutorial] Einblick in die OoP - Teil 2

      Moin moin.

      Hiermit veröffentliche ich mal den zweiten Teil über die Objektorientierte Programmierung in PHP.
      In diesem Beitrag wollen wir uns mit Vererbung von Objekten beschäftigen.
      Ihr solltet diesen Beitrag gelesen haben - habt ihr das nicht getan, dann solltet ihr den ersten Teil zuerst lesen und verstehen.

      Inhalt
      1. Grundlegendes
      1.1 Der Unterschied zwischen private und protected
      1.2 Das Schlüsselwort "final"
      1.3 Objekte Klonen
      2. Die Vererbung
      2.1 Methoden vererben
      2.2 Nachtrag zum Variablenzugriff
      3 Vor- und Nachteile von Vererbung

      1. Grundlegendes

      Wichtig bei Vererbung ist, dass man durch die objektorientierte Vererbung KEINE Werte direkt vererben kann, sondern nur Variablen und/oder Funktionen.

      1.1 Der Unterschied zwischen private und protected

      Eine Methode oder ein Attribut die als private deklariert ist, darf nur innerhalb der Klasse genutzt werden. Eine Veränderung eines Attributes oder Aufrufen einer Methode von außen ist nicht möglich. Man kann einer Methode auch private voran stellen (z.B. private getName() { ... } ), dann ist der Zugriff außerhalb des Objektes nicht möglich.
      Wenn jetzt also sogenannte "Kindklassen" Variablen und/oder Methoden erben sollen, müssen diese mit dem Schlüsselwort "protected" markiert werden.

      1.2 Das Schlüsselwort final

      Das Schlüsselwort "final" ist dafür gut, um Kindklassen davon abzuhalten, Methoden der Elternklasse zu überschreiben. Dazu stellt man der Definition einfach "final" (in der Elternklasse, nicht in der Kindklasse!) voran. Wird eine Klasse als final definiert, kann sie nicht erweitert werden.

      1.3 Objekte Klonen

      Hier gehe ich kurz darauf ein, dass man erzeugte Objekte auch einfach klonen kann.
      Nehmen wir an Dieters Fiffi namens Waldi hat das Zeitliche gesegnet. Und weil der die Frauen wie ein Magnet anzog, hat Dieter den Wuffi mal schnell geklont. Dies geschieht mit dem Schlüsselwort "clone".

      PHP-Quellcode

      1. $waldi = new Hund();
      2. $klon = clone $waldi;


      2. Die Vererbung


      Die eigentliche Vererbung fängt schon beim Klassennamen an. Hier muss man das Schlüsselwort "extends" (zu Deutsch: hängt ab von / wird abgeleitet von) und die Klasse angeben, wovon man die Klasse abhängig macht.
      Außerdem gibt es noch das Schlüsselwort "parent", womit die Vererbung von Methoden passiert.

      2.1 Methoden vererben

      Als Vorwort hierzu stellen wir uns Autos vor. Man könnte jetzt für jede Automarke (wir nehmen hier als Beispiel Audi, Mercedes und Opel) eine eigene Klasse machen. Hier wird man aber schnell merken, dass es nicht so viel Sinn macht, jede set- und get-Methode 3 mal zu schreiben - abgesehen von den Variablen, die mehrfach deklariert werden müssen. Hier kommt das Thema Vererbung ins Spiel.
      Wir bauen uns eine Klasse, das "Grundgerüst" und leiten andere Klassen dann davon ab.

      PHP-Quellcode

      1. class auto {
      2. protected $tireCount = 4;
      3. protected $speed = 0;
      4. public function setSpeed($newSpeed) {
      5. $this->speed = $newSpeed;
      6. }
      7. public function getSpeed() {
      8. return $this->speed;
      9. }
      10. }
      11. class audi extends auto {
      12. protected $engine = "150 PS";
      13. }
      14. class mercedes extends auto {
      15. protected $engine = "200 PS";
      16. }
      17. class opel extends auto {
      18. protected $engine = "180 PS";
      19. }
      Alles anzeigen
      Ich habe hier die Klasse "auto" als das Grundgerüst geschrieben. Man hat 4 Räder, Geschwindigkeit ist standard 0 und dann sind dort noch die Funktionen setSpeed und getSpeed.

      Wie man hier sehen kann, gibt es eine Klasse namens "auto", die im Zusammenhang mit dem Schlüsselwort "extends" steht.
      Da wir uns jetzt eben nicht die Arbeit machen wollen, den ganzen source code zu kopieren und alles 3 mal zu haben, sagen wir den Klasse "audi", "mercedes" und "opel" einfach "extends auto" - "audi extends auto" also: audi wird abgeleitet von auto.
      Wenn die Kindklasse keinen Konstruktor hat, wird automatisch der der Elternklasse ausgeführt. Ansonsten muss man diesen explizit verwenden.

      Jetzt haben wir also 3 Automarken erzeugt, die 150, 200 und 180 PS haben, 4 Räder haben und alle die Methoden setSpeed und getSpeed verwenden können, ohne, dass diese in jeder Klasse vorhanden sind.


      Mit dem Schlüsselwort "parent" kann man auf Methoden der Elternklasse zugreifen.
      Was ist aber, wenn die Elternklasse gar nicht die Methode hat, die man haben möchte - sondern nur die Großelternklasse diese besitzt? Dafür benutzt man anstatt

      PHP-Quellcode

      1. parent::methodenName(argumente)
      einfach

      PHP-Quellcode

      1. nameDerKlasseImVererbungskontext::methodenName(argumente)
      Man könnte also in diesem Falle anstatt "parent" auch einfach "auto" verwenden - dies hätte zwar den gleichen Effekt, ist aber nicht korrekt, da wir uns außerhalb des eigentlichen Objektkontextes bewegen.

      Hierzu nochmal ein besseres Beispiel:

      PHP-Quellcode

      1. class viereck {
      2. function calcUmfang() {
      3. return 2*($this->a+$this->b);
      4. }
      5. function calcFlaeche() {
      6. return $this->a*$this->b;
      7. }
      8. }
      9. class rechteck extends viereck {
      10. protected $a = 2;
      11. protected $b = 3;
      12. }
      13. class quadrat extends viereck {
      14. protected $a = 2;
      15. protected $b = 2;
      16. public function calcUmfang() {
      17. $umfang = parent::calcUmfang();
      18. return $umfang.'<br />'.$this->a*$this->a;
      19. }
      20. }
      21. $rechteck = new rechteck();
      22. echo $rechteck->calcUmfang().'<br />';
      23. echo $rechteck->calcFlaeche();
      24. echo '<br /><br />';
      25. $quadrat = new quadrat();
      26. echo $quadrat->calcUmfang().'<br />';
      Alles anzeigen
      Eine simple Rechnung: Wir machen uns ein Rechteck und ein Quadrat, was von "Viereck" abgeleitet wird.
      Für die Klasse Rechteck werden einfach die Elternfunktionen aufgerufen.
      Bei der Klasse "Quadrat" habe ich es allerdings zum Verständnis etwas anders gemacht:

      PHP-Quellcode

      1. class quadrat extends viereck {
      2. protected $a = 2;
      3. protected $b = 2;
      4. public function calcUmfang() {
      5. $umfang = parent::calcUmfang();
      6. return $umfang.'<br />'.$this->a*$this->a;
      7. }
      8. }
      Da ich dieses mal beide Sachen in einer Funktion berechnen will und den Quellcode von "viereck" nicht kopieren will, überschreibe ich die Funktion calcUmfang().
      Damit ihr seht, wie das mit der Vererbung funktioniert, habe ich das Schlüsselwort "parent" mit eingebaut.
      Man greift mit "parent::calcUmfang()" auf die Methode "calcUmfang" der Elternklasse (hier "viereck") zu. Somit wird die Funktion calcUmfang der Elternklasse ausgeführt und man kann in dieser Klasse die Methode calcUmfang erweitern (hat keinen Einfluss auf andere Klassen, die neu von "viereck" abgeleitet werden). Damit die Fläche berechnet wird, kommt noch das return Statement hinzu. Es wird also Umfang (vorher berechnet und gespeichert) und danach die Fläche ausgegeben.

      2.2 Nachtrag zum Variablenzugriff
      Als Nachtrag zum Variablenzugriff möchte ich hier noch etwas anbringen.
      Hier ist die Klasse "auto" etwas erweitert:

      PHP-Quellcode

      1. class auto {
      2. protected $tireCount = 4;
      3. protected $speed = 0;
      4. protected $seatCount = 5;
      5. public function setSpeed($newSpeed) {
      6. $this->speed = $newSpeed;
      7. }
      8. public function getSpeed() {
      9. return $this->speed;
      10. }
      11. public function getSeatCount() {
      12. return $this->seatCount;
      13. }
      14. }
      Alles anzeigen
      Jetzt hat jedes Auto standardmäßig 5 Sitze. Da mein Opel aber ein Familienwagen ist, der 8 Sitze hat, hat man in der Vererbung auch die Möglichkeit, Variablen zu überladen. Das geschieht dann so:

      PHP-Quellcode

      1. class opel extends auto {
      2. protected $engine = "180 PS";
      3. protected $seatCount = 8;
      4. }
      Wichtig dabei ist aber, dass dies nur $seatCount von Opel überschreibt und nicht von der Elternklasse "auto". Nur der Opel hat 8 Sitze.
      Objekte, die davor erzeugt wurden und danach erzeugt werden, haben wieder 5 Sitze (wegen des Grundgerüsts).

      3 Vor- und Nachteile von Vererbung
      Vorteile
      -Wiederverwendbarkeit
      -Keine Duplizierung von Quellcode mehr nötig
      -Fehlerkorrekturen einer Oberklasse wirken sich direkt und ohne Nacharbeiten auf die Unterklassen aus.

      Nachteile
      -Änderungen an der Wurzel einer Vererbungshierarchie beeinflussen alle erbenden Klassen - im schlimmsten Fall bewirkt eine Methode dann etwas ganz anderes
      -In Java können Speicherleaks durch Subobjekte entstehen, wenn diese nicht richtig freigegeben werden


      Das wars soweit von meiner Seite.
      Verbesserungsvorschläge, Fehlermeldungen und Feedback ist gern gesehen :-)

      Credits:
      -Schreiben des Tuts: 95% Leecher
      -Fürs anlesen diverser Dinge: 5% php.net

      ~Leecher
    • Werbung zur Unterstützung des Forums ( Bitte AddBlocker deaktivieren )

    • -Eine Unterklasse kann nicht auf Werte einer Oberklasse zugreifen

      Wie kommst du denn da drauf?

      Quellcode

      1. php > class Blubb { protected $a = 'Hello World'; }
      2. php > class Blobb extends Blubb { public function Blobb() { echo $this->a; }}
      3. php > new Blobb();
      4. Hello World


      Generell machen sämtliche Beispiele keinen Sinn. Du überschreibst Attribute (ich wusste noch gar nicht, dass das geht *g*) ... Du überschreibst Methoden, nur um in ihr die überschriebene Methode mit den genau gleichen Parametern aufzurufen.

      Folgendes Beispiel ...

      Quellcode

      1. class mann extends mensch {
      2. protected $name;
      3. protected $gender;
      4. protected $age;
      5. protected $size;
      6. protected $weight;
      7. function __construct($name) {
      8. parent::__construct($name);
      9. }
      10. function setData ($gender, $age, $size, $weight) {
      11. parent::setData ($gender, $age, $size, $weight);
      12. }
      13. function getName() {
      14. return $this->name;
      15. }
      16. }
      Alles anzeigen

      ... hätte in dieser Form genau den gleichen Effekt ...

      Quellcode

      1. class mann extends mensch {
      2. function getName() {
      3. return $this->name;
      4. }
      5. }

      (Denn der Rest ist in der Klasse mensch() schon vorhanden. Da mann diese, wie du selber schon sagst, erweitert, sind sämtliche Methoden und Attribute natürlich auch bei ihr vorhanden (denn sie sind ja als protected bzw. public deklariert))

      Ich bezweifle irgendwie, dass du das Thema selber verstanden hast ...

      (und auch ansonsten deckt das Tutorial das Thema nur rudimentär ab ...)
    • Das scheint wohl doch alles ein bisschen lange her zu sein, dass ich das mal gemacht habe ...

      Wenn ich deine Anmerkungen so lese, fällt mir direkt wieder ein, was da schief gelaufen ist - danke dafür! Ich habe da die Reihenfolge beim Vereben völlig verdreht.

      So, Beitrag ist nachbearbeitet.