當方法名、類名在運行時才確定(如路由分發、插件系統、策略模式),call_user_func 和 call_user_func_array 是實現動態調用的核心工具。
function greet($name, $suffix) {
echo "Hello, $name$suffix";
}
call_user_func('greet', 'World', '!'); // Hello, World!
call_user_func('greet', 'PHP', '...'); // Hello, PHP...
class Utils {
public static function add($a, $b) {
return $a + $b;
}
}
$result = call_user_func(['Utils', 'add'], 10, 20); // 30
// 或
$result = call_user_func('Utils::add', 10, 20); // PHP 5.2.3+ 支持
$obj = new DateTime();
$formatter = [$obj, 'format'];
echo call_user_func($formatter, 'Y-m-d'); // 當前日期
唯一區別:第二參數為 **數組**,元素依次對應函數參數。
$params = ['World', '!'];
call_user_func_array('greet', $params); // Hello, World!
// 結合 func_get_args 實現參數數量自適應
function dynamic() {
$args = func_get_args();
$count = func_num_args();
call_user_func_array("handler$count", $args);
}
function handler1($a) { echo "1 param: $a"; }
function handler2($a, $b) { echo "2 params: $a, $b"; }
dynamic('x'); // 1 param: x
dynamic('x', 'y'); // 2 params: x, y
| 特性 | call_user_func | call_user_func_array |
|---|---|---|
| 參數傳遞 | 列表展開 | 數組打包 |
| 動態參數數量 | 不便 | 天然支持 |
| 性能 | 略快(無需打包數組) | 微弱差異 |
| 引用傳遞 | 支持 &$var | 支持 &$arr[0] |
function increment(&$num) { $num++; }
$val = 0;
call_user_func('increment', &$val); // $val = 1
call_user_func_array('increment', [&$val]); // $val = 2
// 參數解包操作符 ... (更直觀、性能更好)
$params = ['World', '!'];
greet(...$params); // 替代 call_user_func_array
$obj->method(...$params); // 替代 call_user_func([$obj, 'method'], ...)
// 類名/方法名動態調用
$class = 'Utils';
$method = 'add';
$class::$method(...[10, 20]); // 靜態
($obj)->$method(...[10, 20]); // 實例
掌握動態調用,是構建靈活、可擴展 PHP 架構的關鍵技能之一。