17.04.17 1 Webtechnologien – SS 2017 - Teil 7/PHP II Webtechnologien Teil 7: PHP – Klassen und Objekte
17.04.17 1Webtechnologien – SS 2017 - Teil 7/PHP II
Webtechnologien
Teil 7: PHP – Klassen und Objekte
2Webtechnologien – SS 2017 - Teil 7/PHP II
Literatur
[7-1] Trachtenberg, Adam: Umsteigen auf PHP 5. O'Reilly, 2005
[7-2] Theis, Thomas: PHP 5.6 und MySQL 5.6.
10. Auflage, Gallileo Computing, 2014
[7-3] Lerdorf, Rasmus; Bergmann, Sebastian; Hicking, Garvin: PHP kurz&gut. O'Reilly, 3. Auflage, 2006
[7-4] Schmidt, Stefan: PHP Design Patterns. O'Reilly, 2006
[7-5] Sklar, David; Trachtenberg, Adam: PHP5 Kochbuch. O'Reilly, 2. Auflage, 2005
3Webtechnologien – SS 2017 - Teil 7/PHP II
Übersicht
• Objekte und Klassen
• Magische Methoden
• Magische Konstanten
• Schnittstellenabstraktion
• Wrapper-Klassen
• Factory-Klassen
4Webtechnologien – SS 2017 - Teil 7/PHP II
Klassen I
• Die Variablen realisieren die Attribute der Klasse.
• Auf diese wird innerhalb der Klasse mit "$this->Attribute" zugegriffen, von außerhalb normalerweise mit "$Object->Attribute".
• Die Funktionen bilden die Methoden. Auf sie wird analog zu den Attributen zugegriffen: "$Object->Methode()" bzw. mit "$this->Methode()".
• Ohne den Vorspann mit $this ist in PHP kein Zugriff auf Attribute und Methoden möglich.
• Als Modifier ist möglich: abstractDeren Bedeutung ist dieselbe wie in Java.
• Als Inheritance sind möglich: extends und implementsDeren Bedeutung ist dieselbe wie in Java.
[abstract] class Name [Inheritance] { [Variablen-Deklarationen] [Funktion-Deklarationen]}
5Webtechnologien – SS 2017 - Teil 7/PHP II
Klassen II - Variablendeklarationen
• Als Modifier sind möglich: private, protected und publicDeren Bedeutung ist dieselbe wie in Java.
• Die Benutzung des Schlüsselwortes var als Modifier ist veraltet und entspricht public.Wenn Sie also ein Attribut explizit deklarieren wollen – was zu empfehlen ist -, dann benutzen Sie eine der drei oben genannten Modifier.
[Modifier] [static] Name[= Wert];
6Webtechnologien – SS 2017 - Teil 7/PHP II
Klassen III - Funktionsdeklarationen
• Als Modifier sind möglich: private, protected und publicDeren Bedeutung ist dieselbe wie in Java.
• Für Name gibt es auch Namen mit festgelegter Bedeutung, die alle mit "__" (Zwei Unterstrichen) beginnen, z.B.:
__construct()
__destruct()
• Ab PHP 7 sind auch hier Type Hints für die Parameter sowie für das Resultat möglich: nach einem declare am Anfang der Datei.
[Modifier] [static] function Name($arg1,$arg2,…,$argN) { .... [return Expr;]}
7Webtechnologien – SS 2017 - Teil 7/PHP II
Modifier von Funktionen und Attributen
Modifier Erläuterung
public Darf von überall her zugegriffen werden
protected Darf nur aus einer Methode innerhalb der Vererbungshierarchie her zugegriffen werden
private Darf nur innerhalb derselben Klasse zugegriffen werden
Default ist public.
8Webtechnologien – SS 2017 - Teil 7/PHP II
Beispiel
class Auto { public $Hersteller; public $Typ; public $Farbe;
function Ausgabe() { echo "$this->Hersteller $this->Typ $this->Farbe"; } function NeueFarbe($FarbeNeu) { $this->Farbe= $FarbeNeu; }}
Es muss "$this->" beim Zugriff von Innen benutzt werden,da ansonsten eine lokale Variable in der Funktion eingerichtet wird.
Dieses Deklarieren ist scheinbarunnötig – machen Sie es trotzdem.
9Webtechnologien – SS 2017 - Teil 7/PHP II
Erzeugen von Instanzen/Objekten I
• Beim Zugriff auf Attribute wird kein "$" vor das Attribut, sondern vor die ganze Konstruktion geschrieben.
• Leider ist folgendes auch möglich:
$Objektname= new Klassenname();
$a= new Auto();$a->Hersteller= "VW";$a->Typ= "Käfer";$a->Farbe= "rosa";$a->Ausgabe();$a->NeueFarbe("schweinchenrosa");
$Attribute= "Hersteller";$a->$Attribute= "VW";
10Webtechnologien – SS 2017 - Teil 7/PHP II
Erzeugen von Instanzen/Objekten II
• Die Routine __autoload() wird außerhalb von Klassen definiert und realisiert einen Klassenlader.
• __autoload() wird bei einer new()-Operation einer nicht definierten Klasse, auch statische aufgerufen.
• Die zu ladenden Dateien müssen im Include-Pfad liegen(Parameter include_path in php.ini).
• Bitte beachten Sie, dass es keinen Linker/Binder gibt, d.h. alles, was zum Skript gehört, muss explizit geladen werden.
• Es gibt noch einen anderen, weit leistungsfähigeren Mechanismus, der hier nicht besprochen wird, siehehttp://php.net/manual/de/language.oop5.autoload.php
function __autoload($Klasse) { include("$Klasse.php");}
Diese Möglichkeit wirdab PHP 7.2 als veraltetgekennzeichnet.
11Webtechnologien – SS 2017 - Teil 7/PHP II
Leider....
• Nach dem Erzeugen eines Objektes lassen sich auch dynamisch neue Attribute durch Zuweisung in das bestehende Objekt integrieren.
Beispiel 1:$b= new Auto();$b->Hersteller= "Ford";$b->Ausgabe;
Beispiel 2:$b= new Auto();$b->Hersteller= "Ford";$b->Ausgabe();
• Im Beispiel 1 wird die neue Eigenschaft "Ausgabe" als public erzeugt.
• Im Beispiel 2 wird dagegen die Methode Ausgabe aufgerufen.
• Es wird im Beispiel 1 nicht unbedingt eine Fehlermeldung ausgegeben!
12Webtechnologien – SS 2017 - Teil 7/PHP II
Klassen "außerhalb" definiert
include_once("auto.class.php"); // Laden der Klasse
$Kfz= new Auto();$Kfz->Hersteller= "Mercedes";$Kfz->Typ= "Elchklasse";$Kfz->NeueFarbe("lila");
class Auto { public $Hersteller; public $Typ; public $Farbe; function Ausgabe() { echo "$this->Hersteller $this->Typ $this->Farbe"; } function NeueFarbe($FarbeNeu) { $this->Farbe= $FarbeNeu; }}
Datei auto.class.php
13Webtechnologien – SS 2017 - Teil 7/PHP II
Konstruktor I
• Konstruktor = Funktion mit dem festgelegten Namen __construct()
• Diese Funktion wird implizit beim new() aufgerufen.
• So wie in Java werden die Parameter von new() nach __construct() weiter gereicht.
class Auto { public $Hersteller; public $Typ; public $Farbe; function Ausgabe() { echo "$this->Hersteller $this->Typ $this->Farbe"; } function __construct($Hersteller, $Typ, $Farbe) { $this->Hersteller= $Hersteller; $this->Typ= $Typ; $this->Farbe= $Farbe; }}
14Webtechnologien – SS 2017 - Teil 7/PHP II
Konstruktor II
$a= new Auto("VW","Käfer","rosa");
$a->Ausgabe();$a->NeueFarbe("schweinchenrosa");
Es gibt in PHP kein Überladen von Funktionen/Methoden, d.h.es gibt immer nur einen Konstruktor, der mit beliebigen Parameternaufgerufen werden kann.
Also: Den Mechanismus in Java, dass mehrere Konstruktoren/Methoden mitunterschiedlichen Parametern unterschieden werden, gibt es in PHP nicht .
Es gibt aber die Möglichkeit dynamisch Methoden zu simulieren und damitauch das Überladen: http://php.net/manual/de/language.oop5.overloading.php Das ist aber kein Überladen.
15Webtechnologien – SS 2017 - Teil 7/PHP II
Beseitigen von Instanzen/Objekten I
unset(Variable [, Variable ...]);
$Kfz= new Auto();$Kfz->Hersteller= "Benz";unset($Kfz);
• Ein(e) Objekt(-Variable) enthält wie in Java eine Referenz auf das Objekt.
• Ein Objekt wird durch den Garbage-Collector gelöscht, wenn keine Referenzen darauf mehr vorhanden sind, also wie in Java.
• Mit unset() wird eine Referenz gelöscht, d.h. die Variable hat anschließend den Wert NULL.
• Eine Variable hat also den Typ NULL mit dem Wert null, wenn
– ihr die Konstante NULL zugewiesen wurde,
– sie noch nicht initialisiert wurde (vor der ersten Zuweisung) oder
– sie mit unset() bearbeitet wurde.
• Mit isset() wird geprüft, ob die Variable den Typ/Wert NULL hat.Aufruf: isset(Variablenname)
16Webtechnologien – SS 2017 - Teil 7/PHP II
Beseitigen von Instanzen/Objekten II
• __destruct() wird direkt vor der Beseitigung aufgerufen, d.h. erst wenn der Referenzzähler auf 0 ist und der Garbage-Collector sich an die Arbeit macht, um das betreffende Objekt zu entfernen,
• also nicht (unbedingt) zum Zeitpunkt von unset(), aber spätestens zum Skriptende.
• Wir haben ähnliche Verhältnisse wie in Java.
class Auto { ... function __destruct() { echo "Jetzt bin ich auf dem Schrottplatz!"; }}
17Webtechnologien – SS 2017 - Teil 7/PHP II
Namensgebung und Deklarationen
• Groß/Kleinschreibung bei:– Variablen, Konstanten und Attributen wird unterschieden.
– Konstruktoren, Funktionen und Klassen wird nicht unterschieden.
• Da sich dies nicht so leicht merken lässt: einfach immer alles so deklarieren, dass es nicht auf die Groß/Kleinschreibung ankommt.
18Webtechnologien – SS 2017 - Teil 7/PHP II
Kopieren von Objekten bei PHP 5 I
• Variablen vom Typ object werden bei– Zuweisungen
– Parameterübergaben
nicht kopiert sondern nur deren Adresse,d.h. der Referenzzähler wird um 1 erhöht.
• Das Zuweisen besteht also im Kopieren seiner Adresse, nicht in einem Klonen; Objekte werden also nicht kopiert.Basisdatentypen, Strings und Arrays werden aber kopiert.
• Wenn geklont, also kopiert werden soll, muss dies per clone erfolgen:
$meins= new Auto();$unser= $meins; // $unser, $meins zeigen auf Dasselbe$deins= clone $meins;// jetzt gibt es zwei gleiche Autos
19Webtechnologien – SS 2017 - Teil 7/PHP II
Kopieren von Objekten bei PHP 5 II
• Bei folgenden Datentypen werden die Werte durch Kopieren als Parameter übergeben bzw. zugewiesen:– Integer (wie Java)
– Double/Float (wie Java)
– Boolean (wie Java)
– String (Nicht in Java!)
– Array bzw. Hash (Nicht in Java!)
Es sei denn, bei der Deklaration der Funktion wurde ein Parameter als Call-by-Reference durch ein & angegeben; dann werden immer die Adressen übergeben.
20Webtechnologien – SS 2017 - Teil 7/PHP II
Die magische Methode __clone() I
• PHP kopiert Klassen automatisch immer nur "flach".
• Flaches Klonen = Kopieren der Werte und Referenzen nur der Wurzel eines Objekt-Baumes
• Tiefes Klonen = Kopieren des gesamten Objekt-Baumes
• Existiert die Methode __clone(), so wird diese zum Klonen aufgerufen. Damit lässt sich tiefes Klonens realisieren.
(1) class Person {(2) private $Vorname; private $Nachname;(3) private $Adresse;(4) function __construct() {(5) $this->Adresse= new Address();(6) }(7) }(8) $heribert= new Person();(9) $elvira= clone $heribert;
21Webtechnologien – SS 2017 - Teil 7/PHP II
Die magische Methode __clone() II – Flaches Klonen
Person Adresseheribert
Situation nach Zeile (8):
Situation nach Zeile (9):
Person Adresseheribert
elvira Person
Klonen
22Webtechnologien – SS 2017 - Teil 7/PHP II
Die magische Methode __clone() III
• In diesem Beispiel wird eine tiefe Kopie realisiert, da auch die Address-Objekte kopiert werden.
(1) class Person {(2) private $Vorname; private $Nachname;(3) private $Adresse;(4) function __construct() {(5) $this->Adresse= new Address();(6) }(7) function __clone() {(8) $this->Adresse= clone $this->Adresse;(9) }(10) }(11) $heribert= new Person();(12) $elvira= clone $heribert;
23Webtechnologien – SS 2017 - Teil 7/PHP II
Die magische Methode __clone() IV – Tiefes Klonen
Person Adresseheribert
Situation nach Zeile (11):
Situation nach Zeile (12):
Person Adresseheribert
elvira Person Adresse
Klonen Klonen
24Webtechnologien – SS 2017 - Teil 7/PHP II
Vererbung I
class Person { public $Vorname; public $Nachname;
function Output() { echo "$this->Vorname $this->Nachname"; }}
25Webtechnologien – SS 2017 - Teil 7/PHP II
Vererbung II
• Verweis auf obere Klasse (Elternklasse): "extends"
• Zugriff auf Attribute oberer Klassen über "parent::"
class Kunde extends Person { public $Strasse; public $Ort; public $Num; function __construct($VN, $NN) { $this->Vorname= $VN; $this->Nachname= $NN; } function Output() { echo "$this->Num<br>"; parent::Output(); echo "$this->Strasse <br>$this->Ort<br>\n"; }}
26Webtechnologien – SS 2017 - Teil 7/PHP II
Bemerkung zu ::
• Der ::-Operator muss auch auf Methoden von Klassen ohne Instanzen (static) angewendet werden.
• In diesem static-Fall besteht folgende Bedingung:Die Methode muss ohne Konstruktor und ohne Initialisierung arbeiten können, also nur mit static-Attributen bzw. nur mit Aufrufen von static-Methoden.
• Dieser Operator wird auch Paamayim Nekudotayim genannt,siehe dazu https://de.wikipedia.org/wiki/Paamayim_Nekudotayim
27Webtechnologien – SS 2017 - Teil 7/PHP II
Konstanten in Klassen I
• Konstanten innerhalb einer Klasse werden mit const deklariert und mit einfachen Werten, keinen Ausdrücken, definiert.
• Ab PHP 7.1 können Konstanten in Klassen auch die üblichen Modifier der Attribute und Methoden haben, public ist Default.
• Der Zugriff innerhalb der Klasse erfolgt mit self::Name,von außen mit Klasse::Name, falls public.
• Konstanten haben kein einleitendes Dollarzeichen.
class Math { const PI= 3.14159; const E= 2.71828; function umfang($radius) { return 2*self::PI*$radius; }}
28Webtechnologien – SS 2017 - Teil 7/PHP II
Konstanten in Klassen II
• Jetzt wird die global deklarierte Konstante PI mit dem Wert 20 benutzt - dies liegt am fehlenden "self::".
define('PI',20);....class Math { const PI= 3.14159; const E= 2.71828; function umfang($radius) { return 2*PI*$radius; }}
29Webtechnologien – SS 2017 - Teil 7/PHP II
static
• Analog zum Zugriff auf Konstanten wird mit self:: auf statische Attribute bzw. Methoden der eigenen Klasse zugegriffen.
• Alle static-Attribute werden ein einziges Mal angelegt und gemeinsam von allen Objekten der betreffenden Klasse benutzt.
• Der Zugriff von Außen erfolgt durch den Klassenname::Methode() bzw. Klassenname::Attribut.
class Math { private static myVar; public static Sinus($value) { self::myVar= ....; return ....; }}
$var= Math::Sinus(0);
30Webtechnologien – SS 2017 - Teil 7/PHP II
final
• Durch das Schlüsselwort final vor einer Klasse, Methode oder einem Attribut lässt sich ein Überschreiben bzw. Überdecken durch Vererbung verhindern.
• final angewendet auf Attribute führt zu Konstanten innerhalb von Klassen und sollte auch so angewendet werden.
31Webtechnologien – SS 2017 - Teil 7/PHP II
Merkregel für :: und ->
Wann muss mit :: und wann mit -> zugegriffen werden?
Wenn der Compiler, also vor der Laufzeit, die Zuordnungbestimmen kann, dann mit ::Wenn erst zur Laufzeit die Adresse der referenzierten Sachebekannt ist, dann mit ->
Oder anders:Alles, was mit new() erzeugt wurde: ->Alles, was static oder eine Konstante ist: ::
Das gilt auch im Inneren der Methoden.
32Webtechnologien – SS 2017 - Teil 7/PHP II
Type Hints
• Es kann der Objekttyp bei der Parameterübergabe eingeschränkt werden.
• Leider geht dies bis PHP 7.0 nur bei Objekten, nicht bei anderen Datentypen, z.B. bei Arrays. Ab PHP 7.0 ist ein Spezialfall der Type Hints.
class PersonGroup { public function add(Person $person) { .... }}
33Webtechnologien – SS 2017 - Teil 7/PHP II
interface I
• Ein Interface ist eine Klasse mit Methoden ohne Body.
• Eine Klasse "erbt" von einem Interface durch das Schlüsselwort implements.
• Von Interfaces können keine Instanzen gebildet werden.
interface File { public function read(); public function write(); public function open();}...class Document implements File { public function read() { ... } ....}
34Webtechnologien – SS 2017 - Teil 7/PHP II
interface II
• Möglichst, am besten immer:Vorher deklarieren, dann instantiieren bzw. benutzen.
• Es können mehrere Interfaces realisiert, aber nur von einer Klasse per extends geerbt werden - also wie in Java.
• Bei Interface-Klassen gibt es kein class-Schlüsselwort.
35Webtechnologien – SS 2017 - Teil 7/PHP II
abstract I
• Um Klassenrümpfe realisieren zu können, wird abstract benutzt.
• abstract kann vor class oder function stehen.
• Von einer Klasse mit mindestens einer abstract-Komponente kann keine Instanz gebildet werden; also wie in Java.
abstract class File { abstract public function read(); abstract public function write(); abstract public function open();}...class Document extends File { public function read() { ... } ....}
36Webtechnologien – SS 2017 - Teil 7/PHP II
abstract II
• Wenn eine Klasse schon eine einzige abstrakte Methode enthält, muss die ganze Klasse als abstrakt gekennzeichnet werden.
• Im Klassenkörper können abstrakte und konkrete Methoden beliebig gemischt auftreten.
• Abstrakte Methoden können nicht als final gekennzeichnet werden, da diese ja per Vererbung konkretisiert werden müssen.
37Webtechnologien – SS 2017 - Teil 7/PHP II
Wrapper-Klassen I
• Eine Wrapper-Klasse verdeckt die Schnittstelle einer anderen Klasse zwecks Anpassung oder Vereinheitlichung.
• Als erstes wird eine Interface-Klasse definiert (Beispiel):
interface SQL_DB { function connect($server, $user, $password); function query($SQL); function disConnect();}
38Webtechnologien – SS 2017 - Teil 7/PHP II
Wrapper-Klassen II
Beispiel zum Verdecken von Oracle-Spezifika:
require_once 'SQL_DB.php';
class Oracle implements SQL_DB { function connect($server, $user, $password) { …… } function query($SQL) { …… } function disConnect() { …… }}
39Webtechnologien – SS 2017 - Teil 7/PHP II
Wrapper-Klassen III
Beispiel zum Verdecken von MySQL-Spezifika:
require_once 'SQL_DB.php';
class MySQL implements SQL_DB { function connect($server, $user, $password) { …… } function query($SQL) { …… } function disConnect() { …… }}
40Webtechnologien – SS 2017 - Teil 7/PHP II
UML-Version (Wrapper mit Interface)
MySQL
connect()
query()
disConnect()
SQL_DB
<<interface>>
connect()
query()
disConnect()
Oracle
connect()
query()
disConnect()
<<realize>><<realize>>
OCI8MySQLi
callcall
41Webtechnologien – SS 2017 - Teil 7/PHP II
Fabrik/Factory-Klasse I
• Eine Fabrik/Factory-Klasse dient dazu, den Aufbau eines Objektes oder eines Geflechts von Objekten zu realisieren und damit auch zu verdecken.
• Regel/Empfehlung:Verwende immer dann Fabrik-Klassen, wenn – beim Aufbau mehrere Klassen alternativ verwendbar sind, also wenn
eine Konfiguration möglich ist,
– der Aufbau vernetzter Objekte komplex ist,
– der Aufbau versteckt werden soll/muss.
42Webtechnologien – SS 2017 - Teil 7/PHP II
Fabrik/Factory-Klasse II
class DB { static function Access($type) { if ($type==="ORACLE") { return new Oracle(); } elseif($type==="MYSQL") { return new MySQL(); } else { die("Unbekannter Datenbanktyp: ".$type); } // schlechte Fehlerbehandlung! }}
Benutzung
$OurDB= DB::Access("MYSQL");$OurDB->Connect("127.0.0.1", "root", "Geheim");
43Webtechnologien – SS 2017 - Teil 7/PHP II
Nach dieser Anstrengung etwas Entspannung...