变量函数

PHP 支持变量函数的概念。这意味着如果一个变量名后面附加了圆括号,PHP 将查找与该变量计算结果相同的名称的函数,并尝试执行它。除其他外,这可用于实现回调、函数表等。

变量函数不适用于语言结构,如 echoprintunset()isset()empty()includerequire 等。使用包装函数来利用这些结构作为变量函数。

示例 #1 变量函数示例

<?php
function foo() {
echo
"在 foo() 中<br />\n";
}

function
bar($arg = '')
{
echo
"在 bar() 中;参数为 '$arg'.<br />\n";
}

// 这是围绕 echo 的包装函数
function echoit($string)
{
echo
$string;
}

$func = 'foo';
$func(); // 这调用了 foo()

$func = 'bar';
$func('test'); // 这调用了 bar()

$func = 'echoit';
$func('test'); // 这调用了 echoit()
?>

对象方法也可以使用变量函数语法调用。

示例 #2 变量方法示例

<?php
class Foo
{
function
Variable()
{
$name = 'Bar';
$this->$name(); // 这调用了 Bar() 方法
}

function
Bar()
{
echo
"这是 Bar";
}
}

$foo = new Foo();
$funcname = "Variable";
$foo->$funcname(); // 这调用了 $foo->Variable()

?>

调用静态方法时,函数调用比静态属性运算符优先级更高。

示例 #3 使用静态属性的变量方法示例

<?php
class Foo
{
static
$variable = '静态属性';
static function
Variable()
{
echo
'方法 Variable 被调用';
}
}

echo
Foo::$variable; // 这将打印 '静态属性'。它在这个作用域中不需要 $variable。
$variable = "Variable";
Foo::$variable(); // 这调用了 $foo->Variable(),读取了在这个作用域中的 $variable。

?>

示例 #4 复杂的可调用对象

<?php
class Foo
{
static function
bar()
{
echo
"bar\n";
}
function
baz()
{
echo
"baz\n";
}
}

$func = array("Foo", "bar");
$func(); // 打印 "bar"
$func = array(new Foo, "baz");
$func(); // 打印 "baz"
$func = "Foo::bar";
$func(); // 打印 "bar"
?>

添加备注

用户贡献的笔记 7 条笔记

23
niemans at pbsolo dot nl
5 年前
虽然文档表明常量的使用类似于变量的使用,但关于变量函数有一个例外。您不能使用常量作为函数名来调用变量函数。

const DEBUGME ='func';
function func($s) { echo $s. "\n"; }

DEBUGME('abc'); // 导致语法错误

$call = DEBUGME;
$call('abc'); // 完成任务

但是您可以将常量用作函数的参数。当您需要调用可变常量函数时,这里有一个简单的解决方法

function dynamic($what, $with)
{
$what($with);
}
dynamic(DEBUGME, 'abc');

在我看来,这有助于隐藏 API 和/或较长的(复杂的)静态调用。
享受!
2
rnealxp at yahoo dot com
4 年前
<?php
/*
你可能是在这个 PHP 变量函数页面上找到自己的,因为,像我一样,你想像在 JavaScript 中一样将函数像对象一样传递给客户端对象。我遇到的问题是,虽然
我可以使用变量像这样调用函数 “ $v(); ”...但我不能像这样使用它 “ $obj->p() ”,其中
'p' 是包含要调用方法名称的属性。不希望在进行调用之前将我的属性保存到变量中: “ $v = $obj->p; $v(); ”;即使找到方法,下面也适用...

我将此扩展工作归功于这个人:tatarynowicz at gmail dot com;
没有他们,我就不会到达这里。
*/
interface iface_dynamic_members{
// 使用此接口可以对实现它的对象进行类型提示。
public function __call($name, $args);
public function
__set($name, $value);
public function
quietly_fail():bool;
}
trait
trait_has_dynamic_members{
// 以特征形式实现这些魔术方法,使客户端对象可以
// 因此它仍然可以从父类继承。
public function __call($name, $args) {
if (
is_callable($this->$name)) {
return
call_user_func($this->$name, $args);
}
else {
// 您的动态成员对象可以声明自己是否愿意忽略不存在的方法调用。
if($this->quietly_fail()===true){
echo
'方法不存在,但我并不介意';
}else{
echo
'方法不存在,我认为这是一个错误';
}
}
}
public function
__set($name, $value) {
$this->$name = is_callable($value) ? $value->bindTo($this, $this): $value; // 使用三元运算符进行赋值。
}
}
abstract class
MBR_ATTR{
// 一类对象可以具有的属性;抽象的,因为不能实例化(如果可以,我也会把它设为“final”)。
public static function is_a_walker(iface_dynamic_members $obj, ?string $walker_type='normal pace'){
$obj->walker_type = $walker_type;
$obj->walker_walk = function() {
return
"我正在走 {$this->walker_type}.";
};
}
public static function
is_a_runner(iface_dynamic_members $obj, string $runner_type){
$obj->runner_type = $runner_type;
$obj->runner_run = function() {
return
"我正在跑 {$this->runner_type}.";
};
self::is_a_walker($obj); // 如果能跑,也能走。
}
}
class
cls_partly_dynamic implements iface_dynamic_members{
use
trait_has_dynamic_members;
public function
quietly_fail():bool{
return
true;
}
}
// 报告所有错误,除了 E_NOTICE
error_reporting(E_ALL & ~E_NOTICE); // 启用所有错误报告,除了通知。
//----
// 配置运行器对象...
$obj_runner = new cls_partly_dynamic();
MBR_ATTR::is_a_runner($obj_runner, 'fast');
$obj_runner->runner_type = 'a bit slow';
//----
// 配置步行者对象...
$obj_walker = new cls_partly_dynamic();
MBR_ATTR::is_a_walker($obj_walker, 'slow');
$obj_walker->walker_type = 'super fast';
//----
// 做些事情...
echo '步行者在行动...' . '<br>';
echo
$obj_walker->walker_walk() . '<br>';
echo
'<br>';
echo
'跑步者在行动...' . '<br>';
echo
$obj_runner->walker_walk() . '<br>';
echo
$obj_runner->runner_run() . '<br>';
echo
$obj_runner->xxx() . '<br>'; // 尝试调用不存在的方法。
// 我同意以上方法/技术并不总是理想的,特别是由于您在
// 选择的 IDE 中丢失了代码完成;我倾向于在用户通过 UI 指定处理步骤时使用此方法进行动态编程。
?>
4
匿名
13 年前
$ wget https://php.net/get/php_manual_en.tar.gz/from/a/mirror
$ grep -l "\$\.\.\." php-chunked-xhtml/function.*.html

接受可变参数的函数列表。
<?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()
?>
0
justusofnigeria at gmail dot com
3 天前
对于任何需要知道这一点的人来说,您可以直接将变量作为函数调用。

$variable_holding_a_function = function () {

return "这是一个返回值";
};

$result = $variable_holding_a_function();

echo $result;
-7
匿名
4 年前
如果您在这里寻找函数引用,这不是这样做的方式。

<?php
function func1(){ echo "hell0 1";}
$choice = func1; // 没有引号
?>

它有效,但 $choice 并不像您想象的那样,是对函数的引用。它只是一个字符串,没有 (!) 引号,只是函数的名称。

它与以下相同
<?php
$choice
= "func1"; // 带引号
?>

您可以执行 echo gettype($choice) 来确认。

因此调用
<?php
$choice
()
?>
对于这两种情况都是一个变量函数,通过名称调用它,而不是通过引用。

通过分配的匿名函数获得对函数的引用
<?php
$func1
= function(){ echo "hell0 1";}
$func1 = function(){ echo "hell0 2";}
?>

现在您可以像一等公民对象一样传递函数
<?php
$choice
= $func1;
?>
或者
<?php
$choice
= $func2;
?>
并调用它
<?php
$choice
();
?>

如果你想传递一个类方法,请使用手册中上面的“复杂可调用”。它是一个按名称调用(而不是引用),但由于你可以包含对象,你仍然可以获得你想要的灵活性。

<?php
class C {
function
k(){ echo "inside k";}
function
j(){ echo "inside j"; return array($this,"k");}};
?>

你可以使用 $this 作为数组中第一个元素的对象。
<?php
$c
= new C;
$c->k();
inside k

$func
= $c->j();
inside j
?>
现在,最高时刻
<?php
$func
();
inside k
?>
-6
anisgazig at gmail dot com
2 年前
<?php
static bar 方法适用于静态或非静态,而非static 方法不能静态工作

//非静态方法
class myCls{
public function
foo(){
echo
"foo function";
}
static public function
bar(){
echo
"static bar function";

}
}

$a = new myCls;
$myf = "foo";
$a->$myf();//有效
echo "\n";

$a = [new myCls,"foo"];//有效
$a();
echo
"\n";
//$a = ["myCls","foo"];//致命错误
//$a();
echo "\n";
//$a = "myCls::foo";//致命错误
//$a();
echo "\n";

//静态方法用静态或非静态调用
$b = new myCls;
$myf = "bar";
$b->$myf();//有效
echo "\n";

$b = [new myCls,"bar"];//有效
$b();
echo
"\n";

$b = "myCls::bar";//有效
$b();
echo
"\n";

$b = ["myCls","bar"];//有效
$b();
echo
"\n";
-16
josh at joshstroup dot xyz
8 年前
一个小而有用的提示。如果你试图从不同的命名空间调用静态函数,你必须使用完全限定的命名空间,即使它们具有相同的顶级命名空间。例如,如果你有以下要调用的类

<?php
namespace Project\TestClass;
class
Test {
static function
funcToCall() {
return
"test";
}
}
?>
你必须像这样调用它
<?php
namespace Project\OtherTestClass;
class
OtherTest {
static function
callOtherFunc() {
$func = '\Project\TestClass::funcToCall';
$func();
}
}
?>
而不是
<?php
class OtherTest {
static function
callOtherFunc() {
$func = 'TestClass::funcToCall';
$func();
}
}
?>
To Top