【问题标题】:php strange recursive result when using the __callStatic functionphp使用__callStatic函数时出现奇怪的递归结果
【发布时间】:2012-08-05 17:13:38
【问题描述】:

我得到了一些奇怪的结果,最好通过显示代码来解释。

假设我创建了一个具有 3 个方法的 A 类:
add 方法 - 添加其他 A 类实例以供以后使用
_调用 魔术方法 - 添加动态变量和值
_callStatic 静态魔术方法 - 这些方法帮助我创建更具可读性的 A 类

所以类是:

class A_Class {

protected $name;
protected $varList;
protected $childs = array();

protected static $tabCount = 0;

public function __construct($name) {
    $this->name = $name;
}

public function add() {
    if (func_num_args()) { 
        $this->childs = array_merge($this->childs, func_get_args());
    }
    return $this;
}

public function __call($name, $arguments) {
    if (count($arguments) > 0) {
        $this->varList[$name] = $arguments[0];
    }
    return $this;
}

public static function __callStatic($name, $arguments) {
    return new A_Class($name);
}

}

现在当我使用它时:

$a = A_Class::MyNameA();
$a->someDynamicVar("I am the var data");
$a->add(A_Class::ANotherNameA());
print_r($a);

工作得很好,结果是:

A_Class Object
(
    [name:protected] => MyNameA
    [varList:protected] => Array
        (
            [someDynamicVar] => I am the var data
        )

    [childs:protected] => Array
        (
        )
)

但是,如果我尝试将 B 类创建为从 A 类继承:

class B_Class extends A_Class {

public function __construct($name) {
    parent::__construct($name);
    $this->add(A_Class::NewAClass());
}

}

并尝试以下操作:

$b = new B_Class("NewBClassInstance");
print_r($b);

我得到一个递归结果:

B_Class Object
(
    [name:protected] => B-MAN
    [varList:protected] => 
    [childs:protected] => Array
        (
            [0] => B_Class Object
 *RECURSION*
        )
)

对我来说这很奇怪。
好像 __callStatic 是从 B 类而不是 A 类运行的

有什么想法吗?

【问题讨论】:

  • 我觉得很奇怪,是因为在你的 varList 中没有一行“添加”包含 A_Class 实例,不是吗?

标签: php inheritance static-methods


【解决方案1】:

也许这个例子会帮助你理解:

<?php

class A
{
  public function __call($name, $args)
  {
    echo "__call\n";
  }

  static public function __callStatic($name, $args)
  {
    echo "__callStatic\n";
  }
}

class B extends A
{
  public function __construct()
  {
    A::callMe();
  }
}

new B();

运行结果是:

__call

它确实调用静态版本。为什么?因为 B 是 A 的后裔,因此当 __call__callStatic 都存在时,A::foo() 是一个模棱两可的调用。

请记住,在类的成员函数上下文中,Class::func() 确实不是意味着“在类 Class 中调用名为 func 的静态方法”。

它只是表示“调用Class 的函数func”。例如:

class A
{
  public function foo() {}
}

class B
{
  public function foo() {}

  public function bar()
  {
    A::foo(); // call A's foo
  }
}

所以在你的情况下,__call 方法在 B 的构造函数中被调用。这正是 PHP 在这种模棱两可的情况下所做的。它返回$this,它被传递给$this-&gt;add(),实际上是在B的构造函数中给你这个:$this-&gt;add($this)

同样,none 表示在类成员函数的上下文中“调用静态函数”:

parent::foo();
self::foo();
static::foo();
A::foo();
B::foo();

它们都只是表示“在类中调用函数 foo,由 :: 左侧的东西引用”。通常你要么有一个显式的实例函数,要么有一个静态函数,所以调用是没有歧义的。但是当你同时拥有__call__callStatic 时,PHP 无法知道你想调用哪个,它总是选择__call

【讨论】:

  • 谢谢。虽然我理解你的回答,但我不明白其中的逻辑。据我所知,这似乎是一个错误的设计
  • 关键点是Foo::bar() 并不意味着“调用名为bar 的静态方法”,因为它出现在派生自Foo 的类的任何实例方法中。这不是 PHP 的错。这是一个特点。您还如何调用继承层次结构中的特定方法?唯一不明确的情况是您同时拥有__call__callStatic。除非绝对必要,否则我建议不要使用这些魔术方法中的任何一种。在您的情况下,只需创建一个名为 A::withName($name) 的静态方法并像 A_Class::withName('NewAClass') 一样调用它。更容易理解。
猜你喜欢
  • 1970-01-01
  • 2015-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多