15.03.2025

Objektorientierte Programmierung mit PHP Teil 1 - Die vier OOP-Säulen

Stell dir vor, du baust ein Haus. Ohne eine stabile Grundlage wird es wackelig, schwer erweiterbar und anfällig für Fehler. Genau so verhält es sich mit Code und hier kommen die 4 Säulen der objektorientierten Programmierung (OOP) ins Spiel. Sie sind die Basis für sauberen, wiederverwendbaren und skalierbaren Code.

PHP bietet dir alle Werkzeuge, um diese Prinzipien optimal umzusetzen und robuste Software zu entwickeln, die nicht nur funktioniert, sondern auch elegant und wartbar bleibt.

INHALTSVERZEICHNIS:

1.- Die vier OOP-Säulen

  1. Kapselung (Encapsulation)
  2. Vererbung (Inheritance)
  3. Polymorphie (Polymorphism)
  4. Abstraktion (Abstraction)

Was ist Objektorientierte Programmierung?

Objektorientierte Programmierung (OOP) ist ein Programmierparadigma, das auf dem Konzept von Objekten basiert – also Strukturen, die in der Regel einen Bezug zu realen Objekten haben. Ein Auto, ein Benutzerkonto oder ein Produkt in einem Onlineshop – all das sind Beispiele für Objekte, die in der Programmierung modelliert werden können. Jedes Objekt vereint Daten (Eigenschaften) und Methoden (Funktionen), mit denen es interagiert.

1.- Kapselung (Encapsulation)

Encapsulation beschreibt das Prinzip, dass Daten und Methoden innerhalb eines Objekts verborgen und nur kontrolliert nach außen zugänglich gemacht werden.

Wie funktioniert Encapsulation?

Encapsulation wird durch Zugriffsmodifikatoren umgesetzt, die steuern, welche Teile des Codes auf Eigenschaften (Variablen) und Methoden einer Klasse zugreifen können. Diese Modifikatoren helfen, sensible Daten zu schützen und stellen sicher, dass Änderungen nur über klar definierte Schnittstellen erfolgen.

Warum ist Encapsulation wichtig?

  • Schutz der Daten
    Verhindert, dass andere Teile des Programms direkt auf interne Daten zugreifen oder diese verändern.
  • Flexibilität
    Änderungen an der internen Implementierung sind möglich, ohne dass andere Teile des Codes angepasst werden müssen.
  • Fehlervermeidung
    Reduziert das Risiko unerwarteter Seiteneffekte durch unkontrollierte Änderungen.

 

In PHP gibt es drei Haupt-Zugriffsmodifikatoren:

// Die Variable ist nicht direkt von außen zugänglich
private $cantBeReachedOutside;

// Sollte nur innerhalb der Klasse und Unterklassen genutzt werden
protected $canBeReachedInSubClasses;

// Die Variable ist frei zugänglich
public $callMeFromWhereEverYouWant;

Beispiel: private vs. protected

<?php

class Bankkonto {
    private $kontostand = 0; // Direkter Zugriff von außen NICHT erlaubt
    protected $transaktionsHistorie = []; // Für Unterklassen sichtbar

    public function einzahlen($betrag) {
        if ($betrag > 0) {
            $this->kontostand += $betrag;
            $this->transaktionsHistorie[] = "Einzahlung: +{$betrag}€";
            echo "Eingezahlt: {$betrag}€. Neuer Kontostand: {$this->kontostand}€.<br>";
        } else {
            echo "Ungültiger Einzahlungsbetrag.<br>";
        }
    }

    public function abheben($betrag) {
        if ($betrag > 0 && $betrag <= $this->kontostand) {
            $this->kontostand -= $betrag;
            $this->transaktionsHistorie[] = "Abhebung: -{$betrag}€";
            echo "Abgehoben: {$betrag}€. Neuer Kontostand: {$this->kontostand}€.<br>";
        } else {
            echo "Nicht genügend Guthaben oder ungültiger Betrag.<br>";
        }
    }

    public function zeigeKontostand() {
        return "Aktueller Kontostand: {$this->kontostand}€";
    }
}

class Sparkonto extends Bankkonto {
    public function zeigeTransaktionen() {
        echo "Transaktionshistorie:<br>";
        foreach ($this->transaktionsHistorie as $transaktion) {
            echo "- {$transaktion}<br>";
        }
    }
}

 

// Konto erstellen
$konto = new Sparkonto();

// Einzahlungen und Abhebungen
$konto->einzahlen(100);
$konto->abheben(30);

// Kontostand anzeigen
echo $konto->zeigeKontostand() . "<br>";

// Transaktionshistorie anzeigen (geht nur in der Unterklasse)
$konto->zeigeTransaktionen();

// Direkter Zugriff auf private/protected Werte NICHT erlaubt:
echo $konto->kontostand; // FEHLER!
echo $konto->transaktionsHistorie; // FEHLER!

 

?>
 

Was passiert hier?

private $kontostand

  • Der Kontostand kann nicht direkt von außen oder von Unterklassen manipuliert werden.
  • Zugriff erfolgt nur über die Methoden einzahlen(), abheben() und zeigeKontostand().

protected $transaktionsHistorie

  • Die Transaktionshistorie ist nicht von außen sichtbar, aber eine Unterklasse (Sparkonto) kann darauf zugreifen.
  • Dadurch kann zeigeTransaktionen() die Historie anzeigen, ohne die Datenstruktur nach außen offenzulegen.

Fazit:

  • Nutze private für sensible Daten, die nicht manipuliert werden sollen.
  • Nutze protected wenn Unterklassen Zugriff haben dürfen, aber die Daten nicht öffentlich sein sollen.
  • Nutze public wenn eine Methode oder Eigenschaft von außen zugänglich sein soll (z.B. ein Getter oder eine Funktion zum Einzahlen auf ein Konto).

2.- Vererbung (Inheritance)

Vererbung ist ein Konzept in OOP, bei dem eine Unterklasse (Kindklasse) die Eigenschaften und Methoden einer Oberklasse (Elternklasse) erbt. Dadurch wird Code wiederverwendbar, duplizierte Programmierung vermieden und die Wartbarkeit des Codes verbessert. Vor allem ermöglicht es dir, eine saubere und modulare Codebasis zu schaffen, die leicht erweitert und angepasst werden kann.

In PHP wird Vererbung mit dem Schlüsselwort extends umgesetzt:

class Elternklasse {
    // Eigenschaften und Methoden, die von Unterklassen geerbt werden können
}

// Nun erstellen wir eine neue Klasse auf der Basis der Elternklasse, übernehmen dessen Variablen und Funktionen und haben nun die Möglichkeit diese nach belieben zu erweitern

class Kindklasse extends Elternklasse {
    // Zusätzliche Eigenschaften oder Methoden, die nur in der Kindklasse existieren
}
 

Beispiel: Fahrzeuge & Autos

Auch wenn Steuergeräte normalerweise nicht in PHP programmiert werden, bauen wir hier trotzdem eine Steuergeräte-Klasse – schließlich ist es eine großartige Möglichkeit, die Magie der Vererbung zu zeigen, und wer will schon auf ein bisschen Spaß mit PHP verzichten?

Aufgabe
Die Elternklasse soll haben allgemeine Funktionen für Fahrzeuge. Für einen sehr besonderen Fahrzeugtypen soll eine Erweiterung der Funktionalität des Steuergerätes ermöglicht werden.
Diese Klasse nennen wir Mercedes-amg-Klasse, die von der Elternklasse Steuergerät erbt und wundervolle nahezu atemberaubende zusätzliche Funktionen bereit stellen soll.

 

Steuergerät (Elternklasse)

  • Enthält Grundfunktionen für jedes moderne Fahrzeug:
    • einschalten(): Das Steuergerät startet das Fahrzeug.
    • ausschalten(): Das Steuergerät fährt das Fahrzeug herunter.
    • setModus($modus): Wechselt zwischen verschiedenen Fahrmodi (z. B. "Komfort", "Sport", "Race").

 

MercedesAMG (Erweiterte Klasse)

  • Fügt atemberaubende AMG-Funktionen hinzu:
    • aktivierenLaunchControl(): Aktiviert die Launch Control für maximale Beschleunigung.
    • aktivierenDriftModus(): Schaltet das Fahrzeug in den Drift-Modus für ultimativen Fahrspaß.
    • turboBoost(): Erhöht kurzfristig die Leistung für mehr Geschwindigkeit.
       

<?php

// Basisklasse: Allgemeines Steuergerät für Fahrzeuge
class Steuergeraet {
    protected $status = "Aus"; 
    protected $modus = "Komfort";

    public function einschalten() {
        $this->status = "An";
        echo "Steuergerät aktiviert. Fahrzeug ist jetzt eingeschaltet!<br>";
    }

    public function ausschalten() {
        $this->status = "Aus";
        echo "Fahrzeug wird heruntergefahren...<br>";
    }

    public function setModus($modus) {
        $moeglicheModi = ["Komfort", "Sport", "Race"];
        if (in_array($modus, $moeglicheModi)) {
            $this->modus = $modus;
            echo "Fahrmodus auf '{$modus}' gewechselt.<br>";
        } else {
            echo "Ungültiger Fahrmodus! Wähle zwischen: Komfort, Sport, Race.<br>";
        }
    }
}

// Abgeleitete Klasse: Mercedes-AMG mit Premium-Funktionen
class MercedesAMG extends Steuergeraet {
    private $turboAktiviert = false;

    public function aktivierenLaunchControl() {
        if ($this->status === "An") {
            echo "LAUNCH CONTROL AKTIVIERT! Maximale Beschleunigung in 3...2...1..<br>";
        } else {
            echo "Fahrzeug ist aus! Bitte zuerst einschalten.<br>";
        }
    }

    public function aktivierenDriftModus() {
        if ($this->status === "An" && $this->modus === "Race") {
            echo "DRIFT MODUS AKTIV! Bereit für epische Drifts!<br>";
        } else {
            echo "Drift-Modus kann nur im 'Race'-Modus aktiviert werden.<br>";
        }
    }

    public function turboBoost() {
        if ($this->status === "An") {
            $this->turboAktiviert = true;
            echo  "TURBO BOOST aktiviert! Spüre die volle AMG-Power!<br>";
        } else {
            echo "Turbo Boost kann nur aktiviert werden, wenn das Fahrzeug an ist.<br>";
        }
    }
}

// --- DEMO ---

$amg = new MercedesAMG();

$amg->einschalten();   // Fahrzeug einschalten
$amg->setModus("Sport");   // Sportmodus aktivieren
$amg->aktivierenLaunchControl();   // Launch Control aktivieren
$amg->setModus("Race");   // Race-Modus aktivieren
$amg->aktivierenDriftModus();   // Drift-Modus aktivieren
$amg->turboBoost();   // Turbo Boost aktivieren
$amg->ausschalten();   // Fahrzeug ausschalten

?>
 

3.- Polymorphie (Polymorphism)

Polymorphie ist ein weiteres zentrales Konzept der objektorientierten Programmierung (OOP). Der Begriff kommt aus dem Griechischen und bedeutet so viel wie „viel Gestalt“ oder „viel Form“. In der OOP bedeutet Polymorphie, dass eine Methode in unterschiedlichen Klassen gleich benannt sein kann, aber unterschiedliches Verhalten aufweist – je nachdem, auf welchem Objekttyp sie aufgerufen wird.

 

Wie funktioniert Polymorphie?

Polymorphie ermöglicht es, dass eine Methode, die in einer Elternklasse definiert wurde, von Kindklassen überschrieben (Overriding) oder überladen (Overloading) wird, um ein spezifisches Verhalten zu erzielen.

1. Überschreiben (Overriding)

Eine Methode der Elternklasse wird in der Kindklasse neu definiert und erhält ein anderes Verhalten. Dies wird oft verwendet, wenn du spezifische Implementierungen für verschiedene Kindklassen benötigst.

2. Überladen (Overloading)

Dies bezieht sich auf das Erstellen von Methoden mit dem gleichen Namen, aber mit unterschiedlichen Parametern. Allerdings unterstützt PHP das Überladen von Methoden nicht direkt. In anderen Programmiersprachen wie Java oder C# ist dies üblicher.
 

Warum ist Polymorphie wichtig?

Polymorphie trägt zur Flexibilität und Erweiterbarkeit des Codes bei. Durch Polymorphie kannst du mit Methoden arbeiten, die auf verschiedene Arten und Weisen arbeiten, je nachdem, welche Klasse die Methode aufruft. Das sorgt für mehr Wiederverwendbarkeit und Lesbarkeit.

 

Das Viecher Beispiel

Angenommen, wir haben eine Kindklasse Tier, die eine Methode geraeuschMachen() enthält.

Verschiedene Tierarten (z. B. Hund und Katze) überschreiben diese Methode, um spezifische Geräusche zu erzeugen:

<?php

// Elternklasse
class Tier {
    public function geraeuschMachen() {
        echo "Ein Geräusch wird gemacht.<br>";
    }
}

// Kindklasse Hund
class Hund extends Tier {
    public function geraeuschMachen() {
        echo "Der Hund bellt: Wuff! Wuff! <br>";
    }
}

// Kindklasse Katze
class Katze extends Tier {
    public function geraeuschMachen() {
        echo "Die Katze miaut: Miau! Miau! <br>";
    }
}

// Funktion zur Demonstration der Polymorphie
function tierGeraeusch(Tier $tier) {
    $tier->geraeuschMachen();
}

// Objekte erstellen
$hund = new Hund();
$katze = new Katze();

// Die gleiche Methode aufrufen, aber das Verhalten hängt vom Objekttyp ab
tierGeraeusch($hund);  // Gibt "Der Hund bellt: Wuff! Wuff!" aus
tierGeraeusch($katze); // Gibt "Die Katze miaut: Miau! Miau!" aus

?>
 

4.- Abstraktion (Abstraction)

Abstraktion dient dazu, komplexe Details zu verbergen und nur die relevanten Informationen eines Objekts sichtbar zu machen. Es geht darum, unnötige Details aus der Sicht des Benutzers oder Entwicklers zu verstecken, während nur die wesentlichen Merkmale und Verhaltensweisen des Objekts dargestellt werden.

 

Ziel der Abstraktion:

  • Komplexität reduzieren: Indem wir nur die wesentlichen Merkmale eines Objekts zeigen und die weniger wichtigen Details verstecken, wird der Umgang mit dem Objekt einfacher und verständlicher.
  • Flexibilität erhöhen: Abstraktion ermöglicht es, die interne Implementierung zu ändern, ohne dass der Benutzer des Objekts etwas davon merkt, solange die öffentliche Schnittstelle gleich bleibt.

 

Wie funktioniert Abstraktion?

Abstraktion wird in der OOP auf zwei Arten umgesetzt:

  1. Abstrakte Klassen: Eine Klasse, die abstrakte Methoden enthält, also Methoden, die nur als Platzhalter dienen und keine Implementierung haben. Diese Methoden müssen in den abgeleiteten (Unter-)Klassen implementiert werden.
  2. Schnittstellen (Interfaces): Ein Vertrag, der die Methoden definiert, die eine Klasse implementieren muss. Eine Schnittstelle selbst enthält keine Implementierungen der Methoden, sondern nur die Methodensignaturen.

 

Beispiel zur Abstraktion:

Angenommen, wir haben eine abstrakte Klasse Fahrzeug, die allgemeine Methoden wie fahren() und stopp() definiert. Die genauen Implementierungen dieser Methoden können je nach Fahrzeugtyp unterschiedlich sein, aber die Schnittstelle bleibt für alle Fahrzeugtypen gleich.

<?php

// Abstrakte Klasse
abstract class Fahrzeug {
    // Abstrakte Methode (muss in jeder Unterklasse implementiert werden)
    abstract public function fahren();
    abstract public function stopp();
}

// Unterklasse - Auto
class Auto extends Fahrzeug {
    public function fahren() {
        echo "Das Auto fährt auf der Straße.<br>";
    }

    public function stopp() {
        echo "Das Auto hält an.<br>";
    }
}

// Unterklasse - Fahrrad
class Fahrrad extends Fahrzeug {
    public function fahren() {
        echo "Das Fahrrad fährt auf dem Radweg.<br>";
    }

    public function stopp() {
        echo "Das Fahrrad stoppt an der Ampel.<br>";
    }
}

// Objekte erstellen
$meinAuto = new Auto();
$meinFahrrad = new Fahrrad();

// Methoden aufrufen
$meinAuto->fahren();  // Ausgabe: Das Auto fährt auf der Straße.
$meinFahrrad->fahren(); // Ausgabe: Das Fahrrad fährt auf dem Radweg.

?>
 

Erklärung des Beispiels:

  1. Abstrakte Klasse Fahrzeug:
    • Definiert die Methoden fahren() und stopp(), aber ohne eine Implementierung. Diese Methoden sind abstrakt, was bedeutet, dass sie in den abgeleiteten Klassen implementiert werden müssen.
  2. Unterklassen Auto und Fahrrad:
    • Beide Klassen erben von Fahrzeug und müssen die abstrakten Methoden fahren() und stopp() implementieren, aber mit unterschiedlichen Implementierungen, die spezifisch für das jeweilige Fahrzeug sind.

Warum ist Abstraktion wichtig?

  • Verbergen von Details: Als Entwickler musst du nicht jedes Mal den gesamten Code verstehen, wenn du mit einem Auto oder Fahrrad arbeitest. Du interagierst nur mit den relevanten Methoden (wie fahren() und stopp()).
  • Erhöhte Wartbarkeit: Änderungen an der Implementierung der spezifischen Fahrzeugarten (z. B. Auto oder Fahrrad) haben keine Auswirkungen auf die Benutzer, die mit der Abstraktion arbeiten.
  • Erweiterbarkeit: Wenn du neue Fahrzeugarten hinzufügst, kannst du einfach neue Klassen erstellen, die von Fahrzeug erben und die abstrakten Methoden implementieren, ohne die bestehende Architektur zu ändern.

Fazit:

Abstraktion ist ein mächtiges Werkzeug in der objektorientierten Programmierung, das es ermöglicht, den Fokus auf die wesentlichen Aspekte eines Objekts zu legen, während die komplexen Details verborgen bleiben. Dadurch wird der Code flexibler, verständlicher und erweiterbar.

Write comment

* These fields are required

Comments

No Comments