__call() 方法解释

__call() method explanation

我有这部分代码:

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

有好心人可以解释一下这个输出的第二行吗?

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

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

也许您的意思是将参数直接传递给构造函数,而不是在数组中?

如果您打印出更多信息(例如打印的方法)并在 $args_num 之后打印换行符,您会发现这更有意义。这会让这个答案看起来不那么令人困惑!

你的第二行是:

$o = new FTPClient();

使用 0 个参数运行 __construct(),因此打印 0

然后,它生成一个函数名来调用:

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

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

然后 __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());
  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
    

备注:

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