Menu
Coddy logo textTech

Repository-Muster

Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy. Lektion 81 von 91.

Das Repository Pattern ist ein Entwurfsmuster, das zwischen der Geschäftslogik deiner Anwendung und der Datenspeicherung vermittelt. Es stellt eine sammlungsähnliche Schnittstelle für den Zugriff auf Domänenobjekte bereit und verbirgt die Details darüber, wie Daten tatsächlich gespeichert oder abgerufen werden.

Stell dir ein Repository als eine spezialisierte Sammlung vor, die weiß, wie Objekte dauerhaft gespeichert und abgerufen werden. Dein Anwendungscode fragt das Repository nach einem Benutzer anhand seiner ID oder speichert ein neues Produkt, ohne zu wissen, ob sich die Daten in einer Datenbank, einer Datei oder einer API befinden. Diese Trennung macht deinen Code besser testbar und flexibler.

<?php
interface UserRepositoryInterface {
    public function find(int $id): ?User;
    public function findAll(): array;
    public function save(User $user): void;
    public function delete(int $id): void;
}

class User {
    public function __construct(
        public int $id,
        public string $name,
        public string $email
    ) {}
}

Die Repository-Implementierung übernimmt den eigentlichen Speichermechanismus:

<?php
class InMemoryUserRepository implements UserRepositoryInterface {
    private array $users = [];
    
    public function find(int $id): ?User {
        return $this->users[$id] ?? null;
    }
    
    public function findAll(): array {
        return array_values($this->users);
    }
    
    public function save(User $user): void {
        $this->users[$user->id] = $user;
    }
    
    public function delete(int $id): void {
        unset($this->users[$id]);
    }
}

$repo = new InMemoryUserRepository();
$repo->save(new User(1, "Alice", "alice@example.com"));
$repo->save(new User(2, "Bob", "bob@example.com"));

echo $repo->find(1)->name . "\n";
echo count($repo->findAll());

Ausgabe:

Alice
2

Das Schöne an diesem Muster ist, dass du Implementierungen austauschen kannst, ohne deine Geschäftslogik zu ändern. Musst du von der In-Memory-Speicherung zu einer Datenbank wechseln? Erstelle eine neue Repository-Klasse, die dieselbe Schnittstelle implementiert. Dein Anwendungscode bleibt unverändert, weil er von der Schnittstelle und nicht von der konkreten Implementierung abhängt.

challenge icon

Aufgabe

Einfach

Erstellen wir ein Produktinventarsystem unter Verwendung des Repository-Musters. Du wirst eine klare Trennung zwischen deinen Domänenobjekten und ihrer Speicherung schaffen, sodass dein Anwendungscode mit Produkten arbeiten kann, ohne die Details der Speicherung zu kennen.

Du wirst deinen Code auf vier Dateien verteilen:

  • Product.php: Erstelle eine Product-Klasse, die die Artikel in deinem Inventar repräsentiert. Jedes Produkt hat eine id (int), einen name (string) und einen price (float). Verwende Konstruktor-Promotion mit öffentlichen Eigenschaften für einen einfachen Zugriff.
  • ProductRepositoryInterface.php: Definiere ein ProductRepositoryInterface, das den Vertrag für jede Implementierung der Produktspeicherung festlegt. Deine Schnittstelle sollte diese Methoden deklarieren:
    • find(int $id): ?Product: Ruft ein Produkt anhand seiner ID ab oder gibt null zurück, wenn es nicht gefunden wurde
    • findAll(): array: Ruft alle Produkte als Array ab
    • save(Product $product): void: Speichert ein Produkt oder aktualisiert es
    • delete(int $id): void: Entfernt ein Produkt anhand seiner ID
  • InMemoryProductRepository.php: Binde sowohl die Product-Klasse als auch die Schnittstelle ein. Erstelle eine InMemoryProductRepository-Klasse, die die Schnittstelle implementiert und ein privates Array zum Speichern der Produkte verwendet. Produkte sollten für eine effiziente Suche nach ihrer ID indiziert werden. Die Methode findAll() sollte nur die Produktobjekte zurückgeben (verwende array_values(), um die Array-Schlüssel zurückzusetzen).
  • main.php: Binde die Repository-Datei ein. Du erhältst zwei Eingaben: zuerst eine JSON-Zeichenfolge mit hinzuzufügenden Produkten und anschließend in einer separaten Zeile die ganzzahlige ID, nach der gesucht werden soll.

    Das JSON-Format lautet:

    [{"id": 1, "name": "Laptop", "price": 999.99}, {"id": 2, "name": "Mouse", "price": 29.99}]

    Erstelle ein InMemoryProductRepository, speichere alle Produkte aus der JSON-Eingabe und verwende anschließend die zweite Eingabe (die ID), um ein bestimmtes Produkt zu finden. Gib die Ergebnisse in diesem Format aus:

    Total products: [count]
    Found: [name] - $[price]

    Formatiere den Preis mit zwei Nachkommastellen. Wenn das Produkt nicht gefunden wird, gib stattdessen Found: Not found aus.

Das Repository-Muster zeigt seine Stärken, wenn du die Speicherimplementierungen austauschen musst. Dein Hauptcode hängt nur von der Schnittstelle ab: Der Wechsel von einem In-Memory-Speicher zu einer Datenbank würde bedeuten, eine neue Repository-Klasse zu erstellen, ohne die Anwendungslogik zu ändern.

Probier es selbst

<?php

require_once 'InMemoryProductRepository.php';

// Eingabe lesen
$jsonInput = trim(fgets(STDIN));
$searchId = intval(trim(fgets(STDIN)));

// Die JSON-Eingabe in ein Array parsen
$productsData = (array)json_decode($jsonInput, true);

// TODO: Eine InMemoryProductRepository-Instanz erstellen

// TODO: Durch $productsData iterieren und jedes Produkt speichern
// Jedes Element hat die Schlüssel 'id', 'name' und 'price'

// TODO: Alle Produkte abrufen und die Gesamtanzahl ausgeben
// Format: "Total products: [count]"

// TODO: Das Produkt mit $searchId finden
// Wenn gefunden, ausgeben: "Found: [name] - $[price]" (Preis auf 2 Dezimalstellen formatiert)
// If not found, print: "Found: Not found"

?>
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-PHP-Compiler