Historia pytania:
Od pierwszej wersji Perl 5 język wspierał elementarny model obiektowy przez mechanizm wiązania linków z pakietem (blessing). W Perl obiekty to zwykłe linki (do hasha, tablicy lub skalaru), "usankcjonowane" funkcją bless, co pozwala systemowi znajdować metody przez pakiet (namespace).
Problem:
Nieuświęcone linki pozostają zwykłymi strukturami danych, a próba wywołania na nich metody prowadzi do błędów w czasie wykonywania. Programista, nie zwracając uwagi na typ linka, ryzykuje przypadkowe manipulowanie wnętrzem obiektu, łamiąc enkapsulację. Praca z "surową" operacją dereferencjonującą {} lub @{} bez kontroli prowadzi do trudnych do wychwycenia błędów.
Rozwiązanie:
Poprawnie tworzyć obiekty tylko przez bless, a następnie odnosić się do danych obiektu tylko przez dereferencjonowanie, sprawdzając typ przy użyciu modułu Scalar::Util (ref, blessed). Zawsze należy unikać bezpośredniego dostępu do struktur (na przykład, $obj->{key}) poza metodami klasy i wdrożyć akcesory (getter/setter) dla kontroli.
Przykład kodu:
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; # bezpiecznie przez accessor print $dog->{name}; # bezpośredni dostęp, niezalecane
Kluczowe cechy:
blessed lub ref znacznie zmniejsza liczbę błędówCzy zwykły link do hasha może być używany jako obiekt bez bless?
Nie, bez wywołania bless link nie ma powiązania z pakietem, a Perl nie znajdzie metod (będzie błąd "Can't call method"), mimo identycznej struktury wewnętrznej.
Jak bezpiecznie określić, czy zmienna jest naprawdę obiektem, a nie tylko linkiem?
Użyć funkcji Scalar::Util::blessed($obj) do sprawdzenia, czy link jest uświęcony. Tylko uświęcone linki są uważane za obiekty.
use Scalar::Util 'blessed'; my $obj = {}; print blessed($obj) ? 'yes' : 'no'; # wyświetli 'no'
Czy można wywołać metodę na nieobiektowym linku bez błędów?
Wywołanie metody na nie-uzbrojonej linku spowoduje błąd fatalny: Perl oczekuje, że link wie o swoim pakiecie. Wyjątek stanowią mechanizmy AUTOLOAD i dynamiczne ładowanie, ale to antywzorzec, prowadzący do błędów.
Młody programista ręcznie tworzy strukturę $person = {name => 'Vasya'} i zapomina wywołać bless, po czym próbuje wywołać $person->name(), co prowadzi do błędu czasie wykonywania.
Plusy:
Minusy:
W kodzie zawsze wywoływane jest bless przy tworzeniu obiektu i używana jest tylko metoda name() do dostępu do danych. Sprawdzanie przez blessed() pozwala na obsługę błędów przed wykonaniem metod.
Plusy:
Minusy: