在PHP中调用方法概念:静态调用与对象上下文

时间:2013-08-08 14:56:15

标签: php magic-methods

SO,

我对PHP类方法调用的概念有疑问。 让我们有一个实现简单sigma动作的类,例如,总和:

class Sigma
{
   protected $_fValue = null;

   public function __construct($fValue)
   {
      $this->_fValue = (double)$fValue;
   }

   public static function __callStatic($sName, $rgArgs)
   {
      if(count($rgArgs)!=count(array_filter($rgArgs, function($mArg)
      {
         return is_object($mArg) && $mArg instanceof self;
      })))
      {
         throw new Exception('Can not call method "'.$sName.'": invalid arguments');
      }
      if(!count($rgArgs))
      {
         return null;
      }
      $rResult = array_shift($rgArgs);
      foreach($rgArgs as $mArg)
      {
         $rResult = $rResult->$sName($mArg);
      }
      return $rResult;
   }

   public function getValue()
   {
      return $this->_fValue;
   }

   public function getSigma(self $rSigma)
   {
      return new self($this->getValue()+$rSigma->getValue());
   }

}

正如您所看到的,我们可以使用它的getSigma()方法返回一个表示当前对象和输入对象的简单总和的自身实例:

$rFirst  = new Sigma(-4.5);
$rSecond = new Sigma(5);
$rThird  = $rFirst->getSigma($rSecond);
var_dump($rThird->getValue());//float(0.5) 

嗯,这里的一切都很好。但正如您所看到的,我在课堂上定义了__callStatic()方法。

我想要实现的目标是,如果我通过静态调用我的getSigma()方法,我可以传递任意数量的参数,因为我{{1} }方法有望被触发。但不幸的是,这正在发生。而不是这样,PHP直接调用我的__callStatic()方法,因为它被定义为static:

getSigma()

我理解为什么会触发致命错误 - PHP通过$rFirst = new Sigma(-4.5); $rSecond = new Sigma(5); $rFourth = Sigma::getSigma($rFirst, $rSecond);//Fatal error: Using $this when not in object context in ... 运算符调用非静态方法 - 然后,在其中使用::

所以长话短说:当非静态方法被称为静态时,有没有办法触发$this方法?或者至少如何通过__callStatic()(以及通过::的静态方法)来防止PHP'bug-or-feature'调用非静态方法?

所有这些我需要实现漂亮的界面,当我可以使用一个方法名称进行对象调用或类调用。而且,由于这是我的目标,我不能将我的非静态方法设为私有或受保护(即它们应该可以在外面使用)

2 个答案:

答案 0 :(得分:1)

不幸的是没有。只要有一个方法带有你试图调用的名称,PHP就会调用它而不考虑调用类型和方法类型。

答案 1 :(得分:0)

也许它可以通过实施__call来解决。像这样:

public function __call($name, $args) {
    if (method_exists($this, "_$name") {
        call_user_func_array(array($this, "_$name"), $args); 
    } else {
    // no method found
    }
}

private function _getSigma($somearg) {
// ...
}

修改

因此,如果您需要扩展或实现某些类,请尝试使用somekind of wrapper,在那里可以修改调用:

class SigmaWrapper {

    private static $_defaultClass = 'Sigma';
    private $_sigmaObject = null;

    public static function factory($sigmaObject) {
        // now would be good to implement some factory   
    }    

    private function setSigmaObject($obj) {
        $this->_sigmaObject = $arg;
    }

    public function __construct($arg) {
        if (is_object($arg)) {
          $this->setSigmaObject($arg);
        } else {
            $class = self::$_defaultClass;
            $this->_sigmaObject = new {$class}($fValue);
        }
    }

    public function __call($name, $args) {
        if (method_exists($this->_sigmaObject, "$name")) {
            // do whatever you need
            // call_user_func_array(array($this->_sigmaObject), "$name"), $args); 
        } else {
            // do whatever you need
            //call
        }
    }

    public function __callStatic($name, $args) {
        if (method_exists(get_class($this->_sigmaObject), "$name")) {
            // do whatever you need
            // call_user_func_array(array(get_class($this->_sigmaObject), "$name"), $args); 
        } else {
            // do whatever you need
            //call
        }
    }

    public function __get($name) {
        return $this->_sigmaObject->{$name};
    }

    public function __set($name, $value) {
        $this->_sigmaObject->{$name} = $value;
    }
}