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 :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
return $s_Class::GetInstance()
je vais utiliser la fonction call_user_func() comme suit

Code : Sélectionner tout - Visualiser dans une fenêtre à part
return call_user_func( array( $s_Class, "GetInstance" ) );
Dans une fabrique dont je vous fournis le code ici :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 ...