【问题标题】:PHP use __get to call a method?PHP使用__get调用方法?
【发布时间】:2012-02-28 12:03:32
【问题描述】:

我有一些 PHP 杂乱,我想委托方法。有点像穷人的混音。

基本上我想要以下内容:

<?php

class Apprentice
{
    public function magic() {
        echo 'Abracadabra!';
    }
}

class Sourcerer // I work magic with the source
{
    private $apprentice;

    public function __construct(){
        $this->apprentice = new Apprentice();
    }

    public function __get($key) {
        if (method_exists($this->apprentice, $key)) {
            return $this->apprentice->{$key};
        }
        throw Exception("no magic left");
    }
}

$source = new Sourcerer();
$source->magic();
?>

不要抛出Fatal error: Call to undefined method Sourcerer::magic() in .../test__get.php

【问题讨论】:

    标签: php class delegation


    【解决方案1】:
    public function __call($name, $args) {
        if (method_exists($this->apprentice, $name)) {
            return $this->apprentice->$name($args);
        }
        throw Exception("no magic left");
    }
    

    ps:__call 用于方法,因为__get 仅用于属性。 是的,最好使用call_user_func_array,否则参数将作为数组提供给magic 函数。

    return call_user_func_array(array($this->apprentice, $name), $args);
    

    【讨论】:

    • 这个++。 __call 是您真正想要的。此外,如果您将来想在静态函数中使用这种功能,您可能需要研究 __callStatic。
    • 哦……我完全误读了文档,我认为__call() 是为了调用一个实例,就好像它是一个函数一样,它是为了实现$s = new S(); $s();。谢谢!
    • @quodlibetor 方法__invoke 用于调用实例,就好像它是一个函数一样。
    【解决方案2】:
    1. 要实际调用apprentice 上的方法,您必须像这样实际调用它:

      return $this->apprentice->$key();
      
    2. 您正在使用$source-&gt;magic(),它不会调用__get 方法。 __get 用于像$source-&gt;magic 这样的变量访问,但$source-&gt;magic() 是一个函数调用。如果你想要一个函数调用的神奇方法,那就是__call

    【讨论】:

      【解决方案3】:

      在你的情况下更像__call 而不是__get

      class Sourcerer // I work magic with the source
      {
          private $apprentice;
      
          public function __construct(){
              $this->apprentice = new Apprentice();
          }
      
          public function __call($name, $arguments) {
              if (method_exists($this->apprentice, $name)) {
                  return call_user_func_array(array($this->apprentice, $name), $arguments);
              }
              throw Exception("no magic left");
          }
      }
      

      【讨论】:

        【解决方案4】:

        您的电话将改为:

        $source = new Sourcerer();
        $source->apprentice->magic();
        

        另外,我相信 __get() 魔术方法适用于属性,而不是方法名称。

        最后,在你实际的__get() 定义中,语法是错误的:它应该是throw new Exception('message');。我也将其移至 else 子句,否则每次调用都会触发它,因为它在任何 if/else 或其他逻辑之外。

        【讨论】:

        • 您对语法的看法是正确的,而对else 的必要性的看法是错误的(if 有返回值。)但是我试图避免查找链。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-10
        • 2010-12-26
        • 2012-04-05
        • 2015-07-23
        • 2017-07-21
        • 1970-01-01
        相关资源
        最近更新 更多