Home
Navigation
Impressum
Coder Welten - Programmierung und Optimierung
Coder Welten
 
 

 

 

OOP: Von Konstruktoren und Destruktoren

Spezielle Methoden zum Erzeugen und Auflösen

Übersicht / Seite:

  1. Einführung (in die objektorientierte Programmierung)
  2. Sichtbarkeit (und Kapselung von Eigenschaften und Methoden)
  3. Vererbung (von Eigenschaften und Methoden sowie Autoload von Klassen)
  4. Konstruktoren und Destruktoren (Methoden zum Erzeugen und Auflösen)

    4.1 Konstruktoren und D... (Besonderheiten bei der Vererbung)
    4.2 Praktischer Einsatz (von Konstruktoren und Destruktoren)

  5. Beispiele (eine simple Parserklasse, eine TCP/IP Socket Klasse und mehr ...)

Konstruktoren

In den bisherigen Beispiel-Klassen wurden alle Methoden mit einem Bezeichner deklariert und definiert. Doch es geht auch mit Konstruktoren. Bei einem Konstruktor handelt es sich um eine Magische Methode, die beim Erzeugen und Instanziieren eines neuen Objektes automatisch mit der Klasse aufgerufen wird. Beachtenswert dabei ist, dass Konstruktormethoden keinen funktionstypischen Rückgabewert liefern.
Zum leichteren Verständnis nachfolgend einige Beispiele als kleine Gegenüber-stellung, einmal mit definierten Methoden und einmal mit Konstruktoren.

Erstes Beispiel mit einer definierten Methode (klasse-08a.php):

<?php

class ErsteTestKlasse {

    private $rueckgabe = "Schuster";

    public function testeMethode() {

        $this->rueckgabe = "Ergebnis für ".$this->rueckgabe;
        return $this->rueckgabe;
   }
}

$obj = new ErsteTestKlasse();
echo $obj->testeMethode()."n";

// Ausgabe: Ergebnis für Schuster 

Wie aus dem ersten Beispiel ersichtlich wird, so wird beim Aufruf der ersten Test-Klasse innerhalb der Methode ein Wert mit dem Sprachkonstrukt return zurückgegeben. Nach der Erzeugung eines Objektes kann die Ausgabe über einen Aufruf der Methode erfolgen.

Zweites Beispiel mit einer Konstruktormethode (klasse-08b.php):

?>

<?php

class ZweiteTestKlasse {

    public $rueckgabe = "Bäcker";

    public function __construct() {

        $this->rueckgabe = "Ergebnis für ".$this->rueckgabe;
   }
}

$obj = new ZweiteTestKlasse();
echo $obj->rueckgabe."n";

// Ausgabe: Ergebnis für Bäcker 

?>

Etwas anders sieht es im zweiten Beispiel bei Verwendung einer Konstruktor­methode aus. Das Sprachkonstrukt return würde hier versagen und ein Bezeichner für eine Methode fehlt, der nach der Erzeugung eines Objektes ansprechbar wäre. Nach Erzeugung des Objektes kann jedoch auf die öffentlichen Eigenschaften zugegriffen werden.

Drittes Beispiel mit __construct() und __toString() (klasse-08c.php):

?>

<?php

class DritteTestKlasse {

    public $rueckgabe = "Fleischer";

    public function __construct() {

        $this->rueckgabe = "Ergebnis für ".$this->rueckgabe;
   }
    public function __toString() {

        return $this->rueckgabe;
    }
}

$obj = new DritteTestKlasse();
echo $obj."n";

// Ausgabe: Ergebnis für Fleischer 

?>

Eine weitere Möglichkeit einen Wert für die Ausgabe zu erhalten, besteht in der Verwendung der Magischen Methode __toString. Diese Magische Methode wird im Zusammenhang mit echo oder print versuchen ein Objekt in einen String umzuwandeln und auszugeben.

Nachfolgend zwei weitere Beispiele in der Gegenüberstellung. Beide Exempel könnten so oder ähnlich als Grundlage für ein Login-Script dienen.

Viertes Beispiel - Login-Script mit einer definierten Methode (klasse-08d.php):

<?php

class Einwahl {

    private $user = "Admin";
    private $pass = "EsPasst";

    public function vergleicheDaten($benutzer, $passwort) {

        if ($benutzer == $this->user and $passwort == $this->pass) {

            /*-------------------------------------------------------
             Hier den Code für eine Verbindung zur DB bzw. für den
             Einwahlvorgang einfügen. Danach eine Mitteilung als
             Bestätigung generieren oder eine Fehlermeldung retour.
             --------------------------------------------------------
            */
            return "Einwahl war erfolgreich!n";
        }
        else {
            return "Einwahl ist fehlgeschlagen!n";
        }
    }
}
$ausgabe = new Einwahl();
echo $ausgabe->vergleicheDaten("Admin","EsPasst");

?>

Das vierte Exempel unterscheidet sich nicht wesentlich vom ersten Code-Listing auf dieser Seite, mit dem Unterschied, dass beim Erstellen des Objektes zwei Werte mit an die Methode der Klasse übergeben werden. Innerhalb der Methode werden diese Werte mit Hilfe eines if-Statements mit den Werten der Eigenschaften auf Gleichheit überprüft. Sollte das if-Statement true liefern, so könnte als nächster Schritt eine Verbindung zur Datenbank erstellt werden oder das Script könnte Zugang zu einem geschützten Bereich gewähren.

Fünftes Beispiel - Login-Script mit __construct (klasse-08e.php):

<?php
session_start();

class Anmeldung {

    private $user = "Admin";
    private $pass = "EsPasst";
    public  $rueckgabe;

    public function __construct($benutzer, $passwort) {

        if ($benutzer == $this->user and $passwort == $this->pass) {

            /*-------------------------------------------------------
             Hier wieder den Code für eine Verbindung usw. einfügen.
             --------------------------------------------------------
            */
            $this->rueckgabe = "Anmeldung war erfolgreich!n";
        }
        else {
            $this->rueckgabe = "Anmeldung ist fehlgeschlagen!n";
        }
    }
    public function __destruct() {

        $_SESSION["speichern"] = "Die letzte ".$this->rueckgabe;
    }
}
$ausgabe = new Anmeldung("Admin","EsPasst");
echo $ausgabe->rueckgabe;

?>

Wie bei den ersten Beispielen, so wurde auch in diesem Beispiel die mit einem Bezeichner definierte Methode gegen eine Konstruktormethode ausgewechselt. Als Ergänzung wurde zusätzlich noch eine weitere Magische Methode verwendet, eine Destruktormethode, die zum Ende der Laufzeit des Scripts noch eine Aktion ausführen soll. Im Beispiel soll in einer Session-Variablen gespeichert werden, ob das letzte Log-in fehlschlug oder nicht.

Destruktoren

Wie bereits erwähnt, so handelt es sich bei der Destruktormethode um eine weitere Magische Methode, die PHP zu bieten hat. Die Verwendung von Destruktoren ist jedoch selten erforderlich, eigentlich nur in speziellen Ausnahme­fällen.
Im Unterschied zu einer Programmiersprache wie C, muss ein Programmierer, gleich ob Einsteiger oder nicht, sich kaum darüber Gedanken machen, ob PHP hinter ihm aufräumt und beim Aufräumen durch das Script belegten Speicher wieder frei gibt oder nicht. Zumindest solange nicht, wie ein Script beim Verbrauch von Speicherplatz nicht die Grenzwerte des Memory Limits erreicht.
PHP verwaltet den erforderlichen Speicherbedarf eigenständig und wird am Ende eines Scripts nicht mehr benötigten Speicherplatz für andere Anwendungen freigeben und dabei alle Objekte, Variablen und Referenzen löschen. Doch welche Aufgaben bleiben nun eigentlich für den Destruktor übrig?

Ein Destruktor wird zum Ende eines Scripts aufgerufen oder wenn keine weiteren Referenzen auf ein Objekt mehr existieren. Letzteres sollte dann der Fall sein, wenn die Referenzen zur Laufzeit eines Scripts durch die Zuweisung der Konstanten NULL überschrieben oder mit unset() gelöscht werden. Wurden die Referenzen gelöscht, wird PHP den Destruktor bereits vor dem Ende der Laufzeit eines Scripts aufrufen.
Wer testen möchte, wann wie viel Speicherplatz vom Script belegt ist, kann das nachfolgende Code-Listing erweitern und die Funktion memory_get_usage() verwenden. Wird memory_get_usage() in den Zeilen vor und nach einer Zuweisung von NULL oder vor oder nach dem Gebrauch von unset() eingefügt, sollte sich ein Unterschied ergeben. Zumindest in allen bisherigen Tests verhielt es sich so.

Sechtes Beispiel mit Destruktor (klasse-08g.php):

<?php

class Speicherplatz {

    public  $rueckgabe;

    public function __construct($eingabe) {

        $this->rueckgabe = $eingabe.memory_get_usage();
    }
    public function __destruct() {

        echo "Destructor<br>n";
    }
}

/*-------------------------------------------------------------------
 Für Testausgaben lassen sich Aktionen mit __destruct() mehrfach vor
 dem Ende der Scriptlaufzeit ausführen.
 --------------------------------------------------------------------
*/
$eingabe = new Speicherplatz("Von PHP belegter Speicherplatz in Bytes: ");
echo $eingabe->rueckgabe."<br>n";
$eingabe = NULL;

$eingabe = new Speicherplatz("Von PHP belegter Speicherplatz in Bytes: ");
echo $eingabe->rueckgabe."<br>n";
unset($eingabe);


/* Ausgabe:

Von PHP belegter Speicherplatz in Bytes: 323912
Destructor
Von PHP belegter Speicherplatz in Bytes: 324000
Destructor

*/

?>

Nachfolgend eine erweiterte Ausgabe als Test, aus dem sich der Unterschied vor und nach dem Löschen mit unset() ableiten lässt. Auch ist dem vorausgehenden wie dem unteren Beispiel zu entnehmen, dass der Destruktor nach jedem Löschen aufgerufen wird.

Was ebenfalls erkennbar wird, durch das Löschen mit unset() verringert sich der verwendete Speicherplatz etwa im gleichen Verhältnis und das unabhängig davon, ob der Destruktor auskommentiert wurde oder nicht. Letzteres liegt daran, dass allein durch den Aufruf des Destruktors keine bereits instanziierten Objekte nachträglich zerstört werden und nur durch die Verwendung von unset($eingabe) die Variable $eingabe einschließlich einer enthaltenen Referenz oder eines sonstigen Wertes aus dem Speicher entfernt wird. Erst deren Entfernung aus dem Speicher führt zu einem Aufruf des Destruktors.
Wie bereits erwähnt, wurden die Test mit und ohne Destruktor durchgeführt, wobei die jeweils ermittelten Endwerte nach dem Löschen von $eingabe mit unset stets den Anfangswerten vor der Erzeugung und Instanziierung eines Objektes entsprachen.

Siebentes Beispiel als Detail-Listing (klasse-08h.php):

<?php

// ...

// Eine erweiterte Ausgabe als Test

echo memory_get_usage() ."<br>n";
$eingabe = new Testausgaben("Von PHP belegter Speicherplatz in Bytes: ");
echo $eingabe->rueckgabe."<br>n";
echo memory_get_usage() ."<br>n";
unset($eingabe);
echo memory_get_usage() ."<br>n";

echo "<br>nEine beliebige andere Ausgabe nur zur Kontrolle.<br><br>n";

echo memory_get_usage() ."<br>n";
$eingabe = new Testausgaben("Von PHP belegter Speicherplatz in Bytes: ");
echo $eingabe->rueckgabe."<br>n";
echo memory_get_usage() ."<br>n";
unset($eingabe);
echo memory_get_usage() ."<br>n";

/* Ausgabe:

330312
Von PHP belegter Speicherplatz in Bytes: 330600
330656
Destructor
330312

Eine beliebige andere Ausgabe nur zur Kontrolle.

330312
Von PHP belegter Speicherplatz in Bytes: 330600
330656
Destructor
330312

*/

?>

Die Verwendung eines Destruktors wird gelegentlich missverstanden. Ein Destruk­tor (zumindest bei PHP) ist weniger dafür gedacht nicht mehr benötigte Ressourcen freizugeben, als vielmehr eine letzte Aktion auszuführen.
Die Stärken eines Destruktors, die für dessen gelegentliche Verwendung sprechen, ergeben sich aus dem Umstand, dass dieser immer aufgerufen wird wenn ein Objekt bzw. die letzte Variable, die eine Referenz auf ein Objekt enthält, gelöscht wird. Dadurch lässt sich mit Hilfe des Destruktors vor dem endgültigen Löschen eines Objektes noch der innerhalb des Destruktors notierte Code ausführen, falls eine Ausgabe oder abschließende Aktion stets erforderlich sein sollte. Im fünften Beispiel wurde noch ein Wert in einer Session-Variablen gespeichert, doch es könnten auch persistente Verbindungen geschlossen oder ein abschließender Hinweis ausge­geben werden.

Wie bereits bei beim Konstruktor erwähnt, so liefert auch der Destruktor keinen Rückgabewert im üblichen Sinne. Eine Ausgabe kann jedoch mit echo oder print erfolgen, ebenfalls wird Code mit Anweisungen noch ausgeführt. Bei der Vererbung sind einige Punkte zu beachten, doch dazu auf der nächsten Seite mehr.

weiterlesen » Vererbung bei Konstruktoren und D...

 

Copyright © Verlag Horst Müller - Stendal - 2006 - Impressum - Datenschutz - Nutzungsbedingungen