Php функции callback аргумент

call_user_func

Вызывает callback-функцию, переданную первым параметром, и передаёт остальные параметры в качестве аргументов. callback .

Список параметров

Ноль или более параметров, передаваемые в callback-функцию.

Замечание:

Учтите, что параметры для call_user_func() не передаются по ссылке.

Пример #1 Пример использования call_user_func() и ссылки

$a = 0 ;
call_user_func ( ‘increment’ , $a );
echo $a . «\n» ;

// Вместо этого можно использовать этот способ
call_user_func_array ( ‘increment’ , array(& $a ));
echo $a . «\n» ;

// Также можно использовать функцию в качестве переменной
$increment = ‘increment’ ;
$increment ( $a );
echo $a . «\n» ;
?>

Результат выполнения данного примера:

Warning: Parameter 1 to increment() expected to be a reference, value given in … 0 1 2

Возвращаемые значения

Возвращает значение, возвращённое callback-функцией.

Примеры

Пример #2 Пример использования call_user_func()

function barber ( $type )
echo «Вы хотели стрижку $type , без проблем\n» ;
>
call_user_func ( ‘barber’ , «под горшок» );
call_user_func ( ‘barber’ , «наголо» );
?>

Результат выполнения данного примера:

Вы хотели стрижку под горшок, без проблем Вы хотели стрижку наголо, без проблем

Пример #3 Использование call_user_func() , используя пространства имён

class Foo static public function test () print «Привет, мир!\n» ;
>
>

call_user_func ( __NAMESPACE__ . ‘\Foo::test’ );
call_user_func (array( __NAMESPACE__ . ‘\Foo’ , ‘test’ ));

Результат выполнения данного примера:

Пример #4 Вызов метода класса с помощью call_user_func()

class myclass static function say_hello ()
echo «Привет!\n» ;
>
>

call_user_func (array( $classname , ‘say_hello’ ));
call_user_func ( $classname . ‘::say_hello’ );

call_user_func (array( $myobject , ‘say_hello’ ));

Результат выполнения данного примера:

Пример #5 Использование лямбда-функции с call_user_func()

Результат выполнения данного примера:

Примечания

Замечание:

Callback-функции, зарегистрированные такими функциями как call_user_func() и call_user_func_array() , не будут вызваны при наличии не пойманного исключения, брошенного в предыдущей callback-функции.

Смотрите также

  • call_user_func_array() — Вызывает callback-функцию с массивом параметров
  • is_callable() — Проверяет, что значение может быть вызвано как функция в текущей области видимости
  • Обращение к функциям через переменные
  • ReflectionFunction::invoke() — Вызывает функцию
  • ReflectionMethod::invoke() — Вызов

User Contributed Notes 31 notes

I benchmarked the comparison in speed between variable functions, call_user_func, and eval. My results are below:

Variable functions took 0.125958204269 seconds.
call_user_func took 0.485446929932 seconds.
eval took 2.78526711464 seconds.

This was run on a Compaq Proliant server, 180MHz Pentium Pro 256MB RAM. Code is as follows:

function fa () < return 1 ; >
function fb () < return 1 ; >
function fc ()

$calla = ‘fa’ ;
$callb = ‘fb’ ;
$callc = ‘fc’ ;

$time = microtime ( true );
for( $i = 5000 ; $i —; ) $x = 0 ;
$x += $calla ();
$x += $callb ();
$x += $callc ();
if( $x != 3 ) die( ‘Bad numbers’ );
>
echo( «Variable functions took » . ( microtime ( true ) — $time ) . » seconds.
» );

$time = microtime ( true );
for( $i = 5000 ; $i —; ) $x = 0 ;
$x += call_user_func ( ‘fa’ , » );
$x += call_user_func ( ‘fb’ , » );
$x += call_user_func ( ‘fc’ , » );
if( $x != 3 ) die( ‘Bad numbers’ );
>
echo( «call_user_func took » . ( microtime ( true ) — $time ) . » seconds.
» );

$time = microtime ( true );
for( $i = 5000 ; $i —; ) $x = 0 ;
eval( ‘$x += ‘ . $calla . ‘();’ );
eval( ‘$x += ‘ . $callb . ‘();’ );
eval( ‘$x += ‘ . $callc . ‘();’ );
if( $x != 3 ) die( ‘Bad numbers’ );
>
echo( «eval took » . ( microtime ( true ) — $time ) . » seconds.
» );

if you simply want to dynamically call a method on an object it is not necessary to use call_user_function but instead you can do the following:

?>

I’ve used the above so I know it works.

@insta at citiesunlimited dot com & @Maresa

call_user_func() alleged slowness is quite over estimated when it comes to real use cases. we are talking about loosing fraction of a second every million calls, which by the way would take less than half a sec to execute in the worst case.

I don’t know of many processes that would actually suffer from this kind of overhead.

Iterations: 100 000
Averaged over: 10
PHP 5.6.30 (cli) (built: Jan 18 2017 19:47:28)
Overall Average
+————————+———-+————+———+
| Invocation | Time (s) | Delta (s) | % |
+————————+———-+————+———+
| directFunction | 0.0089 | -0.0211 | -70.19 |
| directStatic | 0.0098 | -0.0202 | -67.39 |
| directLambda | 0.0109 | -0.0191 | -63.52 |
| directInstance | 0.0116 | -0.0184 | -61.31 |
| directClosure | 0.0150 | -0.0150 | -50.15 |
| Invoke | 0.0282 | -0.0018 | -6.13 |
| call_user_func | 0.0300 | | |
| ClosureFactory | 0.0316 | +0.0016 | +5.20 |
| assignedClosureFactory | 0.0328 | +0.0028 | +9.28 |
| call_user_func_array | 0.0399 | +0.0099 | +33.02 |
| InvokeCallUserFunc | 0.0418 | +0.0118 | +39.17 |
| directImplementation | 0.0475 | +0.0175 | +58.28 |
+————————+———-+————+———+

Iterations: 100 000
Averaged over: 10
PHP 7.1.2 (cli) (built: Feb 14 2017 21:24:45)
Overall Average
+————————+———-+————+———+
| Invocation | Time (s) | Delta (s) | % |
+————————+———-+————+———+
| directFunction | 0.0043 | -0.0096 | -68.92 |
| directStatic | 0.0050 | -0.0089 | -64.04 |
| directInstance | 0.0058 | -0.0081 | -58.22 |
| directLambda | 0.0063 | -0.0075 | -54.44 |
| directClosure | 0.0081 | -0.0058 | -41.57 |
| call_user_func | 0.0139 | | |
| call_user_func_array | 0.0147 | +0.0008 | +5.84 |
| Invoke | 0.0187 | +0.0048 | +34.61 |
| ClosureFactory | 0.0207 | +0.0069 | +49.43 |
| assignedClosureFactory | 0.0219 | +0.0080 | +57.75 |
| directImplementation | 0.0232 | +0.0094 | +67.53 |
| InvokeCallUserFunc | 0.0264 | +0.0126 | +90.67 |
+————————+———-+————+———+

A good use for call_user_func(); is for recursive functions.
If you’re distributing code, you will often come across users who will rename functions and break the code..
Use this: call_user_func(__FUNCTION__, . ); inside a function to call itself with whatever parameters you want.

// example, an extremely simplified factorial calculator..
// it’s quite obvious when someone renames the function, it’ll spit out an error because it wants to call itself.
function Factorial ( $i = 1 ) return( $i == 1 ? 1 : $i * Factorial ( $i — 1 ));
>

// you can give this function whatever name you want, it’ll always work, of course if you initially call it using the name you gave it.
function qwertyuiop ( $i = 1 ) return( $i == 1 ? 1 : $i * call_user_func ( __FUNCTION__ , $i — 1 ));
>
?>

Just that I didn’t see any reference to recursive functions when user_call_func(); really helps.

You don’t need to use this function to call a variable class function. Instead you can do the following:

The example works in PHP 5 from within the class. It is the <> that do the trick.

Updating «insta at citiesunlimited dot com»‘s benchmarking for PHP 7.1.17 we have an INVERSION of results between using variables and call_user_func():

Variable functions took 0.0020599365234375 seconds.
call_user_func took 0.00094509124755859 seconds.
eval took 0.024421215057373 seconds.

So, call_user_func() is now actually the way to go in PHP 7.1+.

function fa () < return 1 ; >
function fb () < return 1 ; >
function fc ()

$calla = ‘fa’ ;
$callb = ‘fb’ ;
$callc = ‘fc’ ;

$time = microtime ( true );
for( $i = 5000 ; $i —; ) $x = 0 ;
$x += $calla ();
$x += $callb ();
$x += $callc ();
if( $x != 3 ) die( ‘Bad numbers’ );
>
echo( «Variable functions took » . ( microtime ( true ) — $time ) . » seconds.
» );

$time = microtime ( true );
for( $i = 5000 ; $i —; ) $x = 0 ;
$x += call_user_func ( ‘fa’ , » );
$x += call_user_func ( ‘fb’ , » );
$x += call_user_func ( ‘fc’ , » );
if( $x != 3 ) die( ‘Bad numbers’ );
>
echo( «call_user_func took » . ( microtime ( true ) — $time ) . » seconds.
» );

$time = microtime ( true );
for( $i = 5000 ; $i —; ) $x = 0 ;
eval( ‘$x += ‘ . $calla . ‘();’ );
eval( ‘$x += ‘ . $callb . ‘();’ );
eval( ‘$x += ‘ . $callc . ‘();’ );
if( $x != 3 ) die( ‘Bad numbers’ );
>
echo( «eval took » . ( microtime ( true ) — $time ) . » seconds.
» );

public function hello ( $str )

[ $obj , ‘hello’ ]( ‘World’ ); // the array can be called as a function

>phil at gettcomm dot com
>22-May-2002 04:51
>if you need to get a reference back from a method, you can work around
>call_user_func()’s shortcomings like this:
>
Naaa! Having back a reference is a real problem, but it can be solved by mean of eval(), instead of using call_user_func:

class Node <
var $name ;
var $child ;
function Node ( $name ) < $this ->name = $name ; >
function & getChild () < return $this ->child ; >
>
$p = new Node ( ‘Father’ );
$c = new Node ( ‘Child’ );
$p -> child = & $c ;

eval ( «\\ $cref = &\\ $p -> getChild ();» );
$cref -> name = ‘Another Child’ ;

// Prints out ‘Another Child’
echo «****** After eval c keyword»>. $c -> name . «\\n\\n» ;

The previous note I posted had an error in the source code. That has been corrected in this note.

Note, that returning by reference does not work properly when the function
is called using call_user_func.

This example illustrates the problem.

print «result:» . $result . «
\n» ;
print «globalVar: » . $globalVar . «
\n» ;

print «result2: » . $result2 . «
\n» ;
print «globalVar: » . $globalVar . «
\n» ;
?>

The above code results in the following output .
Note that $result is not a reference to $globalVar.

result:0
globalVar: 0
result2: 3
globalVar: 3

Also, the use of call_user_method is now deprecated in favor of passing
array( &$object, $method ) as the function to call_user_func. This is
reported when error reporting is set to E_ALL in the latest versions of
PHP.

An entirely OO solution to add dynamicly methods to classes, I used in a project:
class ProductPart

protected $data ;
protected $plugins = array();
function __construct ( $data )

>
public function register ( ProductPlugin $plugin )

if(! in_array ( $plugin , $this -> plugins ))

$this -> plugins [ $plugin -> toString ()] = $plugin ;
> else throw new Exception ( ‘Function allready defined’ );
>
>
public function unregister ( ProductPlugin $plugin ) if(isset( $this -> plugins [ $plugin -> toString ()])) unset( $this -> plugins [ $plugin -> toString ()]);
> else throw new Exception ( ‘No such function’ );
>

protected function __call ( $method , $args ) if(isset( $this -> plugins [ $method ])) array_unshift (& $args , $this -> data );
array_unshift (& $args , $this );
return $this -> plugins [ $method ]-> run ( $args [ 0 ], $args [ 1 ], $args [ 2 ]);

> else throw new Exception ( ‘No such function’ );
>
>
> ?>

I simplified the class somewhat for clearity.

With this class, you can dynamicly add and remove classes by calling register or unregister. Register will store the object in an associative array by calling toString (as defined by ProductPlugin) and saving the method under the returned string in the array. (In this case the name of the method the class adds.)

When a method is called, which isn’t standard in the object, _call will lookup the called method in the array. If found, __call run the method of the plugin with the provided arguments. I restricted the user provided argument to 1, because I want to force the user to use associative arrays.

Because I chose an array to store my classes, removing a function is quite simple. However the unregister function isn’t optimal, I better pass a string instead of a plugin object. I didn’t test it yet on performance.

abstract class ProductPlugin protected $name = null ;
abstract public function run ( $obj , $data , $args );
public function __construct ( $data = null )

if( $this -> name === null ) throw new Exception ( ‘Name must be defined’ );
>
$this -> init ( $data );
>
protected function init ( $data )

>
public function toString () return $this -> name ;
>
>

?>

And at last some demonstration code:

$bla = new ProductPart (array( ‘HelloWorld’ => ‘Hello world’ ));
$hello = new helloPlugin ();
$bla -> register ( $hello );
$bla -> HelloWorld ();
$bla -> unregister ( $hello );
$bla -> HelloWorld ();

Источник

Читайте также:  Php xml удалить ноду
Оцените статью