Bonjour,
Le titre du post résume la question !
Pour pouvoir utiliser la fonction get_called_class() en php <= 5.2 on peut se baser sur la
fonction utilisateur donnée dans la documentation officielle :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| /********************************
* Retro-support of get_called_class()
* Tested and works in PHP 5.2.4
* http://www.sol1.com.au/
********************************/
if(!function_exists('get_called_class')) {
function get_called_class($bt = false,$l = 1) {
if (!$bt) $bt = debug_backtrace();
if (!isset($bt[$l])) throw new Exception("Cannot find called class -> stack level too deep.");
if (!isset($bt[$l]['type'])) {
throw new Exception ('type not set');
}
else switch ($bt[$l]['type']) {
case '::':
$lines = file($bt[$l]['file']);
$i = 0;
$callerLine = '';
do {
$i++;
$callerLine = $lines[$bt[$l]['line']-$i] . $callerLine;
} while (strpos($callerLine,$bt[$l]['function']) === false);
preg_match('/([a-zA-Z0-9\_]+)::'.$bt[$l]['function'].'/',
$callerLine,
$matches);
if (!isset($matches[1])) {
// must be an edge case.
throw new Exception ("Could not find caller class: originating method call is obscured.");
}
switch ($matches[1]) {
case 'self':
case 'parent':
return get_called_class($bt,$l+1);
default:
return $matches[1];
}
// won't get here.
case '->': switch ($bt[$l]['function']) {
case '__get':
// edge case -> get class of calling object
if (!is_object($bt[$l]['object'])) throw new Exception ("Edge case fail. __get called on non object.");
return get_class($bt[$l]['object']);
default: return $bt[$l]['class'];
}
default: throw new Exception ("Unknown backtrace method type");
}
}
}
?> |
Seul problème, cette fonction ne prends pas en compte le mécanisme de Late State Binding sur lequel est justement basée la fonction get_called_class() disponible à partir de PHP 5.3.
Cette fonctionnalité a été baptisée "late static bindings", d'un point de vue interne. "Late binding", littéralement compilation tardive, vient du fait que les éléments static:: ne seront plus résolus en utilisant la classe où la méthode a été définie, mais celle qui est active durant l'exécution. L'adjectif statique a été ajouté car ce problème s'applique aux méthodes statiques, mais pas seulement.
Dans mon cas j'utilise un objet qui hérite d'un singleton abstrait dont voici la structure :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| if( ! class_exists( 'Singleton_Abstract' ) )
{
abstract class Singleton_Abstract
implements Singleton_Interface
{
protected static $i_Counter = 0;
protected static $s_Fline = null;
final private function __clone(){}
protected function __construct(){}
final public static function GetInstance()
{
static $h_Instances = array();
$s_Class = self::GetChild();
if( ! isset( $h_Instances[ $s_Class ] ) )
$h_Instances[ $s_Class ] = new $s_Class;
return $h_Instances[ $s_Class ];
}
final protected static function GetChild()
{
$h_Backtrace = debug_backtrace();
$i_Line = $h_Backtrace[1]['line'];
$s_File = $h_Backtrace[1]['file'];
$s_Function = $h_Backtrace[1]['function'];
if( self::$s_Fline == $s_File . $i_Line ) self::$i_Counter++;
else self::$i_Counter = 0;
$s_Search = "/([a-zA-Z0-9\_]+)::$s_Function/";
$a_Lines = file( $s_File );
$s_Line = $a_Lines[ --$i_Line ];
preg_match_all( $s_Search, $s_Line, $a_Matches );
return $a_Matches[1][self::$i_Counter];
}
} |
Et puisque je suis en PHP 5.2, et que je ne peux pas instancier mes objets singletons comme suit :
return $s_Class::GetInstance()
je vais utiliser la fonction call_user_func() comme suit
return call_user_func( array( $s_Class, "GetInstance" ) );
Dans une fabrique dont je vous fournis le code ici :
1 2 3 4 5 6 7 8 9 10 11 12 13
| public function Factory( $s_Path )
{
$s_FrameworkPath = dirname( dirname( __FILE__ ) ) . DIRECTORY_SEPARATOR;
$s_Path = str_replace( '/', DIRECTORY_SEPARATOR, $s_Path );
$s_Class = str_replace( DIRECTORY_SEPARATOR, '_', $s_Path );
if( file_exists( APPLICATION_PATH . "$s_Path.php" )
OR file_exists( $s_FrameworkPath . "$s_Path.php" ) )
return call_user_func( array( $s_Class, "GetInstance" ) );
//eval( "$s_Class::GetInstance();" );
throw new Exception( "PAGE_NOT_FOUND", 404 );
} |
Et là j'obtiens une suite d'erreurs :
Notice: Undefined index: line in
C:\Documents and Settings\alejandro\Mes documents\...\Framework\Singleton\Abstract.php on line
37
Notice: Undefined index: file in
C:\Documents and Settings\alejandro\Mes documents\...\Framework\Singleton\Abstract.php on line
38
Notice: Undefined offset: 1 in
C:\Documents and Settings\alejandro\Mes documents\...\Framework\Singleton\Abstract.php on line
51
Fatal error: Class name must be a valid object or a string in
C:\Documents and Settings\alejandro\Mes documents\...\Framework\Singleton\Abstract.php on line
28
C'est ma fonction GetChild(), dérivée du get_called_class fait maison dans le manuel PHP qui, comme la fonction dont elle dérive, ne trouve pas les index file et line lorsque la trace a été générée lors d'un appel de fonction statique réalisé par call_user_func().
Si vous avez une solution ...
Partager