Objektorientierung in PHP
Objektorientierung mit PHP
PHP kennt viele OO-Prinzipien
- Klassen und Objekte
- statische und nicht-statische Attribute und Methoden
- abstrakte Klassen und Methoden
- Konstruktoren und Destruktoren
- Einfachvererbung
- Überschreiben von Methoden
- Interfaces
- Einschränkung der Sichtbarkeit mit public, protected, private
- Namensräume (ähnlich Java Packages)
- Ausnahmen/Exceptions
Grenzen der Objektorientierung
- kein Überladen von Methoden
- Großteil der Bibliotheken ist immer noch prozedural, insbesondere Arrays
- In der Praxis immer Mischbetrieb von prozedural und objektorientiert
Definition einer Klasse
- PHP-Klassen sind immer public
- Üblich ist eine Quellcode-Datei pro Klasse
- Syntax:
class CLASSNAME { } - Ableiten mit dem Schlüsselwort
extends
class Mitarbeiter {
public $name;
public $geboren;
}
class Manager extends Mitarbeiter {
public $abteilung;
}
Klasse mit Typangaben
Neuere PHP-Versionen erlauben es, die Typen anzugeben von
- Attributen
- Parametern
- Rückgabewerten
class Mitarbeiter {
public string $name;
public DateTime $geboren;
}
class Manager extends Mitarbeiter {
public string $abteilung;
}
Instanz- und Klassenvariablen
- Instanzvariablen haben den Modifier public, protected, private
- Klassenvariablen haben den Modifier static
- Variablen können bei der Definition initialisiert werden
class Tier {
protected string $name; // nicht initialisiert
public int $alter = 1; // Variable vorbelegt
// statische Variable
public static int $instanzen = 0;
}
Zugriff auf Instanzvariablen
- Instanzvariablen anderer Objekte
$referenz->attributname - Klassenvariable der eigenen Klasse
self::$variablenname - Klassenvariablen fremder Klassen
Klassenname::$variablenname
function setName(string $name) {
$this->name = $name;
}
$t = new Tier();
$t->alter = 14;
echo Tier::$instanzen;
Zugriffsbeschränkung
Attribute und Methoden können einen Modifier haben
public: jeder darf zugreifenprotected: eigene und abgeleitete Klassen darf zugreifenprivate: nur die eigene Klasse darf zugreifen
Klassenkonstanten
Klassenkonstanten
- innerhalb einer Klasse mit Schlüsselwort
constdefiniert - grundsätzlich
public - kein
$im Namen - kein Datentyp, wird automatisch abgeleitet
- Zugriff mit
Klassenname::Konstantenname
class Math {
const PI = 3.14159265;
public static function kreisflaeche(float $radius) {
return Math::PI*$radius*$radius;
}
}
(Nichtstatische) Methoden
Innerhalb einer Klasse definierte Funktionen
- mit Schlüsselwort
functiongekennzeichnet - nur über ein Objekt der Klasse aufrufbar
- kein Überladen, lediglich Überschreiben möglich
- optionale Datentypen für Parameter und Rückgabewert
- überflüssige Parameter werden kommentarlos ignoriert
Statische Methoden
Statische Methoden
- gekennzeichnet durch das Schlüsselwort
static - dürfen
$this-Referenz nicht verwenden - dürfen nur statische Attribute der Klasse nutzen
- dürfen nur statische Methoden aufrufen
Konstruktor
Konstruktor heißt in PHP __construct()
- kann beliebige Parameter (auch mit Default) haben
- kann nicht überladen werden (nur ein Konstruktor pro Klasse)
- wird (im Gegensatz zu Java) vererbt, es sei denn, es gibt in der Kindklasse einen Konstruktor
- wird implizit bei
newaufgerufen - kann auch explizit aufgerufen werden
- Konstruktor der Elternklasse wird nicht automatisch gerufen, kann aber explizit mit
parent::__construct()gerufen werden
Beispiel: Konstruktor
class Mitarbeiter {
public string $name;
public DateTime $geboren;
function __construct(string $name = "",
DateTime $geboren = new DateTime("1.1.1970")) {
$this->name = $name;
$this->geboren = $geboren;
}
}
$m = new Mitarbeiter("Peter");
echo $m->name; // -> Peter
echo $m->geboren->format('d.m.Y'); // -> 1.1.1970
Kopieren von Objekten
Objekte können mit clone kopiert werden
- ruft implizit die
__clone()-Methode auf __clone()-Methode kann überschrieben werden
$a = new Mitarbeiter("Petra Mustermann");
$b = $a;
$a->name ="Petra Suhrbier";
echo $a->name; // -> Petra Suhrbier
echo $b->name; // -> Petra Suhrbier
$c = new Mitarbeiter("Franz Meier");
$d = clone $c;
$c->name ="Franz Suhrbier";
echo $c->name; // -> Franz Suhrbier
echo $d->name; // -> Franz Meier
toString()-Methode
Methode __toString()
- wird bei Ausgabe eines Objektes mit
echoaufgerufen - bestimmt, welche Attribute einer Klasse ausgegeben werden
- wenn Methode nicht definiert ist, gibt es eine Fehlermeldung
class Mitarbeiter {
public string $name;
public DateTime $geboren;
function __construct(string $name = "", DateTime $geboren) { ... }
function __toString() {
return "Name: $this->name, geboren: " . $this->geboren->format('d.m.Y');
}
}
$ma = new Mitarbeiter("Markus Peter", new DateTime("13.7.1984"));
echo $ma; // -> Name: Markus Peter, geboren: 13.7.1984
class Mitarbeiter {
public string $name;
public DateTime $geboren;
function __construct(string $name = "", DateTime $geboren = new DateTime("1.1.1970")) {
$this->name = $name;
$this->geboren = $geboren;
}
function __toString() {
return "Name: $this->name, geboren: " . $this->geboren->format('d.m.Y');
}
}
$ma = new Mitarbeiter("Markus Peter", new DateTime("13.7.1984"));
echo $ma; // -> Name: Markus Peter, geboren: 13.7.1984
Destruktor
Klassen können einen Destruktor angeben
__destruct()-Methode enthält den Code des Destruktors- parameterlos
- wird aufgerufen, wenn letzte Referenz auf das Objekt wegfällt
- nach dem Destruktor-Aufruf wird das Objekt gelöscht
- PHP hat keinen Garbage-Collector, sondern betreibt Reference-Counting
- Destruktor der Elternklasse wird nicht automatisch gerufen, kann aber explizit mit
parent::__destruct()gerufen werden
Beispiel: Destruktor
class KillMe {
function __destruct() {
echo "Wurde vernichtet";
}
}
$k = new KillMe();
$l = $k;
echo "Noch lebt es";
$k = null;
echo "Noch lebt es";
$l = null;
Noch lebt es
Noch lebt es
Wurde vernichtet
Überschreiben von Methoden
- Gleichnamige Methode in abgeleiteter Klasse überschreibt (d. h. ersetzt) Methode der Basisklasse
- Überschriebene Methode der Elternklasse kann mit
parent::methode()aufgerufen werden - Polymorphie braucht man in PHP nicht, da Referenzvariablen keinen Typ haben
- Methoden werden immer virtuell aufgerufen
Beispiel: Überschreiben
class A {
function methode() {
echo "A";
}
}
class B extends A {
function methode() {
parent::methode();
echo "B";
}
}
$a = new A(); $a->methode(); // -> A
$b = new B(); $b->methode(); // -> AB
Abstrakte Methoden und Klassen
Abstrakte Methoden
- haben keine Rumpf
- legen nur die Signatur fest
- werden mit
abstractgekennzeichnet - müssen von der abgeleiteten Klasse implementiert werden
Abstrakte Klassen
- haben mindestens eine abstrakte Methode
- können nicht instanziert werden
- werden mit
abstractgekennzeichnet
Beispiel: Abstrakte Methoden
abstract class A {
public function konkret() {
echo "Ich bin konkret";
}
public abstract function abstrakt();
}
class B extends A {
public function abstrakt() {
echo "Jetzt bin ich auch konkret";
}
}
$b = new B();
$b->abstrakt(); // -> Jetzt bin ich auch konkret
$a = new A(); // Fehler!
instanceof-Operator
Mit instanceof kann man prüfen ob ein Objekt
- von der angegebenen Klassen oder
- von einer Subklasse dieser Klasse ist
class A {}
class B extends A {}
$a = new A();
$b = new B();
echo $a instanceof A; // -> true (1)
echo $a instanceof B; // -> false ()
echo $b instanceof A; // -> true (1)
echo $b instanceof B; // -> true (1)
Interfaces
Interfaces
- werden mit dem Schlüsselwort
interfaceeingeleitet - definieren Methoden-Signaturen ohne Implementierung
- können nicht instanziert werden
Methoden in Interfaces
- sind immer implizit
public - dürfen nicht
protectedoderprivatesein - dürfen keine Implementierungen enthalten
Implementierung von Interfaces
Eine PHP-Klasse
- darf beliebig viele Interfaces implementieren (
implements) - darf von genau einer anderen Klasse erben
- implementiert alle Methoden des Interfaces und wird konkret
- implementiert nicht alle Methoden und wird dadurch abstrakt
Beispiel: Interfaces
interface Flieger {
function fliegen();
}
class Ente implements Flieger {
function fliegen() { /* fliegen */ }
}
abstract class Superheld implements Flieger {
function weltRetten() { }
}
class Superman extends Superheld {
function fliegen() { /* fliegen */ }
}
$s = new Superman();
echo $s instanceof Flieger; // -> true (1)
echo $s instanceof Superheld; // -> true (1)
Namensräume
Namensräume (namespaces)
- stellen einen Prefix vor
- Klassen- und Interfacenamen
- Globale Funktions- und Konstantennamen
- verhindern Namenskollisionen (name clashes)
- sind ähnlich zu Java-Paketen (packages)
- sind hierarchisch aufgebaut mit Backslash (
\) als Trennzeichen
Namensraum definieren
- Namensraum wird mit dem Schlüsselwort
namespacedefiniert - Trennung von Ebenen erfolgt duch \
- Namespace-Statement muss als erstes in der Datei stehen
- keine anderen Statements vor der Deklaration
- kein HTML vor der Deklaration
<?php
namespace de\smits\web;
class A {
function f() {
echo "Hallo";
}
}
?>
Mehrere Namensräume in einer Datei
Es können auch mehrere Namensräume in einer Datei deklariert werden
namespace { // globaler Namespace
const PI = 3.14159265;
}
namespace de\smits\web {
class A {
function f() {
echo PI;
}
}
$a = new A();
$a->f();
}
Namensraum nutzen
Drei Möglichkeiten Namespaces zu nutzen
- Verwendung des Prefix vor allen Namen
- Importieren eines ganzen Namensraums mit
use - Klassen und Interfaces können dann ohne Prefix genutzt werden
- Funktionen behalten letzten Teil des Namensraums als Prefix
- Importieren einzelner Klassen oder Interfaces mit
use - Klassen und Interfaces können ohne Prefix genutzt werden
- Es kann beim Import ein Alias vergeben werden
Beispiel: Namensraum
namespace de\smits\web {
class A { }
function f() { return "web"; }
}
namespace de\smits\pr3 {
class A { }
function f() { return "pr3"; }
}
namespace de\smits {
// Zugriff über Unter-Namespace
echo pr3\f(); // -> pr3
echo web\f(); // -> web
// Zugriff über den vollen Namen
echo \de\smits\pr3\f(); // -> pr3
echo \de\smits\web\f(); // -> web
}
namespace {
// Zugriff über den vollen Namen
echo de\smits\pr3\f(); // -> pr3
echo de\smits\web\f(); // -> web
use de\smits\pr3; // namespace importieren
use de\smits\web; // namespace importieren
echo pr3\f(); // -> pr3
echo web\f(); // -> web
$a = new pr3\A();
use de\smits\web\A; // Klasse importieren
$a = new A();
use de\smits\web\A as X; // Klasse mit Alias importieren
$a = new X();
}