【问题标题】:__call, __callStatic and calling scope in PHP__call、__callStatic 和 PHP 中的调用范围
【发布时间】:2013-08-28 12:26:11
【问题描述】:

我最近阅读了有关在 PHP 中调用作用域和作用域解析运算符 (::) 的内容。有两种变体:实例调用和静态调用。考虑以下监听:

<?php

class A {
    public function __call($method, $parameters) {
        echo "I'm the __call() magic method".PHP_EOL;
    }

    public static function __callStatic($method, $parameters) {
        echo "I'm the __callStatic() magic method".PHP_EOL;
    }
}

class B extends A {
    public function bar() {
        A::foo();
    }
}

class C {
    public function bar() {
        A::foo();
    }
}

A::foo();
(new A)->foo();

B::bar();
(new B)->bar();

C::bar();
(new C)->bar();

执行结果(PHP 5.4.9-4ubuntu2.2)为:

I'm the __callStatic() magic method
I'm the __call() magic method
I'm the __callStatic() magic method
I'm the __call() magic method
I'm the __callStatic() magic method
I'm the __callStatic() magic method

我不明白为什么(new C)-&gt;bar(); 执行__callStatic()A?实例调用应该在 bar() 方法的上下文中进行,不是吗?是PHP的特性吗?

加法1:

此外,如果我不使用魔法方法并进行显式调用,一切都会按预期进行:

<?php

class A {
    public function foo() {
        echo "I'm the foo() method of A class".PHP_EOL;
        echo 'Current class of $this is '.get_class($this).PHP_EOL;
        echo 'Called class is '.get_called_class().PHP_EOL;
    }
}

class B {
    public function bar() {
        A::foo();
    }
}

(new B)->bar();

结果:

I'm the foo() method of A class
Current class of $this is B
Called class is B

【问题讨论】:

  • 我更感兴趣的是为什么C::bar(); 没有抛出错误。
  • 为什么?我认为在这种情况下它可以纠正。
  • It's not。并且可能会抛出E_STRICT
  • 嗯,来自我的 php.ini:error_reporting = E_ALL &amp; ~E_DEPRECATED &amp; ~E_STRICT.
  • @JasonMcCreary 是的,你是对的。我必须在开发中的error_reporting中使用E_STRICT常量,我忘记了:)

标签: php


【解决方案1】:

Cbar() 方法中,你有A::foo();

public function bar() {
    A::foo();
}

由于此方法既没有创建A 的实例,也没有C 扩展A,因此:: 运算符被视为试图调用静态方法A::foo() 的静态运算符。因为foo() 没有在A 上定义,所以它回退到__callStatic() 方法。

如果您希望它调用非静态方法而不扩展 A,则必须创建 A 的实例:

class C {
    public function bar() {
        $aInstance = new A();
        $aInstance->foo();
    }
}

【讨论】:

  • :: 并不总是意味着静态调用。这取决于调用范围。对于(new B)-&gt;bar(); 执行B 类的bar() 方法,而不是A::foo(),在本例中为__callStatic(),因为它是实例调用范围。
  • @vasayxtx 抱歉,我想我的措辞不好。我的意思是,在 C.bar() 的上下文中,它被用作static 运算符。让我重新措辞,希望我能说得更清楚。
【解决方案2】:

这是因为在这种情况下我们没有A 类的实例。 请注意

 class B extends A

所以new B 让我们可以访问A-&gt;foo 的非静态版本。

C 类不扩展 A,因此只有 A 的静态方法可用。

【讨论】:

  • 好的,我明白了。这还不够明显,至少对我来说是这样。
  • 别担心。这些东西可能会变得棘手,需要引起注意,以免忽略一些次要但重要的细节。
  • "C 类没有扩展 A,所以只有 A 的静态方法可用。"我可以在手册中阅读它吗?
  • 您能看到我的补充 1 并解释为什么它按预期工作吗?您的 saing 是否仅适用于魔术方法 __call()?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-16
  • 2018-02-10
  • 2011-08-02
  • 2011-08-01
  • 2011-03-22
  • 1970-01-01
  • 2012-11-07
相关资源
最近更新 更多