【问题标题】:__call() method explanation__call() 方法说明
【发布时间】:2015-09-21 20:25:03
【问题描述】:

我有这部分代码:

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 //不明白这个输出是怎么组合起来的?!
2__构造21
关闭0

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

【问题讨论】:

    标签: php methods magic-methods


    【解决方案1】:
    1. 第一个例子

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

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

      $args_num = func_num_args();
      回声 $args_num; //输出:3
      

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

      $this->__construct3(func_get_args());

      这是不可访问的,意味着 __call() 被调用。在那个神奇的方法中,您打印名称,这里是 __construct3 和参数的数量,这里是参数数组,表示 1

      输出:

      3__construct31
      
    2. 第二个例子

      $o = new FTPClient();

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

      $args_num = func_num_args();
      回声 $args_num; //输出:0
      

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

      $this->__construct(func_get_args());

      并且构造函数是可调用的,所以__call() 不会在这里被调用。而是再次调用构造函数,但使用一个数组,其中包含参数数组,这里是一个空数组。

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

      $args_num = func_num_args();
      回声 $args_num; //输出:1
      

      之后你尝试调用方法__construct1():

      $this->__construct1(func_get_args());

      现在__construct1() 不可访问,这意味着__call() 被触发。在那个神奇的方法中,您打印名称,这里是 __construct1 和参数的计数,这里是一个带有参数数组的数组,表示 1

      输出:

      01__construct11
      

    注意事项:

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

    【讨论】:

    • 我比我更喜欢这个答案,它更干净。
    • @RocketHazmat 当您在答案中使用编号列表时,我是否注意到格式化有什么痛苦?! :]
    • 是的,你需要使用8个空格而不是4个来获得一个代码块,但是编辑器没有意识到,所以你需要手动添加这些空格~
    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案3】:

      你的第二行是:

      $o = new FTPClient();
      

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

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

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

      您使用 0 args 运行函数,所以它变成了 __construct。由于此函数存在,它不会触发__call 函数。然后你调用__construct 传递它func_get_args()(它会返回一个空数组)。

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

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

      附: 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());
      

      【讨论】:

        猜你喜欢
        • 2013-07-19
        • 2020-10-31
        • 2013-11-10
        • 2011-12-24
        • 2013-09-15
        • 1970-01-01
        • 2015-10-05
        • 1970-01-01
        • 2011-06-22
        相关资源
        最近更新 更多