可变函数
PHP 支持可变函数的概念。这意味着如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数,并且尝试执行它。可变函数可以用来实现包括回调函数,函数表在内的一些用途。
可变函数不能用于例如echo,print,unset(),isset(),empty(),include,require以及类似的语言结构。需要使用自己的包装函数来将这些结构用作可变函数。
Example #1 可变函数示例
<?php function foo() { echo "In foo()<br />\n"; } function bar($arg = '') { echo "In bar(); argument was '$arg'.<br />\n"; } // 使用 echo 的包装函数 function echoit($string) { echo $string; } $func = 'foo'; $func(); // This calls foo() $func = 'bar'; $func('test'); // This calls bar() $func = 'echoit'; $func('test'); // This calls echoit() ?>
也可以用可变函数的语法来调用一个对象的方法。
Example #2 可变方法范例
<?php class Foo { function Variable() { $name = 'Bar'; $this->$name(); // This calls the Bar() method } function Bar() { echo "This is Bar"; } } $foo = new Foo(); $funcname = "Variable"; $foo->$funcname(); // This calls $foo->Variable() ?>
当调用静态方法时,函数调用要比静态属性优先:
Example #3 Variable 方法和静态属性示例
<?php class Foo { static $variable = 'static property'; static function Variable() { echo 'Method Variable called'; } } echo Foo::$variable; // This prints 'static property'. It does need a $variable in this scope. $variable = "Variable"; Foo::$variable(); // This calls $foo->Variable() reading $variable in this scope. ?>
As of PHP 5.4.0, you can call any
Example #4 Complex callables
<?php class Foo { static function bar() { echo "bar\n"; } function baz() { echo "baz\n"; } } $func = array("Foo", "bar"); $func(); // prints "bar" $func = array(new Foo, "baz"); $func(); // prints "baz" $func = "Foo::bar"; $func(); // prints "bar" as of PHP 7.0.0; prior, it raised a fatal error ?>
参见is_callable(),call_user_func(),可变变量和function_exists()。
更新日志
版本 | 说明 |
---|---|
7.0.0 | 'ClassName::methodName' is allowed as variable function. |
5.4.0 | Arrays, which are valid callables, are allowed as variable functions. |
$ wget http://www.php.net/get/php_manual_en.tar.gz/from/a/mirror $ grep -l "\$\.\.\." php-chunked-xhtml/function.*.html List of functions that accept variable arguments. <?php array_diff_assoc() array_diff_key() array_diff_uassoc() array() array_intersect_ukey() array_map() array_merge() array_merge_recursive() array_multisort() array_push() array_replace() array_replace_recursive() array_unshift() call_user_func() call_user_method() compact() dba_open() dba_popen() echo() forward_static_call() fprintf() fscanf() httprequestpool_construct() ibase_execute() ibase_set_event_handler() ibase_wait_event() isset() list() maxdb_stmt_bind_param() maxdb_stmt_bind_result() mb_convert_variables() newt_checkbox_tree_add_item() newt_grid_h_close_stacked() newt_grid_h_stacked() newt_grid_v_close_stacked() newt_grid_v_stacked() newt_win_choice() newt_win_entries() newt_win_menu() newt_win_message() newt_win_ternary() pack() printf() register_shutdown_function() register_tick_function() session_register() setlocale() sprintf() sscanf() unset() var_dump() w32api_deftype() w32api_init_dtype() w32api_invoke_function() wddx_add_vars() wddx_serialize_vars() ?>
A small, but helpful note. If you are trying to call a static function from a different namespace, you must use the fully qualified namespace, even if they have the same top level namespace(s). For example if you have the following class to call: <?php namespace Project\TestClass; class Test { static function funcToCall() { return "test"; } } ?> You must call it as: <?php namespace Project\OtherTestClass; class OtherTest { static function callOtherFunc() { $func = '\Project\TestClass::funcToCall'; $func(); } } ?> and not: <?php class OtherTest { static function callOtherFunc() { $func = 'TestClass::funcToCall'; $func(); } } ?>
While the documentation suggests that the use of a constant is similar to the use of a variable, there is an exception regarding variable functions. You cannot use a constant as the function name to call a variable function. const DEBUGME ='func'; function func($s) { echo $s. "\n"; } DEBUGME('abc'); // results in a syntax error $call = DEBUGME; $call('abc'); // does the job But you can use a constant as an argument to a function. Here's a simple workaround when you need to call a variable constant function: function dynamic($what, $with) { $what($with); } dynamic(DEBUGME, 'abc'); This makes sense to me to hide API's and/or long (complicated) static calls. Enjoy!
If you want to call a static function (PHP5) in a variable method: Make an array of two entries where the 0th entry is the name of the class to be invoked ('self' and 'parent' work as well) and the 1st entry is the name of the function. Basically, a 'callback' variable is either a string (the name of the function) or an array (0 => 'className', 1 => 'functionName'). Then, to call that function, you can use either call_user_func() or call_user_func_array(). Examples: <?php class A { protected $a; protected $c; function __construct() { $this->a = array('self', 'a'); $this->c = array('self', 'c'); } static function a($name, &$value) { echo $name,' => ',$value++,"\n"; } function b($name, &$value) { call_user_func_array($this->a, array($name, &$value)); } static function c($str) { echo $str,"\n"; } function d() { call_user_func_array($this->c, func_get_args()); } function e() { call_user_func($this->c, func_get_arg(0)); } } class B extends A { function __construct() { $this->a = array('parent', 'a'); $this->c = array('self', 'c'); } static function c() { print_r(func_get_args()); } function d() { call_user_func_array($this->c, func_get_args()); } function e() { call_user_func($this->c, func_get_args()); } } $a =& new A; $b =& new B; $i = 0; A::a('index', $i); $a->b('index', $i); $a->c('string'); $a->d('string'); $a->e('string'); # etc. ?>