PHP 错误地处理了我的静态调用

2021-12-23 00:00:00 class static methods php php-5.3

我在 PHP 5.3 上遇到了问题.我需要使用 __callStatic 调用一个方法,但是如果我在实例化对象中使用它,PHP 会调用 __call 代替.

I'm havinh a problem on PHP 5.3. I need to call a method by using __callStatic, but if I use it in a instancied object, PHP call __call instead.

以上现实生活中的例子:

Above a real life example:

<?php

    class A {
        function __call($method, $args){
            // Note: $this is defined!
            echo "Ops! Don't works. {$this->c}";
        }

        static function __callStatic($method, $args){
            echo 'Fine!';
        }
    }

    class B extends A {
        public $c = 'Real Ops!';

        function useCallStatic(){
            static::foo();
            // === A::foo();
            // === B::foo();
        }
    }

    $foo = new B();
    $foo->useCallStatic();

    // This works:
    // B::foo();

?>

打印:操作!不工作.真正的行动!

Prints: Ops! Don't works. Real Ops!

请注意,我从 new B() 调用了 useCallStatic.如果我直接调用像 B::foo().

Note that I call useCallStatic from a new B(). If I call directly works fine like B::foo().

我能做些什么才能正常工作?

What I can do to it works fine?

推荐答案

仔细想了想,其实不是bug.但这绝对不直观.

After thinking about it, it's not really a bug. But it's definitely unintuitive.

<?php
class A
{
  public function foo()
  {
    static::bar();
  }

  public function bar()
  {
    echo "bar()
";
  }
}

$a = new A();
$a->foo();

这是有效的,并调用 bar().这并不意味着静态调用栏.表示查找当前的类名,如果存在则调用函数bar,无论是否为静态函数.

This is valid, and calls bar(). It does not mean call bar statically. It means to look up the current class name and call function bar if it exists, whether or not it's a static function.

再澄清一点:您认为 parent::bar() 是否意味着调用名为 bar() 的静态函数?不,这意味着调用任何名为 bar() 的函数.

To clarify a bit more: do you think parent::bar() means to call a static function called bar()? No, it means call whatever function is named bar().

考虑:

<?php
class A
{
  function __call($name, $args)
  {
    echo "__call()
";
  }

  static function __callStatic($name, $ags)
  {
    echo "__callStatic()
";
  }

  function regularMethod()
  {
    echo "regularMethod()
";
  }

  static function staticMethod()
  {
    echo "staticMethod()
";
  }

}

class B extends A
{
  function foo()
  {
    parent::nonExistant();   
    static::nonExistant();
    parent::regularMethod();
    parent::staticMethod(); 
  }
}

$b = new B();
$b->foo();

parent::nonExistant() 方法调用 A::__call()static::nonExistant() 也是如此.为 任一 调用调用 A::__callStatic() 将同样有效!PHP 无法知道您要调用哪一个.但是,按照设计,PHP 在从此类上下文调用时给予 __call 优先权.

The parent::nonExistant() method invokes A::__call(), as does static::nonExistant(). Invoking A::__callStatic() for either call would be equally as valid! There is no way for PHP to know which one you want to be called. However, by design, PHP gives __call the priority when invoked from this sort of context.

parent::regularMethod() 调用非静态函数 regularMethod().(同样,:: 操作符并不意味着调用这个静态函数".)同样,parent::staticMethod() 调用 A::staticMethod() 正如人们所期望的那样.

parent::regularMethod() invokes the non static function regularMethod(). (Again, the :: operator does not mean "call this static function.") Likewise parent::staticMethod() invokes A::staticMethod() as one might expect.

解决您的问题:

您可以在继承的类中手动调用self::__callStatic('foo').

You could manually call self::__callStatic('foo') in the inherited class.

或者在 A 类的 __call 方法中过滤已知列表并调用 self::__callStatic.

Or within the __call method of class A filter against a known list and call self::__callStatic.

function __call($f, $a)
{
  if ($f == 'foo')
    return self::__callStatic($f, $a); 
  else
  {
  }
}

这很丑陋,但至少扩展类的人不需要做任何特别的事情.

It's ugly, but at least people who extend the class won't need to do anything special.

相关文章