Moin!
ich habe eine Klasse in etwa dieser Form:
class Beispiel {
private $f; // erhält später den Rückgabewert von fopen()
public function __construct ($path) {
$this->f = fopen($path, 'r');
}private function __destruct () {
fclose($this->f); // wirft einen Fehler "Not a valid stream resource"
}public function close () {
$this->__destruct();
}
}
Wie erwähnt: Man ruft den Destruktor nicht auf!
> Wenn ich die close-Methode aufrufe, erhalte ich den oben angemerkten Fehler, der sich auf den fclose-Aufruf in \_\_destruct() bezieht. Versetze ich den fclose()-Aufruf in die close-Methode selbst, erhalte ich den Fehler nicht. Den Hintergrund dahinter habe ich noch immer nicht verstanden.
Man ruft den Destruktor nicht auf... :)
Entweder schließt du die Ressource explizit mit einem Aufruf von "close()". Dann muss deine Klasse durch Code verhindern, dass man sie danach noch benutzt, oder die Datei dafür dann wieder öffnen. Oder du schließt sie implizit im Destruktor. Dann wird die Ressource geschlossen, wenn das Objekt gelöscht wird. Wann das ist, ist nicht garantiert.
> > Du hast allerdings nicht unbedingt eine Garantie, dass andere dir sonst in der Klasse zur Verfügung stehenden Objekte noch existieren. Vor allem bei zirkulären Referenzen muss man ja irgendwo mal anfangen mit dem Wegwerfen.
>
> Das könnte bereits die auch von mir vermutete Erklärung dazu sein.
Sehe ich nicht.
> > Nein. Das Schließen einer Ressource gehört IN den Destruktor.
>
> Also doch so, wie oben beschrieben? Mit der passenden Fehlermeldung?
Du hast im schlechtesten Fall keine normale Ausgabemöglichkeit mehr. Und dein Beispiel ist auch nicht wirklich geeignet für das Demonstrieren von Destruktoren.
Wenn der Destruktor die Datei schließt, aber der Zeitpunkt nicht garantiert nach dem "unset()" liegt, sondern auch irgendwann bis hin zum Skriptende passieren kann, und das für die Applikation auch keine Rolle spielt, kann man auf das explizite Schließen auch verzichten, und es die Aufräumroutine von PHP machen lassen.
Wenn man hingegen explizit die Datei schließen muss, kann man es nicht im Destruktor machen.
> > Man ruft Destruktoren auch nie explizit auf, sondern allerhöchstens implizit durch `unset($object)`{:.language-php}.
>
> Das habe ich durch diesen Thread jetzt gelernt. Davor war mir der Sinn für diese \_\_destruct-Methode überhaupt nicht klar.
Es gibt ziemlich wenig Grund, einen Destruktor in einer Klasse einzubauen. In PHP vor 5.3 war es zum Auflösen zirkulärer Referenzen lebensnotwendig, aber mit 5.3 ist der Garbage Collector dazu selbständig in der Lage. Sofern man also nicht explizit Codeoptimierungen vornimmt und die Garbage Collection deaktiviert, entfällt dieser Grund für Destruktoren schon mal.
Ebenfalls entfällt der Grund für das implizite Freigeben von Ressourcen. Braucht man es explizit, erstellt man dafür eine eigene Methode.
- Sven Rautenberg