Reputation: 37365
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)
Upvotes: 1
Views: 677
Reputation: 12587
Maybe it could solved by implementing __call
. Like this:
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) {
// ...
}
edit
So if you need class to extend or to implement something, try using somekind of wrapper, where you can mangle calls:
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;
}
}
Upvotes: 0
Reputation: 437734
Unfortunately not. As long as there is a method with the name you are trying to call, PHP will call it without considering type of call vs the type of method.
Upvotes: 1