Mediante esta clase abstracta de php podremos crear nuestras clases simplemente extendiendo esta clase
abstract class Singleton {
protected function __construct() {
}
final public static function getInstance( $calledClassName = null ) {
static $aoInstance = array();
if ( $calledClassName == null ) {
$calledClassName = get_called_class();
}
if (! isset ($aoInstance[$calledClassName])) {
$aoInstance[$calledClassName] = new $calledClassName();
}
return $aoInstance[$calledClassName];
}
final private function __clone() {
}
}
Ejemplo:
class DataBase extends Singleton {
[...]
}
$db = DataBase::getInstance();
El problema que nos encontraremos en PHP 5.2.x es que no existe la función get_called_class por lo que deberemos tener esa función.
if(!function_exists('get_called_class')) {
class class_tools {
static $i = 0;
static $fl = null;
static function get_called_class() {
$bt = debug_backtrace();
if(self::$fl == $bt[2]['file'].$bt[2]['line']) {
self::$i++;
} else {
self::$i = 0;
self::$fl = $bt[2]['file'].$bt[2]['line'];
}
$lines = file($bt[2]['file']);
preg_match_all('
/([a-zA-Z0-9\_]+)::'.$bt[2]['function'].'/',
$lines[$bt[2]['line']-1],
$matches
);
$returnValue = $matches[1][self::$i];
// comprobamos si lo llamamos desde un call_user_func y similar
if ( empty( $returnValue )
&& isset( $bt[3]['function'] )
&& in_array($bt[3]['function'],array('call_user_func', 'call_user_func_array'))) {
$returnValue = $bt[3]['args'][0][0];
}
return $returnValue ;
}
}
function get_called_class() {
return class_tools::get_called_class();
}
}
Como se puede ver utiliza la funcion debug_backtrace() para determinar a que clase estamos llamando. Con esta función ya no tendremos problemas a la hora de instanciar nuestros “Singleton” en php.
Ejemplos de uso que funcionan perfectamente en PHP 5.3, y ahora en PHP 5.2
$objeto = DataBase::getInstance() ;
[...]
$miClase = 'DataBase';
$objeto = call_user_func( array( $miClase, 'getInstance'));