2013-08-28 30 views
3

我最近阅读了PHP调用范围和范围解析运算符(:)。有两种变体:实例调用和静态调用。考虑如下因素listeng:__call,__call静态和在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)->bar();执行的A__callStatic()?实例调用应该在bar()方法的上下文中进行,不是吗?它是PHP的功能吗?

Addition1:

而且,如果我不使用魔法的方法和不明确调用,一切都按预期:

<?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 
+4

我更感兴趣的是为什么'C :: bar();'没有抛出错误。 –

+0

为什么?我认为这是纠正在这种情况下。 – vasayxtx

+0

[这不是](http://stackoverflow.com/questions/3754786/calling-non-static-method-with)。可能会抛出一个'E_STRICT'。 –

回答

3

bar()方法C,您有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(); 
    } 
} 
+0

'::'并不总是意味着静态调用。这取决于调用范围。对于'(new B) - > bar();''执行'B'类的方法而不是'A :: foo()',并且在这种情况下使用'__callStatic()',因为它是实例调用范围。 – vasayxtx

+0

@vasayxtx对不起,我猜这是我的错误措辞。我的意思是在C.bar()的上下文中,它被用作'静态'运算符。让我重新说一句,希望我能说得更清楚。 – newfurniturey

0

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

class B extends A 

所以new B让我们访问的A->foo非静态版本。

类别C不扩展A所以只有静态方法A可用。

+0

好吧,我明白了。这并不明显,至少对我而言。 – vasayxtx

+0

别担心。这些东西可能会变得棘手,需要一些注意,以免忽略一些次要但重要的细节。 – Mchl

+0

“C类不扩展A,因此只有A的静态方法可用。” 我可以在手册中了解它吗? – vasayxtx