Piero V.

Singleton in PHP + annesso bug

È da un po’ di tempo che sto programmando in C++ ma oggi sono tornato a programmare un po’ in PHP.

Devo dire che ormai mi sembra strano non dover dichiarare più variabili, non aver più gli header e poter implementare i metodi fuori dalla classe stessa.

Però mi ha fatto bene questa pausa di PHP perché ho imparato una tecnica molto interessante, quella delle “singleton”.

In pratica le singleton sono classi che possono avere una sola istanza.

Il loro metodo si riduce praticamente ai metodi statici, però sono più eleganti, secondo me.

Ci sono due principali metodi in C++ per fare i singleton: impostare il costruttore private, in modo da impedire la chiamata al di fuori della classe e dopo chiamarlo o da un metodo statico oppure tramite l’overriding dell’operatore new.

Implementare il primo metodo in PHP è facilissimo, mentre implementare il secondo dovrebbe essere fattibile tramite il metodo magico __call. Però non funziona, ma per farvi vedere come sarebbe lo metto lo stesso nel codice, che è il seguente:

<?php

class MiaClasse {

	/**
	 * L'istanza del singleton.
	 *
	 * @var MiaClasse object
	 * @access private
	 */
	private static $msSingleton = null;

	/**
	 * Un numero per fare una prova.
	 *
	 * @var integer
	 * @access public
	 */
	public $prova = 0;

	/**
	 * Il costruttore.
	 *
	 * È privato perché così si può creare una nuova istanza
	 * solamente da altri metodi di questa classe.
	 */
	private function __construct()
	{
		echo "Costruisco la classe\n";
	}

	/**
	 * Ritorno (o creo, se non esiste) il singleton.
	 */
	public static function getSingleton()
	{
		if(is_null(self::$msSingleton)) {
			self::$msSingleton = new MiaClasse();
		}

		return self::$msSingleton;
	}

	/**
	 * Fallback per le chiamate ai metodi privati.
	 *
	 * Se per caso si prova a creare una nuova istanza, tramite
	 * questa funzione chiamo sempre getSingleton.
	 * È un po' come l'overriding dell'operatore new in C++.
	 */
	public function __call($name, $arguments)
	{
		echo '__call called. $name = ' . $name;
		if($name == '__construct') {
			return self::getSingleton();
		}
	}

}

$a = MiaClasse::getSingleton();
$a->prova = 20;

$b = MiaClasse::getSingleton();
echo $b->prova . "\n";
$b->prova = 27;
echo $a->prova . "\n";

$c = $a->__construct();
$c->foo = 32;
echo $a->foo . "\n";

/*$d = new MyClass();
echo $d->foo . "\n";
$d->foo = 29;
echo $a->foo . "\n";*/

Come vedete se modifico $b modifico anche $a. … [Leggi il resto]