何时使用 call_user_func_array
When to use call_user_func_array
我已经阅读了 stack 上关于使用 call_user_func_array
与仅调用该函数的其他答案,但我仍然无法了解何时应该使用前者。我知道当您不知道传递了多少个参数时,您可能想使用 call_user_func_array
,因此您可以这样做:$args = func_get_args();
... 但是您是否总是需要知道参数,如果它们将在函数中使用?
以下两项工作,我假设第一项的开销较小。
$format = new Foo;
$method = 'somemethod';
$arg = 'somevalue';
if (method_exists($format, $method)) {
return $format->$method($arg);
}
对
return call_user_func_array(array($format, $method), array($arg));
什么时候才能真正受益于使用 call_user_func_array
?
call_user_func_array 非常有用的例子
假设您想要访问一个对象,但是通过静态方法,就像这样:
Helper::load();
好吧,它本身是行不通的,因为如果你看一下具体的 class 它没有静态方法:
class Helper {
public function load()
{
// Do some loading ...
}
public function aFunctionThatNeedsParameters( $param1, $param2 )
{
// Do something, and $param1 and $param2 are required ...
}
}
所以在一秒钟内class,我们可以做这样的事情,因为上面的Helperclass被加载到依赖注入容器中(注意这两个Helperclasses命名相同,但会在不同的命名空间中):
class Helper extends DIContainer {
public static $helper_instance = NULL;
public static function get_instance()
{
if( is_null( self::$helper_instance ) )
{
self::$helper_instance = parent::$container['helper'];
}
return self::$helper_instance;
}
public static function __callStatic( $method, $params )
{
$obj = self::get_instance();
return call_user_func_array( [ $obj, $method ], $params );
}
}
问题是,可能还有其他方法需要参数,即使我们的加载方法没有参数。
所以在这种情况下我们可以使用Helper::load()
,但也可以使用Helper::aFunctionThatNeedsParameters( $param1, $param2 )
我认为这在 PHP 框架中被大量使用,这些框架知道静态 classes 通常不合适,但他们希望能够像调用静态方法一样调用方法。我希望这是有道理的。
David Sklar 解决了何时使用 call_user_func_array in his PHP Cookbook 的问题。因此,关注 OP 的一条评论:
"...don't you always need to know the arguments if they are to be used
in a function?"
这是 call_user_func() 可以派上用场的例子:
<?php
function Test(){
$args = func_get_args();
call_user_func_array("printf",$args);
}
Test("Candidates 2014: %s %s %s %s\n","Tom","Debbie","Harry", "Sally");
Test("Candidates 2015: %s %s\n","Bob","Sam","Sarah");
有了一对 call_user_func_array() 和 func_get_args(),用户定义的函数 Test() 可以接受可变数量的参数。
此外,对于聚合方法也很有用(参见 PHP Cookbook p208-210),如以下简化示例所示:
<?php
class Address {
protected $city;
public function getCity() {
return $this->city;
}
public function setCity($city) {
$this->city=$city;
}
}
class Person {
protected $name="Tester";
protected $address;
public function __construct() {
$this->address = new Address;
}
public function getName(){
return $this->name;
}
public function __call($method, $args){
if (method_exists($this->address,$method)) {
return call_user_func_array( array($this->address,$method),$args);
}
}
}
$sharbear = new Person;
echo $sharbear->setCity("Baltimore");
echo "Name: ",$sharbear->getName(),"\n";
echo "City: ",$sharbear->getCity();
参见 live code
附录
因为 PHP 5.6,PHP 支持 variadic functions and argument unpacking,所以 call_user_func() 和 func_get_args() 可以根据变量参数替换为如下:
<?php
function Test(...$args){
printf(...$args);
}
$namesT = ["Timmy","Teddy","Theo","Tad"];
$namesB = ["Bobby","Bill","Brad"];
Test("T Names: %s %s %s %s\n",...$namesT);
Test("B Names: %s %s %s\n",...$namesB);
<!-- begin snippet: js hide: false console: true babel: false -->
<pre>
I use call_user_func_array when I need to call a function or php function from my ajax enabled page.
eg.
in html and javascript:
<form id='my-form'>
<input id='name' value='Wong, Billy'>
<input id='age' value='50'>
<a href='javascript;' onClick="xjx.query('helloWorld', $('#name').val(), $('#age').val())">Show name and age</a>
<a href='javascript;' onClick="xjx.query('showName', $('#name').val())">Show name</a>
<a href='javascript;' onClick="xjx.query('showAge', $('#age').val())">Show age</a>
<a href='javascript;' onClick="xjx.post('#my-form', 'showPost', 'live long and prosper')">Show age</a>
</form>
xjx.query and xjx.post, personal javascript functions of mine will then format and submit to the php page via ajax
in php
$method = $_POST['method'];
$args = $_POST['args'];
call_user_func_array($method, $args)
function helloWorld($name, $age) {
....
}
function showName($name) {
....
}
function showAge($age) {
....
}
function showPost($f, $message) {
print_r($f);
echo $message;
}
my libs are found in github with xjx as the project name
</pre>
假设我们有几个 类
class Request
{
private $req;
public function __construct($req)
{
$this->req = $req;
}
public function __call($name, $arg)
{
return \call_user_func_array(array($this->req,$name), $arg);
}
}
class Get
{
public function load($url)
{
// fire an http request
}
}
class Post
{
public function load($url)
{
// fire an http request
}
public function attachHeader($header=[])
{
// attach an header to the request
}
}
$request_1 = new Request(new Get());
$request_1->load($url);
$request_2 = new Request(new Post());
$request_2->attachHeader($header_data);
$request_2->load($url);
在这里你可以看到我们可以使用 call_user_func_array()
调用 attachHeader()
方法
没问题。
希望对你有所帮助
我已经阅读了 stack 上关于使用 call_user_func_array
与仅调用该函数的其他答案,但我仍然无法了解何时应该使用前者。我知道当您不知道传递了多少个参数时,您可能想使用 call_user_func_array
,因此您可以这样做:$args = func_get_args();
... 但是您是否总是需要知道参数,如果它们将在函数中使用?
以下两项工作,我假设第一项的开销较小。
$format = new Foo;
$method = 'somemethod';
$arg = 'somevalue';
if (method_exists($format, $method)) {
return $format->$method($arg);
}
对
return call_user_func_array(array($format, $method), array($arg));
什么时候才能真正受益于使用 call_user_func_array
?
call_user_func_array 非常有用的例子
假设您想要访问一个对象,但是通过静态方法,就像这样:
Helper::load();
好吧,它本身是行不通的,因为如果你看一下具体的 class 它没有静态方法:
class Helper {
public function load()
{
// Do some loading ...
}
public function aFunctionThatNeedsParameters( $param1, $param2 )
{
// Do something, and $param1 and $param2 are required ...
}
}
所以在一秒钟内class,我们可以做这样的事情,因为上面的Helperclass被加载到依赖注入容器中(注意这两个Helperclasses命名相同,但会在不同的命名空间中):
class Helper extends DIContainer {
public static $helper_instance = NULL;
public static function get_instance()
{
if( is_null( self::$helper_instance ) )
{
self::$helper_instance = parent::$container['helper'];
}
return self::$helper_instance;
}
public static function __callStatic( $method, $params )
{
$obj = self::get_instance();
return call_user_func_array( [ $obj, $method ], $params );
}
}
问题是,可能还有其他方法需要参数,即使我们的加载方法没有参数。
所以在这种情况下我们可以使用Helper::load()
,但也可以使用Helper::aFunctionThatNeedsParameters( $param1, $param2 )
我认为这在 PHP 框架中被大量使用,这些框架知道静态 classes 通常不合适,但他们希望能够像调用静态方法一样调用方法。我希望这是有道理的。
David Sklar 解决了何时使用 call_user_func_array in his PHP Cookbook 的问题。因此,关注 OP 的一条评论:
"...don't you always need to know the arguments if they are to be used in a function?"
这是 call_user_func() 可以派上用场的例子:
<?php
function Test(){
$args = func_get_args();
call_user_func_array("printf",$args);
}
Test("Candidates 2014: %s %s %s %s\n","Tom","Debbie","Harry", "Sally");
Test("Candidates 2015: %s %s\n","Bob","Sam","Sarah");
有了一对 call_user_func_array() 和 func_get_args(),用户定义的函数 Test() 可以接受可变数量的参数。
此外,对于聚合方法也很有用(参见 PHP Cookbook p208-210),如以下简化示例所示:
<?php
class Address {
protected $city;
public function getCity() {
return $this->city;
}
public function setCity($city) {
$this->city=$city;
}
}
class Person {
protected $name="Tester";
protected $address;
public function __construct() {
$this->address = new Address;
}
public function getName(){
return $this->name;
}
public function __call($method, $args){
if (method_exists($this->address,$method)) {
return call_user_func_array( array($this->address,$method),$args);
}
}
}
$sharbear = new Person;
echo $sharbear->setCity("Baltimore");
echo "Name: ",$sharbear->getName(),"\n";
echo "City: ",$sharbear->getCity();
参见 live code
附录
因为 PHP 5.6,PHP 支持 variadic functions and argument unpacking,所以 call_user_func() 和 func_get_args() 可以根据变量参数替换为如下:
<?php
function Test(...$args){
printf(...$args);
}
$namesT = ["Timmy","Teddy","Theo","Tad"];
$namesB = ["Bobby","Bill","Brad"];
Test("T Names: %s %s %s %s\n",...$namesT);
Test("B Names: %s %s %s\n",...$namesB);
<!-- begin snippet: js hide: false console: true babel: false -->
<pre>
I use call_user_func_array when I need to call a function or php function from my ajax enabled page.
eg.
in html and javascript:
<form id='my-form'>
<input id='name' value='Wong, Billy'>
<input id='age' value='50'>
<a href='javascript;' onClick="xjx.query('helloWorld', $('#name').val(), $('#age').val())">Show name and age</a>
<a href='javascript;' onClick="xjx.query('showName', $('#name').val())">Show name</a>
<a href='javascript;' onClick="xjx.query('showAge', $('#age').val())">Show age</a>
<a href='javascript;' onClick="xjx.post('#my-form', 'showPost', 'live long and prosper')">Show age</a>
</form>
xjx.query and xjx.post, personal javascript functions of mine will then format and submit to the php page via ajax
in php
$method = $_POST['method'];
$args = $_POST['args'];
call_user_func_array($method, $args)
function helloWorld($name, $age) {
....
}
function showName($name) {
....
}
function showAge($age) {
....
}
function showPost($f, $message) {
print_r($f);
echo $message;
}
my libs are found in github with xjx as the project name
</pre>
假设我们有几个 类
class Request
{
private $req;
public function __construct($req)
{
$this->req = $req;
}
public function __call($name, $arg)
{
return \call_user_func_array(array($this->req,$name), $arg);
}
}
class Get
{
public function load($url)
{
// fire an http request
}
}
class Post
{
public function load($url)
{
// fire an http request
}
public function attachHeader($header=[])
{
// attach an header to the request
}
}
$request_1 = new Request(new Get());
$request_1->load($url);
$request_2 = new Request(new Post());
$request_2->attachHeader($header_data);
$request_2->load($url);
在这里你可以看到我们可以使用 call_user_func_array()
调用 attachHeader()
方法
没问题。
希望对你有所帮助