Modul 295
Backend für Applikationen realisieren
06 - Klassen
Objektorientierte Grundlagen in PHP
Lernziele dieser Lektion
- Die Begriffe Klasse, Objekt und Instanz erklären können
- Eigene Klassen mit Eigenschaften und Methoden in PHP definieren können
- Objekte erzeugen und mit
$this, Konstruktoren und Sichtbarkeiten arbeiten können
- Statische Eigenschaften, Methoden und Klassenkonstanten einsetzen können
- Vererbung, abstrakte Klassen und Interfaces anwenden können
readonly-Eigenschaften und den instanceof-Operator verwenden können
Rückblick: Funktionen
-
Mit Funktionen haben wir Code gebündelt und
wiederverwendbar gemacht
-
Bisher waren Daten (Variablen, Arrays) und Code (Funktionen)
getrennte Dinge
-
Heute verbinden wir beides: Klassen bündeln Daten und
die dazugehörigen Funktionen gemeinsam
Wozu Klassen?
-
Ein Array kann Daten zu einem Produkt speichern - aber die
Logik dazu (z.B. Preis berechnen) liegt woanders im Code
-
Eine Klasse beschreibt einen eigenen Datentyp,
der Eigenschaften (Daten) und Methoden (Verhalten) an einem
Ort zusammenfasst
-
Das Konzept kennen Sie bereits aus anderen Sprachen -
in PHP gilt dasselbe Prinzip
<?php
// Bisher: Daten und Logik getrennt
$product = ["name" => "Apfel", "price" => 0.50];
function printInfo($product) {
echo $product["name"] . ": " . $product["price"] . " CHF";
}
Klasse, Objekt und Instanz
-
Eine Klasse ist ein Bauplan - sie legt fest, welche
Eigenschaften und Methoden ein Ding dieses Typs hat
-
Ein Objekt ist ein konkretes Ding, das nach diesem
Bauplan erzeugt wurde - man sagt auch, es ist eine
Instanz der Klasse
-
Aus einer Klasse lassen sich beliebig viele, unabhängige
Objekte erzeugen
Eine Klasse definieren
-
Mit dem Schlüsselwort
class,
gefolgt vom Namen (meist PascalCase)
und einem Codeblock in geschweiften Klammern
-
Eigenschaften (properties) sind Variablen innerhalb
der Klasse - sie speichern die Daten eines Objekts
<?php
class Product {
public string $name;
public float $price;
}
// Bis hierhin passiert noch nichts -
// die Klasse wurde nur definiert
Ein Objekt erzeugen
-
Mit dem Schlüsselwort
new
gefolgt vom Klassennamen wird ein neues Objekt (eine Instanz)
erzeugt
-
Auf Eigenschaften greift man mit dem Pfeil-Operator
-> zu
<?php
class Product {
public string $name;
public float $price;
}
$apple = new Product();
$apple->name = "Apfel";
$apple->price = 0.50;
echo $apple->name; // "Apfel"
Mehrere, unabhängige Objekte
-
Jedes Objekt hat seine eigenen Werte für die
Eigenschaften - eine Änderung an einem Objekt wirkt sich
nicht auf ein anderes aus
<?php
$apple = new Product();
$apple->name = "Apfel";
$apple->price = 0.50;
$bread = new Product();
$bread->name = "Brot";
$bread->price = 3.20;
echo $apple->name; // "Apfel"
echo $bread->name; // "Brot"
Methoden
-
Eine Methode ist eine Funktion innerhalb einer Klasse -
sie beschreibt das Verhalten eines Objekts
-
Aufgerufen wird sie ebenfalls mit dem Pfeil-Operator
->
<?php
class Product {
public string $name;
public float $price;
public function printInfo() {
echo $this->name . ": " . $this->price . " CHF";
}
}
$apple = new Product();
$apple->name = "Apfel";
$apple->price = 0.50;
$apple->printInfo(); // "Apfel: 0.5 CHF"
$this - Verweis auf das aktuelle Objekt
-
Innerhalb einer Methode zeigt
$this
immer auf das Objekt, über welches die Methode gerade
aufgerufen wurde
-
Damit greift eine Methode auf die Eigenschaften
ihres eigenen Objekts zu
<?php
$apple->printInfo(); // $this zeigt hier auf $apple
$bread->printInfo(); // $this zeigt hier auf $bread
Der Konstruktor __construct()
-
Die Methode
__construct()
wird automatisch aufgerufen, sobald ein Objekt mit
new erzeugt wird
-
Sie dient dazu, die Eigenschaften direkt bei der Erzeugung
zu setzen - statt sie danach einzeln zuzuweisen
<?php
class Product {
public string $name;
public float $price;
public function __construct($name, $price) {
$this->name = $name;
$this->price = $price;
}
}
$apple = new Product("Apfel", 0.50);
echo $apple->name; // "Apfel"
Constructor Property Promotion
-
Seit PHP 8 können Eigenschaften direkt in der
Parameterliste des Konstruktors deklariert werden - Deklaration
und Zuweisung passieren dann in einem Schritt
-
Spart Schreibarbeit, das Verhalten ist identisch zur
vorherigen Folie
<?php
class Product {
public function __construct(
public string $name,
public float $price
) {}
}
$apple = new Product("Apfel", 0.50);
echo $apple->name; // "Apfel"
Sichtbarkeit: public und private
-
public - von überall
zugreifbar, auch von aussen über
->
-
private - nur innerhalb
derselben Klasse zugreifbar, schützt Daten vor
unerlaubtem Zugriff von aussen
<?php
class Product {
public function __construct(
public string $name,
private float $price
) {}
}
$apple = new Product("Apfel", 0.50);
echo $apple->name; // "Apfel" - erlaubt
echo $apple->price; // Fehler: $price ist private
Sichtbarkeit: protected
-
protected - zugreifbar
innerhalb der eigenen Klasse und in davon abgeleiteten
Klassen (Vererbung, siehe später)
-
Von aussen (über
->)
ist der Zugriff, wie bei private,
nicht erlaubt
Getter und Setter
-
Da
private-Eigenschaften
von aussen nicht direkt zugreifbar sind, definiert man
öffentliche Methoden dafür - Getter zum Lesen,
Setter zum Schreiben
-
Ein Setter kann zusätzlich Werte prüfen, bevor er sie
übernimmt
<?php
class Product {
public function __construct(
public string $name,
private float $price
) {}
public function getPrice(): float {
return $this->price;
}
public function setPrice(float $price): void {
if ($price >= 0) {
$this->price = $price;
}
}
}
$apple = new Product("Apfel", 0.50);
echo $apple->getPrice(); // 0.5
$apple->setPrice(0.80);
echo $apple->getPrice(); // 0.8
Statische Eigenschaften
-
Eine
static-Eigenschaft
gehört der Klasse selbst, nicht einem einzelnen Objekt -
alle Objekte teilen sich denselben Wert
-
Zugriff innerhalb der Klasse mit
self::$name
<?php
class Product {
public static int $count = 0;
public function __construct(public string $name) {
self::$count++;
}
}
$apple = new Product("Apfel");
$bread = new Product("Brot");
echo Product::$count; // 2
Statische Methoden
-
Eine
static-Methode wird
über den Klassennamen aufgerufen, nicht über ein Objekt -
Klasse::methode()
-
Innerhalb einer statischen Methode gibt es kein
$this, da kein konkretes
Objekt vorliegt
<?php
class Product {
private static int $count = 0;
public function __construct(public string $name) {
self::$count++;
}
public static function getCount(): int {
return self::$count;
}
}
new Product("Apfel");
new Product("Brot");
echo Product::getCount(); // 2
Klassenkonstanten
-
Mit
const definiert man
einen Wert, der sich nie ändert - z.B. einen Steuersatz
-
Zugriff innerhalb der Klasse mit
self::NAME, von aussen mit
Klasse::NAME
<?php
class Product {
public const TAX_RATE = 0.077;
public function __construct(
public string $name,
public float $price
) {}
public function priceWithTax(): float {
return $this->price * (1 + self::TAX_RATE);
}
}
$apple = new Product("Apfel", 0.50);
echo $apple->priceWithTax(); // 0.5385
echo Product::TAX_RATE; // 0.077
Vererbung mit extends
-
Eine Klasse kann alle Eigenschaften und Methoden einer
anderen Klasse erben - die neue Klasse muss diese
nicht selbst nochmals definieren
-
Die ursprüngliche Klasse heisst Basisklasse (Eltern-
klasse), die neue abgeleitete Klasse (Kindklasse)
<?php
class SaleProduct extends Product {
// erbt $name, $price, priceWithTax(), ...
public function __construct(
string $name,
float $price,
public float $discount
) {
parent::__construct($name, $price);
}
}
$sale = new SaleProduct("Apfel", 0.50, 0.2);
echo $sale->priceWithTax(); // geerbt von Product
parent::
-
Mit
parent:: ruft man
gezielt eine Methode der Basisklasse auf - z.B. deren
Konstruktor, wie auf der vorherigen Folie
-
So lässt sich Code der Basisklasse wiederverwenden, statt
ihn zu duplizieren
Methoden überschreiben (Overriding)
-
Eine abgeleitete Klasse kann eine geerbte Methode mit
demselben Namen neu definieren - die eigene Version
gilt dann
-
Mit
parent::methode() lässt
sich innerhalb der neuen Version trotzdem die ursprüngliche
Methode mit aufrufen
<?php
class SaleProduct extends Product {
public function __construct(
string $name, float $price, public float $discount
) {
parent::__construct($name, $price);
}
public function priceWithTax(): float {
$reducedPrice = $this->price * (1 - $this->discount);
return $reducedPrice * (1 + self::TAX_RATE);
}
}
$sale = new SaleProduct("Apfel", 0.50, 0.2);
echo $sale->priceWithTax(); // eigene, überschriebene Version
Abstrakte Klassen
-
Eine
abstract-Klasse kann
nicht direkt mit new
erzeugt werden - sie dient nur als Basis für andere Klassen
-
Sie kann abstrakte Methoden enthalten - diese haben
keinen Codeblock, jede abgeleitete Klasse muss sie
implementieren
<?php
abstract class Shape {
abstract public function calculateArea(): float;
public function printArea(): void {
echo "Fläche: " . $this->calculateArea();
}
}
$shape = new Shape(); // Fehler: abstrakte Klasse
Abstrakte Klasse implementieren
-
Konkrete Klassen erben von der abstrakten Klasse und liefern
die Umsetzung der abstrakten Methode
-
Nicht-abstrakte Methoden (wie
printArea())
werden ganz normal geerbt
<?php
class Circle extends Shape {
public function __construct(private float $radius) {}
public function calculateArea(): float {
return M_PI * $this->radius ** 2;
}
}
$circle = new Circle(3);
$circle->printArea(); // "Fläche: 28.27..."
Interfaces
-
Ein
interface schreibt vor,
welche Methoden eine Klasse haben muss - ohne selbst
eine Umsetzung vorzugeben
-
Eine Klasse setzt ein Interface mit
implements um und kann
dabei auch gleichzeitig von einer Klasse erben
<?php
interface Describable {
public function describe(): string;
}
class Circle extends Shape implements Describable {
public function __construct(private float $radius) {}
public function calculateArea(): float {
return M_PI * $this->radius ** 2;
}
public function describe(): string {
return "Kreis mit Radius " . $this->radius;
}
}
Unveränderliche Eigenschaften mit readonly
-
Seit PHP 8.1 kann eine Eigenschaft als
readonly markiert werden -
sie darf nur einmal, direkt im Konstruktor, gesetzt
werden
-
Ein späterer Schreibversuch löst einen Fehler aus - nützlich
für Werte, die sich nach der Erzeugung nicht mehr ändern
sollen
<?php
class Point {
public function __construct(
public readonly float $x,
public readonly float $y
) {}
}
$p = new Point(3, 4);
echo $p->x; // 3
$p->x = 10; // Fehler: readonly-Eigenschaft
Der instanceof-Operator
-
Mit
instanceof prüft man,
ob ein Objekt von einer bestimmten Klasse (oder einem
Interface) ist
-
Praktisch, wenn ein Array Objekte verschiedener,
verwandter Klassen enthält
<?php
$shapes = [new Circle(3), new Product("Apfel", 0.5)];
foreach ($shapes as $item) {
if ($item instanceof Shape) {
$item->printArea();
}
}
// nur der Kreis wird ausgegeben - Product ist kein Shape
TL;DR
-
Eine Klasse ist ein Bauplan für Objekte - mit
new wird daraus eine
konkrete Instanz erzeugt
-
Eigenschaften und Methoden gehören zusammen;
$this zeigt innerhalb einer
Methode auf das eigene Objekt
-
public,
private und
protected steuern die
Sichtbarkeit - Getter/Setter kapseln private Daten
-
static gehört der Klasse,
nicht dem Objekt; const
definiert unveränderliche Klassenwerte
-
extends vererbt,
abstract-Klassen und
interfaces legen fest, was
abgeleitete Klassen können müssen