1

SO,

I have a problem with concept of PHP class method calling. Let we have a class that implementing simple sigma action, for example, a 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());
   }

}

As you can see, we can use it's getSigma() method to return an instance of itself that represents simple sum of current object and input object:

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

Well, everything is ok here. But as you can see, I've defined __callStatic() method in my class.

What I want to achieve - is that if I'll call my getSigma() method via static call, I would be able to pass any number of parameters since my __callStatic() method is expected to be triggered. But, unfortunately, this is not happening. Instead of this, PHP calls my getSigma() method directly as it was defined as static:

$rFirst  = new Sigma(-4.5);
$rSecond = new Sigma(5);
$rFourth = Sigma::getSigma($rFirst, $rSecond);//Fatal error: Using $this when not in object context in ...

And I understand why fatal error was triggered - PHP calls non-static method via :: operator - then, inside it , $this is used.

So to make long story short: is there a way to trigger __callStatic() method when non-static method is called as static? Or at least how to prevent that PHP 'bug-or-feature' with calling non-static methods via :: (and static methods via ->)?

All this I need to implement beautiful interface, when I can either use one method name for either object call or class call. And, since that is my goal, I can not make my non-static methods private or protected (i.e. they should be accessible for using outside)

4

2 回答 2

1

不幸的是没有。只要有一个名称与您尝试调用的方法相同,PHP 就会调用它,而不考虑调用类型与方法类型。

于 2013-08-08T15:01:08.857 回答
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) {
// ...
}

编辑

因此,如果您需要类来扩展或实现某些东西,请尝试使用某种包装器,您可以在其中破坏调用:

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;
    }
}
于 2013-08-08T15:11:25.347 回答