Klassen und Objekte
Eine Klasse ist der Bauplan für ein Objekt:
<?php declare(strict_types=1);
namespace spriebsch\tfd\modernPhpDevelopment\objects;
class Counter
{
private int $counter = 0;
public function increment(): void
{
$this->counter += 1;
}
}
Hier haben wir eine Klasse, die einen Zähler repräsentiert. Ein Objekt kapselt Daten (den Zählerwert, anfangs 0) sowie Code beziehungsweise die Algorithmen, die auf diesen Daten operieren. Diese Idee steht in relativ krassem Gegensatz zu der Tatsache, dass Quellcode normalerweise in einer Versionskontrolle verwaltet wird, die Daten einer Anwendung aber in einer Datenbank oder ähnlichen Persistenz-Mechanismen, also getrennt voneinander abgelegt werden.
Den Code nennen wir Methoden, auch wenn dort in PHP function
steht. Wir können uns eine Methode als eine Funktion vorstellen, die innerhalb eines Objekts existiert.
Weiterhin können Objekte Daten enthalten, in unserem Beispiel den Zählerwert, der ein int
ist. Diese Daten nennen wir Attribute oder Properties des Objekts. Um innerhalb eines Objektes auf seinen Zustand, also die aktuellen Attributwerte zuzugreifen, verwenden wir die spezielle Variable $this
. Für den Aufruf einer Methode verwenden wir den Pfeil ->
, der in PHP auch Object Operator genannt wird. In anderen Programmiersprachen wird anstelle des Pfeils .
verwendet.
$this
$this
ist ein reservierter Variablenname. Wenn Du versuchst, die Variable $this
neu zuzuweisen, führt das direkt zum Abbruch des Programms:
<?php declare(strict_types=1);
namespace spriebsch\tfd\modernPhpDevelopment\objects;
class Counter
{
public function increment(): void
{
$this = new Counter;
}
}
PHP Fatal error: Cannot re-assign $this in reassignThis-will-fail.php on line 9
Wie wir in diesem Beispiel gerade schon gesehen haben, verwenden wir new
, um aus einer Klasse ein Objekt zu erzeugen. Das gibt uns eine Referenz auf die erzeugte Objektinstanz zurück, über die wir dem Objekt Nachrichten senden können:
<?php declare(strict_types=1);
namespace spriebsch\tfd\modernPhpDevelopment\objects;
class Counter
{
private int $counter = 0;
public function increment(): void
{
$this->counter += 1;
}
}
$counter = new Counter;
$counter->increment();
var_dump($counter);
instance.php:18: class spriebsch\tfd\modernPhpDevelopment\objects\Counter#1 (1) { private int $counter => int(1) }
Anstelle von "Nachricht senden" würden viele Menschen sagen, dass wir eine Methode aufrufen. Das klingt eher danach, eine Funktion aufzurufen. Hier sehen wir wieder das Spannungsfeld zwischen der Idee von Messaging ("OOP wie es eigentlich gedacht war") und einem eher klassischen Programmierverständnis (Funktionsaufrufe), das in der prozeduralen Programmierung wurzelt.
Wir können mehrere Zähler erzeugen, die voneinander unabhängig sind. Insbesondere hat jedes Zähler-Objekt seinen eigenen Zustand:
<?php declare(strict_types=1);
namespace spriebsch\tfd\modernPhpDevelopment\objects;
class Counter
{
private int $counter = 0;
public function increment(): void
{
$this->counter += 1;
}
}
$counter1 = new Counter;
$counter1->increment();
$counter1->increment();
$counter2 = new Counter;
$counter2->increment();
var_dump($counter1, $counter2);
counters.php:22: class spriebsch\tfd\modernPhpDevelopment\objects\Counter#1 (1) { private int $counter => int(2) } counters.php:22: class spriebsch\tfd\modernPhpDevelopment\objects\Counter#2 (1) { private int $counter => int(1) }
var_dump()
zeigt uns dabei für jedes Objekt hinter dem Klassennamen (das #1
beziehungsweise #2
) an, das wievielte in diesem Programmdurchlauf erzeugte Objekt ausgegeben wir da sehen. Zusätzlich wird uns der Zustand des Objektes in Form der aktuellen Attributwerte ausgegeben.
Weiter geht's
Die Sichtbarkeit, also das private
und das public
in den obigen Beispielen, ist eine eigene Sache für sich, die mehr Erläuterung braucht.
Um ein Objekt in einen arbeitsfähigen Zustand zu versetzen, brauchen wir einen Konstruktor.
Wenn wir nun fleißig Klassen definieren und dann auch noch Third-Party-Code in unsere Anwendung bringen, entstehen mit großer Wahrscheinlichkeit Namenskonflikte, gerade für so einfache und häufig verwendete Klassennamen wie etwa Node
, String
, oder Item
. Um solche Namenskonflikte zu vermeiden, gibt es in PHP Namensräume (Namespaces).