note 96021 deleted from function.get-called-class by danbrown
| From: | danbrown@php.net | Date: | Wed, 03 Feb 2010 16:43:38 +0000 |
| Subject: | note 96021 deleted from function.get-called-class by danbrown | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-165629@lists.php.net to get a copy of this message | ||
Note Submitter: feb2010 at birth-online dot de
----
The get_called_class() implementation of "laurence+nospam at sol1 dot com dot au" further
down doesn't know anything if you called a static method from within another static method
using call_user_func() or call_user_func_array().
In this case, the second backtrace entry ($l=1) has no "file" or "line" and the
lookup fails. I added a few lines to look further in the backtrace for these two cases and get the
class name from the first parameter of call_user_func/call_user_func_array.
This is what the function looks like for now:
<?php
/********************************
* Retro-support of get_called_class()
* Tested and works in PHP 5.2.4
* http://www.sol1.com.au/
* additions by Markus Birth <feb2010@birth-online.de>
********************************/
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 '::':
$function = $bt[$l]['function'];
if ( !isset( $bt[$l]['file'] ) ) {
$l++;
if ( $bt[$l]['function'] == 'call_user_func' ||
$bt[$l]['function'] == 'call_user_func_array' ) {
return $bt[$l]['args'][0][0];
}
}
$lines = file($bt[$l]['file']);
$i = 0;
$callerLine = '';
do {
$i++;
$callerLine = $lines[$bt[$l]['line']-$i] . $callerLine;
} while ( stripos( $callerLine, $function ) === false && $i < 500 );
preg_match( '/([a-zA-Z0-9\_]+)::' . $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.' . print_r( $bt, true ) );
}
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' );
}
}
}
function set_class_var( $class, $varname, $value ) {
if ( !class_exists( $class ) ) throw new Exception( 'Class "' . $class .
'" does not exist!' );
if ( !property_exists( $class, $varname ) ) throw new Exception( 'Class "' .
$class . '" has no property "' . $varname . '"!' );
eval( $class . '::$' . $varname . ' =& $value;' );
return $value;
}
?>