PHP ist eine vollwertige objektorientierte Sprache: Klassen, Interfaces, Traits, Enums (seit 8.1), Vererbung, Konstanten, abstrakte Klassen, readonly-Properties (8.1) und readonly-Klassen (8.2). Attribute (seit 8.0) ersetzen DocBlock-Annotationen. Zugriffs-Modifier: public, protected, private; seit 8.4 auch private(set) und protected(set).
Klasse mit Konstruktor-Property-Promotion (PHP 8.0+)
<?php
declare(strict_types=1);
final class Product
{
public function __construct(
public readonly string $name,
public readonly float $price,
private int $stock = 0,
) {}
public function increaseStock(int $amount): void
{
$this->stock += $amount;
}
public function isAvailable(): bool
{
return $this->stock > 0;
}
}
$p = new Product('T-Shirt', 24.90);
$p->increaseStock(50);
echo $p->name; // T-Shirt (public readonly)
// $p->name = 'x'; // Error: Cannot modify readonly property
Vererbung
class Animal
{
public function __construct(public string $name) {}
public function speak(): string
{
return "$this->name macht Geräusche";
}
}
class Dog extends Animal
{
public function speak(): string
{
return "$this->name bellt";
}
}
$d = new Dog('Bello');
echo $d->speak(); // Bello bellt
Interfaces
interface PaymentGateway
{
public function charge(int $amountInCents, string $currency): bool;
public function refund(string $transactionId): bool;
}
final class StripeGateway implements PaymentGateway
{
public function charge(int $amountInCents, string $currency): bool { /* ... */ }
public function refund(string $transactionId): bool { /* ... */ }
}
Abstrakte Klassen
Können nicht instanziiert werden. Erzwingen, dass Kinder bestimmte Methoden implementieren, teilen aber gemeinsamen Code:
abstract class Report
{
public function generate(): string
{
$data = $this->collect();
return $this->format($data);
}
abstract protected function collect(): array;
abstract protected function format(array $data): string;
}
Traits — horizontale Wiederverwendung
PHP hat keine Mehrfachvererbung. Traits sind der Ersatz: Methoden-Bausteine, die in mehrere Klassen eingemischt werden:
trait Loggable
{
public function log(string $msg): void
{
error_log('[' . static::class . '] ' . $msg);
}
}
class User { use Loggable; }
class Order { use Loggable; }
(new User)->log('Registriert'); // [User] Registriert
Statische Methoden & Properties
class Config
{
private static array $data = [];
public static function set(string $key, mixed $value): void
{
self::$data[$key] = $value;
}
public static function get(string $key): mixed
{
return self::$data[$key] ?? null;
}
}
Config::set('app.name', 'programmierung.net');
echo Config::get('app.name');
Readonly-Klassen (PHP 8.2+)
Alle Properties sind implizit readonly. Ideal für Value Objects und DTOs:
final readonly class Money
{
public function __construct(
public int $cents,
public string $currency,
) {}
public function plus(Money $other): Money
{
return new Money($this->cents + $other->cents, $this->currency);
}
}Häufige Fragen
Wann nutze ich ein Interface, wann eine abstrakte Klasse?
Interface: Vertrag ohne Implementierung — eine Klasse kann viele implementieren. Abstrakte Klasse: teilweise Implementierung + abstract-Methoden; nur eine Elternklasse. Faustregel: Verhalten → Interface, Gerüst → Abstract.
Was sind Traits und wann sind sie sinnvoll?
Traits enthalten Methoden und Properties, die in Klassen "eingemischt" werden (use TraitName;). Lösen Mehrfachvererbung ohne Diamond-Problem. Typisch: Logging, Cacheable, HasUuid in Laravel-Models.
Was macht <code>readonly</code> bei Properties?
public readonly int $id; erlaubt genau eine Zuweisung — meist im Konstruktor. Danach wirft jeder Set-Versuch eine Error. Perfekt für Value-Objects. Seit 8.2 auch für die ganze Klasse: final readonly class.
Was sind Enum-Typen?
Seit PHP 8.1: enum Status { case Active; case Inactive; }. Mit Werten als Backed-Enum: enum Status: string { case Active = "active"; }. Enum-Cases sind Singletons — gleicher Wert heißt gleiche Instanz.
Wie funktioniert Dependency Injection in PHP?
Abhängigkeiten werden im Konstruktor als typisierte Parameter deklariert (public function __construct(private LoggerInterface $log) {}, Constructor Property Promotion seit 8.0). Ein DI-Container (z.B. der Laravel-Service-Container) löst sie automatisch auf.