Klassen und Objekte

In der objektorientierten Programmierung entspricht die Klasse dem gesuchten Konstrukt für das Zusammenfassen von Daten und Operationen in einer Einheit. In der Fachsprache der Objektorientierung nennt man die Daten die Instanzvariablen und die Operationen die Methoden der Klasse.

Eine Klasse dient als Bauplan für die Erzeugung von Objekten während der Laufzeit eines objektorientierten Programmes. Dieses besteht aus einem dynamischen Geflecht solcher Objekte.

Dieses Zusammenfassen von Daten und Operationen in einer Einheit wird Kapselung genannt und bildet die Grundlage der objektorientierten Programmierung.

Mit diesem Geheimnisprinzip wird die Trennung von Nutzungs- und Implementierungsschicht, von Realisierung und Nutzung verfolgt: Ein Entwickler, der eine Klasse eines anderen Entwicklers verwenden möchte, braucht die internen Abläufe der Klasse nicht zu kennen, er verwendet nur die vereinbarte Schnittstelle.

Zu diesem Zweck wird den Instanzvariablen und Methoden einer Klasse bei ihrer Deklaration eine von drei möglichen Zugreifbarkeiten zugewiesen:

Wird keines der drei Schlüsselwörter private, protected und public bei der Deklaration einer Instanzvariablen beziehungsweise einer Methode angegeben, so wird implizit die allgemeine Zugreifbarkeit (public) angenommen.

Nicht verwechseln sollte man das Geheimnisprinzip mit einem Sicherheitskonzept im Sinne einer Zugriffskontrolle, die sicherstellt, dass nur berechtigte Objekte auf bestimmte Instanzvariablen und Methoden zugreifen dürfen. Dies ist hier nicht gemeint. Vielmehr sollen für die Verwendung der Klasse unwesentliche Details vor dem Verwender der Klasse verborgen werden, wie beispielsweise die Verwaltung von Ressourcen. Es geht nicht darum, dass er diese Details nicht wissen darf, sondern er braucht sie nicht zu wissen. Dies erlaubt es dem Programmierer einer Klasse, Implementierungsdetails zu ändern, ohne dass der Verwender der Klasse Änderungen an seinem Code vornehmen muss. Die Deklaration einer Methode als public kommt somit einer Festlegung gleich, während die Implementierung von als protected oder private deklarierten Methoden in einer späteren Version oder Unterklasse (siehe „Vererbung“) geändert werden kann.

Die Syntax für die Deklaration von Klassen, Instanzvariablen und Methoden betrachten wir in diesem Kapitel am Beispiel einer Klasse für den Zugriff auf eine MySQL-Datenbank. Die Minimalfunktionalität, die wir von einer solchen Klasse erwarten, umfasst Methoden für den Auf- und Abbau einer Verbindung zum Datenbankserver sowie Methoden für die Ausführung von Anfragen und die Verarbeitung von Ergebniszeilen, die von einer Anfrage geliefert werden.

Um die Struktur von Klassen, die Interaktionen zwischen Objekten oder die Abläufe innerhalb einer Methode zu illustrieren, verwenden wir Diagramme in der Notation der Unified Modeling Language (UML).

Eine Klasse wird in UML beispielsweise als Rechteck dargestellt, das durch horizontale Linien in drei Bereiche aufgeteilt ist. Der obere Bereich beinhaltet neben dem Klassennamen (fett) optionale Informationen, beispielsweise über die Paketzugehörigkeit der Klasse. Die beiden anderen Bereiche sind den Instanzvariablen und Methoden der Klasse vorbehalten. Die Zugreifbarkeit von Instanzvariablen und Methoden wird durch Voranstellen von + (public), # (protected) und - (private) ausgedrückt. Abbildung 1.1 zeigt ein UML-Klassendiagramm für unser Beispiel.

Abbildung 1.1. Eine Klasse für den Zugriff auf eine MySQL-Datenbank

Eine Klasse für den Zugriff auf eine MySQL-Datenbank


Die Implementierung dieser Klasse in PHP zeigt Beispiel 1.2. Das Beispiel verwendet die Pseudovariable $this, die wir im Abschnitt über Referenzen genauer betrachten werden. Die Verwendung der Klasse wird in Beispiel 1.3 demonstriert.

Beispiel 1.2: Eine Klasse für den Zugriff auf eine MySQL-Datenbank

<?php
class DB_MySQL {
  private $connection = NULL;
  private $result = NULL;
 
  public function connect($host, $database, $user, $pass) {
    $this->connection = mysql_connect(
      $host,
      $user,
      $pass,
      TRUE
    );
 
    mysql_select_db($database, $this->connection);
  }
 
  public function disconnect() {
    if (is_resource($this->connection)) {
      mysql_close($this->connection);
    }
  }
 
  public function query($query) {
    if (is_resource($this->connection)) {
      if (is_resource($this->result)) {
        mysql_free_result($this->result);
      }
 
      $this->result = mysql_query(
        $query,
        $this->connection
      );
    }
  }
 
  public function fetchRow() {
    if (is_resource($this->result)) {
      $row = mysql_fetch_assoc($this->result);
 
      if (is_array($row)) {
        return $row;
      } else {
        return FALSE;
      }
    }
  }
}
?>


Beispiel 1.3: Verwendung der MySQL-Klasse

<?php
require_once 'DB_MySQL.php';
 
$mysql = new DB_MySQL;
$mysql->connect('localhost', 'test', 'root', '');
$mysql->query('SELECT spalte FROM tabelle');
 
while ($row = $mysql->fetchRow()) {
  // ...
}
 
$mysql->disconnect();
?>


Bei der Deklaration von Methoden erlaubt PHP die Angabe eines Klassen- oder Schnittstellennamens für als Parameter übergebene Objekte. Im Gegensatz zu statisch getypten Programmiersprachen erfolgt die Typprüfung jedoch nicht zum Zeitpunkt der Kompilierung, sondern erst zur Laufzeit. Diese so genannten Type Hints ersparen dem Programmierer Schreibarbeit, wie an Beispiel 1.4 und Beispiel 1.5 zu erkennen ist.

Beispiel 1.4: Typprüfung mit Type Hints

<?php
class Vector {
  public function add(Vector $vector) {
    // ...
  }
}
?>


Beispiel 1.5: Typprüfung mit dem instanceof-Operator

<?php
class Vector {
  public function add($vector) {
    if (!($vector instanceof Vector)) {
      die('Parameter muss vom Typ Vector sein.');
    }
 
    // ...
  }
}
?>


Beispiel 1.4 und Beispiel 1.5 sind semantisch äquivalent und unterscheiden sich nur in der Art der Typprüfung durch die Type Hints beziehungsweise den instanceof-Operator.