Anonyme Klassen wurden in PHP 7.0 eingeführt und bieten eine praktische Möglichkeit, Klassen zu definieren und zu instanziieren, ohne ihnen einen Namen zu geben. Diese Funktion ist besonders nützlich für einmalige Objekte, die nur an einer Stelle im Code verwendet werden.
Eine anonyme Klasse wird definiert und instanziiert in einem einzigen Schritt:
$objekt = new class {
public function hallo(): string {
return "Hallo von einer anonymen Klasse!";
}
};
echo $objekt->hallo(); // Ausgabe: Hallo von einer anonymen Klasse!Im Gegensatz zu benannten Klassen haben anonyme Klassen keinen Namen, auf den später im Code Bezug genommen werden kann. Sie werden direkt instanziiert, wenn sie definiert werden.
Anonyme Klassen sind besonders nützlich in folgenden Situationen:
Wie bei benannten Klassen können auch anonyme Klassen Konstruktoren mit Parametern haben:
$logger = new class('app.log') {
private string $dateiname;
public function __construct(string $dateiname) {
$this->dateiname = $dateiname;
echo "Logger initialisiert mit Datei: {$this->dateiname}\n";
}
public function log(string $nachricht): void {
echo "Schreibe in {$this->dateiname}: $nachricht\n";
}
};
$logger->log("Anwendung gestartet");Anonyme Klassen können von anderen Klassen erben und Interfaces implementieren:
interface MessageHandler {
public function handle(string $nachricht): void;
}
abstract class AbstractLogger {
protected function formatNachricht(string $nachricht): string {
return date('Y-m-d H:i:s') . ' - ' . $nachricht;
}
}
$logger = new class extends AbstractLogger implements MessageHandler {
public function handle(string $nachricht): void {
$formattedMessage = $this->formatNachricht($nachricht);
echo "Handler: $formattedMessage\n";
}
};
$logger->handle("Ein wichtiges Ereignis");Anonyme Klassen können als Rückgabewerte von Methoden verwendet werden, um spezialisierte Implementierungen zu erstellen:
class FormatterFactory {
public static function createFormatter(string $typ): object {
switch ($typ) {
case 'json':
return new class {
public function format(array $daten): string {
return json_encode($daten);
}
};
case 'xml':
return new class {
public function format(array $daten): string {
$xml = new SimpleXMLElement('<root/>');
foreach ($daten as $key => $value) {
$xml->addChild($key, $value);
}
return $xml->asXML();
}
};
case 'csv':
return new class {
public function format(array $daten): string {
$output = fopen('php://temp', 'r+');
fputcsv($output, array_keys($daten));
fputcsv($output, array_values($daten));
rewind($output);
$csv = stream_get_contents($output);
fclose($output);
return $csv;
}
};
default:
throw new InvalidArgumentException("Unbekannter Formatierer: $typ");
}
}
}
$jsonFormatter = FormatterFactory::createFormatter('json');
$xmlFormatter = FormatterFactory::createFormatter('xml');
$daten = ['name' => 'Max Mustermann', 'alter' => 30];
echo $jsonFormatter->format($daten) . "\n";
echo $xmlFormatter->format($daten) . "\n";Anonyme Klassen können Zugriff auf Variablen aus dem umgebenden Scope haben, indem sie sie im Konstruktor übergeben:
$prefix = "LOG";
$suffix = "END";
$logger = new class($prefix, $suffix) {
private string $prefix;
private string $suffix;
public function __construct(string $prefix, string $suffix) {
$this->prefix = $prefix;
$this->suffix = $suffix;
}
public function log(string $nachricht): void {
echo "{$this->prefix}: $nachricht :{$this->suffix}\n";
}
};
$logger->log("Wichtige Nachricht"); // Ausgabe: LOG: Wichtige Nachricht :ENDAnonyme Klassen können auch Traits verwenden:
trait Loggable {
private string $logLevel = 'INFO';
public function setLogLevel(string $level): void {
$this->logLevel = $level;
}
public function log(string $nachricht): void {
echo "[{$this->logLevel}] $nachricht\n";
}
}
trait Timestampable {
public function getTimestamp(): string {
return date('Y-m-d H:i:s');
}
}
$logger = new class {
use Loggable, Timestampable;
public function logWithTimestamp(string $nachricht): void {
$this->log($this->getTimestamp() . " - " . $nachricht);
}
};
$logger->setLogLevel('DEBUG');
$logger->logWithTimestamp("Anwendung gestartet");Anonyme Klassen eignen sich gut als komplexe Callbacks, besonders wenn mehrere Methoden oder Zustände benötigt werden:
$daten = [5, 1, 9, 3, 7];
// Sortieren mit einer anonymen Klasse als Callback
usort($daten, new class {
private bool $aufsteigend = true;
public function __invoke(int $a, int $b): int {
return $this->aufsteigend ? $a <=> $b : $b <=> $a;
}
});
print_r($daten); // Ausgabe: [1, 3, 5, 7, 9]Anonyme Klassen funktionieren nahtlos mit Type Hints zusammen, indem sie Interfaces implementieren:
interface DataProcessor {
public function process(array $daten): array;
}
function verarbeiteUndFiltere(DataProcessor $processor, array $daten): array {
$verarbeitet = $processor->process($daten);
return array_filter($verarbeitet, fn($item) => $item > 0);
}
$result = verarbeiteUndFiltere(
new class implements DataProcessor {
public function process(array $daten): array {
return array_map(fn($item) => $item * 2 - 5, $daten);
}
},
[1, 2, 3, 4, 5]
);
print_r($result); // Ausgabe: [1 => -1, 2 => 1, 3 => 3, 4 => 5]Intern werden anonyme Klassen mit einem automatisch generierten Namen versehen. Dieser Name wird für jeden anonymen Klassenblock im Quellcode einmalig generiert:
$class1 = new class {};
$class2 = new class {};
echo get_class($class1) . "\n"; // Ausgabe: class@anonymous/file.php:0x123456
echo get_class($class2) . "\n"; // Ausgabe: class@anonymous/file.php:0x789abcBezüglich der Performance gibt es keinen signifikanten Unterschied zwischen anonymen und benannten Klassen. Beide werden zur Laufzeit geladen und verarbeitet. Der Hauptunterschied liegt in der Lesbarkeit und Organisation des Codes.
Ein typisches Anwendungsbeispiel für anonyme Klassen sind Event Listener in einem Event-System:
interface EventListener {
public function handle(array $eventData): void;
}
class EventDispatcher {
private array $listeners = [];
public function addListener(string $event, EventListener $listener): void {
$this->listeners[$event][] = $listener;
}
public function dispatch(string $event, array $data = []): void {
if (!isset($this->listeners[$event])) {
return;
}
foreach ($this->listeners[$event] as $listener) {
$listener->handle($data);
}
}
}
// Verwendung des Event-Systems mit anonymen Klassen
$dispatcher = new EventDispatcher();
// Füge einen Logger-Listener hinzu
$dispatcher->addListener('user.login', new class implements EventListener {
public function handle(array $eventData): void {
echo "LOGIN: Benutzer {$eventData['username']} hat sich angemeldet\n";
}
});
// Füge einen Statistik-Listener hinzu
$dispatcher->addListener('user.login', new class implements EventListener {
private array $logins = [];
public function handle(array $eventData): void {
$this->logins[] = [
'username' => $eventData['username'],
'time' => time()
];
echo "STATS: {$eventData['username']} ist der " . count($this->logins) . ". Login\n";
}
});
// Dispatche ein Event
$dispatcher->dispatch('user.login', [
'username' => 'max.mustermann',
'ip' => '192.168.1.1'
]);Anonyme Klassen eignen sich hervorragend für die Implementierung des Strategiemusters, besonders wenn die Strategien nur an einer Stelle verwendet werden:
interface ZahlungsStrategie {
public function bezahlen(float $betrag): bool;
}
class Bestellung {
private array $produkte = [];
private ?ZahlungsStrategie $zahlungsStrategie = null;
public function addProdukt(string $name, float $preis, int $menge = 1): void {
$this->produkte[] = [
'name' => $name,
'preis' => $preis,
'menge' => $menge
];
}
public function setZahlungsStrategie(ZahlungsStrategie $strategie): void {
$this->zahlungsStrategie = $strategie;
}
public function getGesamtbetrag(): float {
$summe = 0;
foreach ($this->produkte as $produkt) {
$summe += $produkt['preis'] * $produkt['menge'];
}
return $summe;
}
public function bezahlen(): bool {
if ($this->zahlungsStrategie === null) {
throw new RuntimeException("Keine Zahlungsstrategie festgelegt");
}
$betrag = $this->getGesamtbetrag();
return $this->zahlungsStrategie->bezahlen($betrag);
}
}
// Verwendung
$bestellung = new Bestellung();
$bestellung->addProdukt("PHP-Buch", 29.99);
$bestellung->addProdukt("USB-Stick", 9.99, 2);
// Kreditkartenzahlung mit anonymer Klasse
$bestellung->setZahlungsStrategie(new class implements ZahlungsStrategie {
private string $kartenNummer = '1234-5678-9012-3456';
private string $kartenInhaber = 'Max Mustermann';
public function bezahlen(float $betrag): bool {
echo "Zahle {$betrag}€ mit Kreditkarte ({$this->kartenNummer})\n";
// In einer realen Anwendung würde hier die Zahlungsabwicklung erfolgen
return true;
}
});
$bestellung->bezahlen();
// Alternative Zahlungsmethode: PayPal
$bestellung->setZahlungsStrategie(new class implements ZahlungsStrategie {
private string $email = 'max.mustermann@example.com';
public function bezahlen(float $betrag): bool {
echo "Zahle {$betrag}€ mit PayPal ({$this->email})\n";
// PayPal-Zahlungsabwicklung
return true;
}
});
$bestellung->bezahlen();Für die effektive Nutzung anonymer Klassen sollten folgende Best Practices beachtet werden:
Einfach halten: Verwenden Sie anonyme Klassen für einfache, einmalige Implementierungen. Komplexere Klassen sollten benannt werden.
Interface-Implementierung: Kombinieren Sie anonyme Klassen mit Interfaces, um klare Verträge zu definieren.
Kleine Schnittstellen: Anonyme Klassen eignen sich besonders gut für Interfaces mit wenigen Methoden.
Fokus auf spezifische Aufgaben: Jede anonyme Klasse sollte eine klar definierte, einzelne Verantwortung haben.
Vermeiden von Duplizierung: Wenn Sie die gleiche anonyme Klasse an mehreren Stellen verwenden, ist es besser, eine benannte Klasse zu erstellen.