__call()方法说明

时间:2015-09-21 20:25:04

标签: php methods magic-methods

我有这部分代码:

class FTPClient
{
    public function __construct() {
        $args_num=func_num_args();
        echo $args_num;
        $this->{"__construct".($args_num===0 ? '' : $args_num)}(func_get_args());
    }

    function __call($name,$args) {
        echo $name,count($args),'<br/>';
    }

    public function open() {
        echo 'open';
    }
}
    $o = new FTPClient('127.0.0.1','user','pass');
    $o = new FTPClient();
    $o = new FTPClient('127.0.0.1','user');
    $o->close();

输出如下:

3__construct31
01__construct11 //Don't understand how this output came together?!
2__construct21
close0

有人会这么善良并且可以向我解释这个输出的第二行吗?

3 个答案:

答案 0 :(得分:5)

  1. 第一个例子

    $o = new FTPClient('127.0.0.1','user','pass');

    你有3个参数,意味着3用这一行打印:

    $args_num = func_num_args();
    echo $args_num;  //output: 3
    

    之后,您尝试调用方法__construct3()

    $this->__construct3(func_get_args());

    无法访问,意味着__call()被调用。在该魔术方法中,您打印名称,此处为 __construct3 ,参数计数(此处为参数数组)表示 1

    输出:

    3__construct31
    
  2. 第二个例子

    $o = new FTPClient();

    你有0个参数,意味着0用这一行打印:

    $args_num = func_num_args();
    echo $args_num;  //output: 0
    

    之后你试图调用方法__construct(),构造函数:

    $this->__construct(func_get_args());

    构造函数是可调用的,因此{}不会调用__call()。而是再次调用构造函数,但是使用一个包含参数数组的数组,这里是一个空数组。

    现在在第二个电话中你有1个参数,意味着1用这一行打印:

    $args_num = func_num_args();
    echo $args_num;  //output: 1
    

    之后,您尝试调用方法__construct1()

    $this->__construct1(func_get_args());

    现在__construct1()无法访问,意味着__call()被触发。在这种魔术方法中,您可以打印名称,此处为 __construct1 ,参数计数(此处为带参数数组的数组)表示 1

    输出:

    01__construct11
    
  3. 备注:

      当您尝试调用无法访问的方法时,
    • __call()会被触发。

答案 1 :(得分:2)

当您使用零参数运行构造函数时,将再次调用构造函数本身。由于构造函数是一个有效的方法,因此不会在那个时间调用__call(但稍后会在调用__construct1时调用)。

你看到01,因为第一次由构造函数打印0,然后调用__construct([empty array]),打印1.然后调用__construct1,因为有一个参数(func_get_args的空数组) )) - 从而打印1__construct1(然后打印1)。

或许你的意思是将参数直接传递给构造函数而不是数组?

如果您打印出更多信息(例如正在进行打印的方法)以及在$args_num之后打印换行符,您会发现这更有意义。那会让这个答案看起来更加混乱!

答案 2 :(得分:1)

你的第二行是:

$o = new FTPClient();

运行带有0个参数的__construct(),从而打印0

然后,它生成一个要调用的函数名称:

"__construct".($args_num===0 ? '' : $args_num)

你运行了0参数的函数,所以这只是__construct。由于此函数存在,因此它不会触发__call函数。然后调用__construct传递它func_get_args()(返回一个空数组)。

然后__construct再次运行 并带有1个参数(一个空数组),从而打印1

然后生成函数名__construct1,调用后触发__call。你调用__construct1传递它func_get_args(),这是一个包含一个元素的数组,是之前的空数组。

P.S。 count($args) 总是 1,因为您正在做:

$this->{"__construct".($args_num===0 ? '' : $args_num)}(func_get_args());

这会调用该函数并将其传递给一个参数。一个数组。

如果您想展开该数组并将每个元素作为自己的参数传递,那么您需要使用call_user_func_array

call_user_func_array([$this, "__construct".($args_num===0 ? '' : $args_num)], func_get_args());