Geschiedenis van de vraag:
Sinds de eerste release van Perl 5 ondersteunt de taal een elementair objectmodel via het mechanisme van het koppelen van verwijzingen aan een pakket (blessing). In Perl zijn objecten gewone verwijzingen (naar een hash, array of scalair) die zijn "gezworen" door de functie bless, waardoor het systeem methoden via het pakket (namespace) kan vinden.
Probleem:
Niet-gezegende verwijzingen blijven gewone gegevensstructuren, en het proberen aanroepen van een methode op hen leidt tot runtime-fouten. Een programmeur zonder de juiste aandacht voor het type verwijzing loopt het risico per ongeluk met de interne gegevens van een object te manipuleren, waardoor de encapsulatie wordt verbroken. Ook kan het werken met de "rauwe" dereferencing-operatie {} of @{} zonder controle leiden tot moeilijk te traceren bugs.
Oplossing:
Maak objecten correct alleen via bless, en benader de gegevens van het object alleen via dereferencing, door het type te controleren met behulp van de module Scalar::Util (ref, blessed). Vermijd altijd directe toegang tot structuren (bijvoorbeeld, $obj->{key}) buiten de methoden van de klasse en implementeer accessoren (getter/setter) voor controle.
Voorbeeld code:
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; # veilig via accessor print $dog->{name}; # directe toegang, niet aanbevolen
Belangrijkste kenmerken:
blessed of ref verminderen aanzienlijk het aantal bugsKan een gewone verwijzing naar een hash als object worden gebruikt zonder bless?
Nee, zonder de aanroep van bless heeft de verwijzing geen associatie met een pakket, en Perl zal geen methoden vinden (er zal een fout "Can't call method" optreden), ondanks de identieke interne structuur.
Hoe kan veilig worden vastgesteld of een variabele werkelijk een object is en geen gewone verwijzing?
Gebruik de functie Scalar::Util::blessed($obj) om te controleren of de verwijzing gezegend is. Alleen gezegende verwijzingen worden als objecten beschouwd.
use Scalar::Util 'blessed'; my $obj = {}; print blessed($obj) ? 'yes' : 'no'; # zal 'no' afdrukken
Kan een methode op een niet-object verwijzing zonder fouten worden aangeroepen?
Het aanroepen van een methode op een niet-gezegende verwijzing zal een fatale fout veroorzaken: Perl verwacht dat de verwijzing weet over zijn pakket. Uitzonderingen zijn AUTOLOAD-mechanismen en dynamische laadsystemen, maar dit is een antipatroon dat leidt tot fouten.
Een jonge ontwikkelaar maakt handmatig een structuur $person = {name => 'Vasya'} en vergeet bless aan te roepen, waarna hij probeert $person->name() aan te roepen, wat leidt tot een runtime-error.
Voordelen:
Nadelen:
In de code wordt altijd bless aangeroepen bij het maken van een object en wordt alleen de methode name() gebruikt voor toegang tot de gegevens. Controle met blessed() stelt ons in staat om fouten te verwerken voordat methoden worden uitgevoerd.
Voordelen:
Nadelen: