Die Grundlagen

class

Einfache Klassendefinitionen beginnen mit dem Schlüsselwort class, gefolgt von einem Klassennamen, gefolgt von einem Paar geschweifter Klammern, die die Definitionen der Eigenschaften und Methoden der Klasse enthalten.

Der Klassenname kann ein beliebiger gültiger Bezeichner sein, vorausgesetzt es ist kein von PHP reserviertes Wort. Ein gültiger Klassenname beginnt mit einem Buchstaben oder einem Unterstrich, gefolgt von einer beliebigen Anzahl von Buchstaben, Ziffern oder Unterstrichen; als regulärer Ausdruck formuliert: ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$.

Eine Klasse darf aus ihren eigenen Konstanten, Variablen ("Eigenschaften" genannt) und Funktionen ("Methoden" genannt) bestehen.

Beispiel #1 Definition einer einfachen Klasse

<?php
class SimpleClass
{
// Deklaration einer Eigenschaft
public $var = 'ein Standardwert';

// Deklaration einer Methode
public function displayVar() {
echo
$this->var;
}
}
?>

Die Pseudovariable $this ist verfügbar, wenn eine Methode aus einem Objektkontext heraus aufgerufen wird. $this ist eine Referenz auf das aufgerufene Objekt.

Warnung

Wird eine nicht-statische Methode statisch aufgerufen, so wird ein Error ausgelöst. Vor PHP 8.0.0 führte dies zu einem Hinweis über das veraltete Verfahren und $this war nicht definiert.

Beispiel #2 Einige Beispiele für die Pseudovariable $this

<?php
class A
{
function
foo()
{
if (isset(
$this)) {
echo
'$this ist definiert (';
echo
get_class($this);
echo
").\n";
} else {
echo
"\$this ist nicht definiert.\n";
}
}
}

class
B
{
function
bar()
{
A::foo();
}
}

$a = new A();
$a->foo();

A::foo();

$b = new B();
$b->bar();

B::bar();
?>

Das oben gezeigte Beispiel erzeugt mit PHP 7 folgende Ausgabe:

 $this ist definiert (A). Deprecated: Non-static method A::foo() should not be called statically in %s on line 27 $this ist nicht definiert. Deprecated: Non-static method A::foo() should not be called statically in %s on line 20 $this ist nicht definiert. Deprecated: Non-static method B::bar() should not be called statically in %s on line 32 Deprecated: Non-static method A::foo() should not be called statically in %s on line 20 $this ist nicht definiert. 

Das oben gezeigte Beispiel erzeugt mit PHP 8 folgende Ausgabe:

 $this ist definiert (A). Fatal error: Uncaught Error: Non-static method A::foo() cannot be called statically in %s :27 Stack trace: #0 {main} thrown in %s on line 27 

Schreibgeschützte Klassen

Seit PHP 8.2.0 kann eine Klasse mit dem Modifikator readonly gekennzeichnet werden. Wenn eine Klasse als readonly markiert wird, wird der Modifikator readonly zu jeder deklarierten Eigenschaft hinzugefügt und die Erstellung dynamischer Eigenschaften verhindert. Darüber hinaus ist es nicht möglich, die Unterstützung für solche Eigenschaften mit Hilfe des Attributs AllowDynamicProperties hinzuzufügen. Der Versuch, dies zu tun, führt zu einem Fehler bei der Kompilierung.

<?php
#[\AllowDynamicProperties]
readonly class
Foo {
}

// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo
?>

Da weder nicht typisierte noch statische Eigenschaften mit dem readonly-Modifikator gekennzeichnet werden können, können readonly-Klassen diese auch nicht deklarieren:

<?php
readonly class Foo
{
public
$bar;
}

// Fatal error: Readonly property Foo::$bar must have type
?>
<?php
readonly class Foo
{
public static
int $bar;
}

// Fatal error: Readonly class Foo cannot declare static properties
?>

Eine readonly-Klasse kann nur dann erweitert werden, wenn die Kindklasse ebenfalls eine readonly-Klasse ist.

new

Um eine Instanz einer Klasse zu erzeugen, muss das Schlüsselwort new verwendet werden. Ein Objekt wird immer erzeugt, außer das Objekt besitzt einen definierten Konstruktor, der aufgrund eines Fehlers eine Exception auslöst. Klassen sollten vor ihrer Instantiierung definiert werden (in manchen Fällen ist dies eine Notwendigkeit).

Wenn eine Variable, die einen String mit dem Namen einer Klasse enthält, zusammen mit new verwendet wird, wird eine neue Instanz dieser Klasse erzeugt. Falls sich die Klasse in einem Namensraum befindet, muss der voll qualifizierte Name hierfür genutzt werden.

Hinweis:

Wenn dem Klassenkonstruktor keine Argumente übergeben werden müssen, können die Klammern hinter dem Klassennamen weggelassen werden.

Beispiel #3 Eine Instanz erzeugen

<?php
$instanz
= new SimpleClass();

// dies ist auch mit einer Variablen möglich:
$klassenName = 'SimpleClass';
$instanz = new $klassenName(); // new SimpleClass()
?>

Seit PHP 8.0.0 wird die Verwendung von new mit beliebigen Ausdrücken unterstützt. Dies ermöglicht eine komplexere Instanziierung, sofern der Ausdruck einen String erzeugt. Die Ausdrücke müssen in Klammern eingeschlossen werden.

Beispiel #4 Erzeugen einer Instanz mit einem beliebigen Ausdruck

Hier werden mehrere Beispiele für gültige beliebige Ausdrücke gezeigt, die einen Klassennamen erzeugen. Enthalten ist ein Funktionsaufruf, eine String-Verkettung und die Konstante ::class.

<?php

class ClassA extends \stdClass {}
class
ClassB extends \stdClass {}
class
ClassC extends ClassB {}
class
ClassD extends ClassA {}

function
getSomeClass(): string
{
return
'ClassA';
}

var_dump(new (getSomeClass()));
var_dump(new ('Class' . 'B'));
var_dump(new ('Class' . 'C'));
var_dump(new (ClassD::class));
?>

Das oben gezeigte Beispiel erzeugt mit PHP 8 folgende Ausgabe:

 object(ClassA)#1 (0) { } object(ClassB)#1 (0) { } object(ClassC)#1 (0) { } object(ClassD)#1 (0) { } 

Im Kontext einer Klasse ist es möglich, neue Objekte mit new self und new parent anzulegen.

Wenn man eine bereits erzeugte Instanz einer Klasse einer neuen Variablen zuweist, wird die neue Variable auf dieselbe Instanz zugreifen wie das Objekt, das zugewiesen wurde. Dieses Verhalten ist dasselbe, wenn man Instanzen an Funktionen übergibt. Eine Kopie eines bereits erzeugten Objekts erhält man, indem man es klont.

Beispiel #5 Objektzuweisung

<?php

$instanz
= new SimpleClass();

$zugewiesen = $instanz;
$referenz =& $instanz;

$instanz->var = '$zugewiesen wird diesen Wert haben';

$instanz = null; // $instanz und $referenz werden null

var_dump($instanz);
var_dump($referenz);
var_dump($zugewiesen);
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

 NULL NULL object(SimpleClass)#1 (1) { ["var"]=> string(34) "$zugewiesen wird diesen Wert haben" } 

Es gibt mehrere Möglichkeiten, Instanzen eines Objekts zu erzeugen:

Beispiel #6 Erzeugen neuer Objekte

<?php

class Test
{
public static function
getNew()
{
return new static();
}
}

class
Child extends Test {}

$obj1 = new Test(); // Durch den Namen der Klasse
$obj2 = new $obj1(); // Durch die Variable, die ein Objekt enthält
var_dump($obj1 !== $obj2);

$obj3 = Test::getNew(); // Durch die Methode der Klasse
var_dump($obj3 instanceof Test);

$obj4 = Child::getNew(); // Durch eine Methode der Kindklasse

?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

 bool(true) bool(true) bool(true) 

Es ist möglich, auf ein Mitglied eines neu erzeugten Objekts in einem einzigen Ausdruck zuzugreifen:

Beispiel #7 Zugriff auf ein Mitglied eines neu erzeugten Objekts

<?php
echo (new DateTime())->format('Y');
?>

Das oben gezeigte Beispiel erzeugt eine ähnliche Ausgabe wie:

 2016 

Hinweis: Vor PHP 7.1 werden die Argumente nicht ausgewertet, wenn keine Konstruktor-Funktion definiert ist.

Eigenschaften und Methoden

Klassen-Eigenschaften und -Methoden leben in separaten "Namensräumen", so dass es eine Eigenschaft und eine Methode desselben Namens geben kann. Der Zugriff auf eine Eigenschaft und eine Methode hat die gleiche Schreibweise und ob auf eine Eigenschaft zugegriffen oder eine Methode aufgerufen wird, hängt einzig und allein vom Kontext ab, d. h. ob die Verwendung ein Variablenzugriff oder ein Funktionsaufruf ist.

Beispiel #8 Variablenzugriff vs. Methodenaufruf

<?php
class Foo
{
public
$bar = 'Eigenschaft';

public function
bar() {
return
'Methode';
}
}

$obj = new Foo();
echo
$obj->bar, PHP_EOL, $obj->bar(), PHP_EOL;

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

 Eigenschaft Methode 

Das bedeutet, dass der Aufruf einer anonymen Funktion, die einer Eigenschaft zugewiesen wurde, nicht direkt möglich ist. Stattdessen muss beispielsweise die Eigenschaft zunächst einer Variablen zugewiesen werden. Es ist möglich, eine solche Eigenschaft direkt aufzurufen, indem man sie in Klammern einschließt.

Beispiel #9 Aufruf einer anonymen Funktion, die in einer Eigenschaft gespeichert ist

<?php
class Foo
{
public
$bar;

public function
__construct() {
$this->bar = function() {
return
42;
};
}
}

$obj = new Foo();

echo (
$obj->bar)(), PHP_EOL;

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

 42 

extends

Eine Klasse kann die Konstanten, Methoden und Eigenschaften einer anderen Klasse erben, indem man das Schlüsselwort extends in der Deklaration benutzt. Es ist nicht möglich, mehrere Klassen zu erweitern; eine Klasse kann nur eine einzige Basisklasse beerben.

Die geerbten Konstanten, Methoden und Eigenschaften können überschrieben werden, indem sie mit demselben Namen neu deklariert werden, mit dem sie in der Elternklasse definiert wurden. Falls die Elternklasse eine Methode oder eine Konstante als final definiert hat, können diese nicht überschrieben werden. Es ist möglich, auf die überschriebenen Methoden oder statischen Eigenschaften zuzugreifen, wenn diese mittels parent:: referenziert werden.

Hinweis: Seit PHP 8.1.0 können Konstanten als final deklariert werden.

Beispiel #10 Einfache Vererbung

<?php
class ExtendClass extends SimpleClass
{
// Die Elternmethode überschreiben
function displayVar()
{
echo
"Erweiternde Klasse\n";
parent::displayVar();
}
}

$extended = new ExtendClass();
$extended->displayVar();
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

 Erweiternde Klasse ein Standardwert 

Regeln zur Signaturkompatibilität

Wenn eine Methode überschrieben wird, so muss deren Signatur mit derjenigen der Elternmethode kompatibel sein. Andernfalls wird ein fataler Fehler hervorgerufen oder, vor PHP 8.0.0, eine Warnung der Stufe E_WARNING ausgegeben. Eine Signatur ist kompatibel, wenn sie die Regeln der Varianz einhält, einen obligatorischen Parameter optional macht, nur neue optionale Parameter hinzufügt und die Sichtbarkeit nicht einschränkt, sondern nur lockert. Dies ist als das Liskovsche Substitutionsprinzip, kurz LSP, bekannt. Der Konstruktor sowie private Methoden sind von diesen Regeln zur Signaturkompatibilität ausgenommen, weshalb im Fall einer Untimmigkeit in der Signatur kein fataler Fehler hervorgerufen wird.

Beispiel #11 Kompatible Kindmethoden

<?php

class Base
{
public function
foo(int $a) {
echo
"Gültig\n";
}
}

class
Extend1 extends Base
{
function
foo(int $a = 5)
{
parent::foo($a);
}
}

class
Extend2 extends Base
{
function
foo(int $a, $b = 5)
{
parent::foo($a);
}
}

$extended1 = new Extend1();
$extended1->foo();
$extended2 = new Extend2();
$extended2->foo(1);

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

 Gültig Gültig 

Das folgende Beispiel demonstriert, dass eine Kindmethode nicht zur Elternmethode kompatibel ist, wenn sie einen Parameter entfernt oder einen optionalen Parameter notwendig macht.

Beispiel #12 Fataler Fehler, wenn eine Kindmethode einen Parameter entfernt

<?php

class Base
{
public function
foo(int $a = 5) {
echo
"Gültig\n";
}
}

class
Extend extends Base
{
function
foo()
{
parent::foo(1);
}
}

Das oben gezeigte Beispiel erzeugt mit PHP 8 eine ähnliche Ausgabe wie:

 Fatal error: Declaration of Extend::foo() must be compatible with Base::foo(int $a = 5) in /in/evtlq on line 13 

Beispiel #13 Fataler Fehler, wenn eine Kindmethode einen optionalen Parameter notwendig macht

<?php

class Base
{
public function
foo(int $a = 5) {
echo
"Gültig\n";
}
}

class
Extend extends Base
{
function
foo(int $a)
{
parent::foo($a);
}
}

Das oben gezeigte Beispiel erzeugt mit PHP 8 eine ähnliche Ausgabe wie:

 Fatal error: Declaration of Extend::foo(int $a) must be compatible with Base::foo(int $a = 5) in /in/qJXVC on line 13 
Warnung

Die Umbenennung eines Parameters einer Methode in einer Kindklasse führt nicht zur Inkompatibilität. Es wird jedoch davon abgeraten, da es zu Fehlern der Stufe Error führt, wenn benannte Parameter verwendet werden.

Beispiel #14 Fehler, wenn benannte Parameter verwendet und diese in der Kindklasse umbenannt werden

<?php

class A {
public function
test($foo, $bar) {}
}

class
B extends A {
public function
test($a, $b) {}
}

$obj = new B;

// Übergabe der Parameter gemäß den Konventionen von A::test()
$obj->test(foo: "foo", bar: "bar"); // ERROR!

Das oben gezeigte Beispiel erzeugt eine ähnliche Ausgabe wie:

 Fatal error: Uncaught Error: Unknown named parameter $foo in /in/XaaeN:14 Stack trace: #0 {main} thrown in /in/XaaeN on line 14 

::class

Das Schlüsselwort class kann auch für die Namensauflösung einer Klasse verwendet werden. Um den vollständig qualifizierten Namen der Klasse ClassName zu erhalten, kann ClassName::class verwendet werden. Dies ist vor allem dann praktisch, wenn mit Namensräumen gearbeitet wird.

Beispiel #15 Auflösung von Klassennamen

<?php
namespace NS {
class
ClassName {
}

echo
ClassName::class;
}
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

 NS\ClassName 

Hinweis:

Bei der Auflösung des Klassennamens unter Verwendung von ::class handelt es sich um eine Transformation zur Übersetzungszeit. Das bedeutet, dass zu der Zeit, zu der die Klassennamen-Zeichenkette erzeugt wird, noch kein Autoloading erfolgt ist. Daraus folgt, dass Klassennamen erweitert werden, selbst wenn die Klasse nicht existiert. In diesem Fall wird kein Fehler erzeugt.

Beispiel #16 Fehlende Auflösung des Klassennamens

<?php
print Does\Not\Exist::class;
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

 Does\Not\Exist 

Von PHP 8.0.0 an kann ::class auch auf Objekte angewendet werden. Diese Auflösung des Klassennamens erfolgt nicht zur Übersetzungszeit, sondern zur Laufzeit. Sie hat die gleichen Auswirkungen wie der Aufruf von get_class() auf das Objekt.

Beispiel #17 Namensauflösung eines Objekts

<?php
namespace NS {
class
ClassName {
}
}
$c = new ClassName();
print
$c::class;
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

 NS\ClassName 

Nullsafe-Methoden und -Eigenschaften

Von PHP 8.0.0 an kann auf Eigenschaften und Methoden stattdessen auch mit dem "Nullsafe"-Operator zugegriffen werden: ?->. Der Nullsafe-Operator funktioniert genauso als Eigenschafts- oder Methodenzugriff wie oben, mit dem Unterschied, dass null zurückgegeben wird, statt dass eine Exception erzeugt wird, wenn das Objekt, das dereferenziert wird, null ist. Wenn die Dereferenzierung Teil einer Zeichenkette ist, wird der Rest der Zeichenkette übersprungen.

Der Effekt ist ähnlich, wie wenn man jeden Zugriff zuerst mit is_null() prüft, aber kompakter.

Beispiel #18 Nullsafe Operator

<?php

// Von PHP 8.0.0 an entspricht diese Zeile:
$result = $repository?->getUser(5)?->name;

// dem folgenden Codeblock:
if (is_null($repository)) {
$result = null;
} else {
$user = $repository->getUser(5);
if (
is_null($user)) {
$result = null;
} else {
$result = $user->name;
}
}
?>

Hinweis:

Der Nullsafe-Operator wird am besten verwendet, wenn Null ein gültiger und potenziell erwarteter möglicher Rückgabewert für eine Eigenschaft oder eine Methode ist. Um einen Fehler anzuzeigen, ist die Erzeugung einer Exception vorzuziehen.

To Top