Categorie
PHP

PHP – metodi magici __get e __set best practice

PHP dispone di un certo un mero di funzioni dette “metodi magici“. Si tratta di metodi che vengono attivati al verificarsi di terminati eventi, ed aventi una sintassi particolare nel nome. Difatti li possiamo riconoscere facilmente visto che iniziano tutti con un doppio undescore.

Due di questi (__construct e __destruct) li abbiamo già conosciuti in un mio precedente post: capire i costruttori ed i distruttori, mentre l’elenco completo lo potete trovare direttamente nella documentazione ufficiale: PHP Magic Methods.
In questo articolo voglio soffermarmi su un paio di metodi magici, cioè __get() e __set(), soprattutto dal punto di vista della loro utilità e possibilità di utilizzo nel “mondo reale”.

Come funzionano

Le funzioni __get, e __set naturalmente si riferiscono alla programmazione OOP, quindi devono essere dichiarate all’interno di una classe.
Questi metodi sono invocati quando la proprietà è inaccessibile (o non esiste, quindi è inaccessibile).

class Foo
{
    private $baz = "baz_value";

    public function __get($name) {
        echo 'Attributo non trovato';
    }         
}

$foo = new Foo();
echo $foo->baz;

Nel codice precedente verrà invocato il metodo __get visto che la proprietà $baz anche se esiste è privata, quindi non accessibile direttamente dall’esterno.
[box type=”note”]Se $baz fosse stata pubblica allora il metodo non sarebbe stato invocato.[/box] Stesso discorso per quanto riguarda __set, che sarà invocato quando si cerca di settare il valore di un attributo inaccessibile.

class Foo
{   
    public function __set($name, $value) {
        echo 'Attributo non trovato';
    }
}

$foo = new Foo();
$foo->baz = 'baz_value';

__get e __set come getter e setter

Bene ora che abbiamo capito cono funzionano, la domanda nasce spontanea. Può essere considerata una buona pratica utilizzare i metodi magici __get e __set come sostituti di dei canonici getter e setter?
Facciamo alcune considerazioni aiutandoci con qualche esempio.

Usando __get e __set

class Foo
{
    private $baz;
    private $boo;

    public function __get($name) {
        if (property_exists($this, $name)) {
            return $this->$name;
        }
    }

    public function __set($name, $value) {
        if (property_exists($this, $name)) {
            $this->$name = $value;
        }   
    }
}

$foo = new Foo();
$foo->baz ='baz_value';
$foo->boo = 'boo_value';
echo $foo->baz;
echo $foo->boo;

Lo snippet di codice precedente è piuttosto intuitivo, abbiamo usato i metodi magici per ottenere e settare i valori di proprietà non direttamente accessibili dall’esterno. Vediamo lo stesso esempio usando questa volta un approccio più tradizionale.

Usando i tradizionali getters e setters

class Foo
{
    private $baz;
    private $boo;

    public function getBaz()
    {
        return $this->baz;
    }    

    public function setBaz($value)
    {
        $this->baz = $value;
    }   

    public function getBoo()
    {
        return $this->boo;
    }    

    public function setBoo($value)
    {
        $this->boo = $value;
    }     
}

$foo = new Foo();
$foo->setBaz('baz_value');
$foo->setBoo('boo_value');
echo $foo->getBaz();
echo $foo->getBoo();

La prima cosa da notare è che da entrambi gli esempi otterremo lo stesso identico risultato.
A prima vista la prima soluzione potrebbe apparire come la migliore o quantomeno quella più concisa e snella. Due metodi contro quattro (che aumenterebbero con l’aumentare delle proprietà).
Tuttavia ci non diversi aspetti negativi e pericolosi da considerare:

  • __get e __set sono decisamente più lenti (fino a 10 volte) di getter / setter
  • Rendono impossibile il completamento automatico del codice e questo è un grave problema (personalmente non conosco un IDE che sia in grado di farlo).
  • Le APIs risultano poco chiare.
  • Il sistema è più difficile da capire, soprattutto per i nuovi arrivati.

Considerazioni finali

I metodi magici non sono sostituti di getter e setter. Come spiegato consentono di gestire le chiamate a proprietà inaccessibili che altrimenti causerebbero un errore. Quindi a mio avviso sono da considerarsi più legati alla gestione degli errori che altro.

Nel caso in cui, tuttavia, scegliessimo si utilizzare __get e __set come getter e setter questo non è un errore, ma solamente, almeno dal mio punto di vista, una cattiva pratica.
In questo caso è raccomandato utilizzare un array:

class Foo {
    protected $_values = array();

    public function __get($key)
    {
        return $this->_values[$key];
    }

    public function __set($key, $value)
    {
        $this->_values[$key] = $value;
    }
}

In questo modo siamo sicuri che non è possibile accedere alla variabile in un’altro modo per evitare collisioni (notare che $_value è protetta).

2 risposte su “PHP – metodi magici __get e __set best practice”

Simply wish to say your article is as amazing.
The clearness for your submit is just excellent and i could suppose you’re a
professional on this subject. Fine with your permission let me
to clutch your RSS feed to keep updated with approaching post.
Thanks one million and please carry on the enjoyable work.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.