Geschichte der Frage:
Seit der ersten Veröffentlichung von Perl 5 unterstützt die Sprache ein elementares Objektmodell über den Mechanismus des Bindens von Referenzen an ein Paket (blessing). In Perl sind Objekte einfache Referenzen (auf ein Hash, Array oder Skalar), die durch die Funktion bless "geweiht" werden, was dem System ermöglicht, Methoden über Pakete (Namespace) zu finden.
Problem:
Nicht-geweihte Referenzen bleiben einfache Datenstrukturen, und der Versuch, eine Methode auf ihnen aufzurufen, führt zu Laufzeitfehlern. Ein Programmierer, der nicht auf den Referenztyp achtet, riskiert, versehentlich mit den inneren Werten eines Objekts zu manipulieren, wodurch die Kapselung verletzt wird. Auch die Arbeit mit "rohen" Dereferenzierungsoperationen {} oder @{} ohne Kontrolle führt zu schwer diagnostizierbaren Bugs.
Lösung:
Objekte sollten korrekt nur über bless erstellt werden, dann sollten die Daten des Objekts nur durch Dereferenzierung zugegriffen werden, wobei der Typ mithilfe des Moduls Scalar::Util (ref, blessed) überprüft wird. Direkter Zugriff auf Strukturen (z. B. $obj->{key}) außerhalb der Methoden der Klasse sollte immer vermieden werden, und Accessoren (Getter/Setter) zur Kontrolle sollten implementiert werden.
Codebeispiel:
package Animal; sub new { my $class = shift; my $self = { name => shift }; bless $self, $class; return $self; } sub name { my $self = shift; $self->{name} = shift if @_; return $self->{name}; } my $dog = Animal->new("Rex"); print $dog->name; # sicher über Accessor print $dog->{name}; # direkter Zugriff, nicht empfohlen
Schlüsselaspekte:
blessed oder ref reduzieren die Anzahl der Bugs erheblich.Kann eine normale Referenz auf ein Hash ohne bless als Objekt verwendet werden?
Nein, ohne den Aufruf von bless hat die Referenz keine Assoziation mit einem Paket, und Perl findet die Methoden nicht (es gibt einen Fehler "Can't call method"), trotz identischer interner Struktur.
Wie kann man sicher feststellen, ob eine Variable tatsächlich ein Objekt ist und nicht nur eine Referenz?
Verwenden Sie die Funktion Scalar::Util::blessed($obj), um zu überprüfen, ob die Referenz geweiht ist. Nur geweihte Referenzen gelten als Objekte.
use Scalar::Util 'blessed'; my $obj = {}; print blessed($obj) ? 'ja' : 'nein'; # gibt 'nein' aus
Kann man eine Methode auf einer nicht-objektlichen Referenz ohne Fehler aufrufen?
Der Aufruf einer Methode auf einer nicht-geweihten Referenz führt zu einem fatalen Fehler: Perl erwartet, dass die Referenz über ihr Paket Bescheid weiß. Ausnahmen bilden AUTOLOAD-Mechanismen und dynamische Ladevorgänge, aber das ist ein Antipattern, das zu Fehlern führt.
Ein junger Entwickler erstellt manuell die Struktur $person = {name => 'Vasya'} und vergisst, bless aufzurufen, und versucht dann, $person->name() aufzurufen, was zu einem Laufzeitfehler führt.
Vorteile:
Nachteile:
Im Code wird immer bless beim Erstellen eines Objekts aufgerufen, und es wird nur die Methode name() für den Zugriff auf die Daten verwendet. Die Überprüfung über blessed() ermöglicht es, Fehler vor der Ausführung der Methoden zu behandeln.
Vorteile:
Nachteile: