SO,
我对PHP类方法调用的概念有一个问题。让我们有一个实现简单西格玛操作的类,例如,一个sum:
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()
方法。
我想要实现的是,如果我通过static调用来调用我的getSigma()
方法,我将能够传递任意数量的参数,因为我的__callStatic()
方法预计会被触发。但是,不幸的是,这是而不是。相反,PHP直接调用我的getSigma()
方法,因为它被定义为静态:
$rFirst = new Sigma(-4.5);
$rSecond = new Sigma(5);
$rFourth = Sigma::getSigma($rFirst, $rSecond);//Fatal error: Using $this when not in object context in ...
我理解为什么会触发致命错误——PHP通过::
运算符调用非静态方法——然后在其中使用$this
。
长话短说:当非静态方法被称为静态方法时,有没有办法触发__callStatic()
方法?或者至少如何通过::
调用非静态方法(以及通过->
调用静态方法)来防止PHP的"bug或特性"?
所有这些我都需要实现漂亮的接口,当我可以为对象调用或类调用使用一个方法名时。而且,由于这是我的目标,我不能使我的非静态方法私有或受保护(即,它们应该可以在外部使用)
很遗憾没有。只要有一个方法的名称是您要调用的,PHP就会调用它,而不考虑调用类型和方法类型。
也许可以通过实现__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) {
// ...
}
编辑
因此,如果您需要类来扩展或实现某些东西,请尝试使用某种包装器,在那里您可以破坏调用:
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;
}
}