PHP可以使用静态方式调用非静态方法引入的思考
在看某个ORM类库的时候发现子类使用了subClass::parentMethod()
的方式调用,比如self::save()
,在记忆里这是静态调用,可是这个save()
方法在父类里是一个非静态方法。于是刨根问底的搜索问题答案才有了下面的内容。
魔术方法定义
__call(string $name, array $arguments)
在对象中调用一个不可访问方法时,__call()会被触发.__callStatic(string $name , array $arguments)
使用静态方式调用一个不可访问的方法时,__callStatic()会被触发. 如果调用的方法是非静态方法,那么会报一个Strict Standards
提示。
class A
{
public function __call($name, $args)
{
echo "NO\n";
}
public static function __callStatic($name, $args)
{
echo "YES\n";
}
}
class B extends A
{
public function test()
{
A::test();
}
public static function stest()
{
A::test();
}
}
$b = new B; $b->test(); //执行调用
先看B继承A的情况
- 当执行到test方法中的
A::test()
的时候,会去A类中找这个方法,如果找不到恰好又声明了__call()
和__callStatic()
的话__call()
就会被调用。那么问题来了,我们明明是用A::test()
进行静态调用的,为什么会__call()
会被调用,应该是__callStatic()
被调用啊混蛋!!! - 这个时候看了PHP中的calling scope这篇文章以后,对calling scope有了比较深入的理解。首先明确了在PHP中, 判断静态与否不是靠
::
(PAAMAYIM_NEKUDOTAYIM)符号, 而是靠calling scope,而$this
指针在方法被调用的时候指向的就是这个calling scope。所以当执行A::test()
的时候,B对象的calling scope就被传递给了A,那么这个时候就不是静态调用,所以执行了_call()
方法。
- 当执行到test方法中的
再看B没有继承A的情况
- 当执行到test方法中的
A::test()
的时候,相当于类外调用。那么这个时候可以分两种情况讨论 - 如果A类里没有
test()
方法,就如同上面示例代码,那么这时会在A类里寻找test()
,没有则进入到__callStatic()
中。如果安装1的情况那么理解应该是进入__call()
。所以我的理解是如果A中没有存在所对应的方法,那么此时这个作用域就丢失了,所以就进入了__callStatic()
中。 - 如果A类中有
test()
方法,那么这个就和鸟哥那篇博客里举的例子一样了,这时候也会把B类的作用域传递到被调用的test()
方法中。但是这里PHP5(Strict Standards错误)和PHP7(Deprecated错误)有些不一样,我将在下一篇记录一下。
参考阅读
- 当执行到test方法中的