详解PHP后期静态绑定分析与应用
基础知识
1.范围解析操作符(::)
- 可以用于访问静态成员,类常量,还可以用于覆盖类中的属性和方法。
- self,parent和static这三个特殊的关键字是用于在类定义的内部对其属性或方法进行访问的。
- parent用于调用父类中被覆盖的属性或方法(出现在哪里,就将解析为相应类的父类)。
- self用于调用本类中的方法或属性(出现在哪里,就将解析为相应的类;注意与$this区别,$this指向当前实例化的对象)。
- 当一个子类覆盖其父类中的方法时,PHP不会调用父类中已被覆盖的方法。是否调用父类的方法取决于子类。
2.PHP内核将类的继承实现放在了"编译阶段"
运行结果:
AA
AA结论:
self::和parent::出现在某个类X的定义中,则将被解析为相应的类X,除非在子类中覆盖父类的方法。
3.Static(静态)关键字
作用:
-在函数体内的修饰变量的static关键字用于定义静态局部变量。
-用于修饰类成员函数和成员变量时用于声明静态成员。
-(PHP5.3之后)在作用域解析符(::)前又表示静态延迟绑定的特殊类。例子:
定义静态局部变量(出现位置:局部函数中)
特征:静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。
定义静态方法,静态属性
a)声明类属性或方法为静态,就可以不实例化类而直接访问。
b)静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)
c)如果没有指定访问控制,属性和方法默认为公有。
d)由于静态方法不需要通过对象即可调用,所以伪变量$this在静态方法中不可用。
e)静态属性不可以由对象通过->操作符来访问。
f)用静态方式调用一个非静态方法会导致一个E_STRICT级别的错误。
g)就像其它所有的PHP静态变量一样,静态属性只能被初始化为文字或常量,不能使用表达式。所以可以把静态属性初始化为整数或数组,但不能初始化为另一个变量或函数返回值,也不能指向一个对象。
a.静态方法例子(出现位置:类的方法定义)
b.静态属性例子(出现位置:类的属性定义)
staticValue()."\n"; print$foo->my_static."\n";//Undefined"Property"my_static print$foo::$my_static."\n"; $classname='Foo'; print$classname::$my_static."\n";//AsofPHP5.3.0 printBar::$my_static."\n"; $bar=newBar(); print$bar->fooStatic()."\n"; ?>c.用于后期静态绑定(出现位置:类的方法中,用于修饰变量或方法)
下面详细分析
后期静态绑定(latestaticbinding)
自PHP5.3.0起,PHP增加了一个叫做后期静态绑定的功能,用于在继承范围内引用静态调用的类。
1.转发调用与非转发调用
转发调用:
指的是通过以下几种方式进行的静态调用:self::,parent::,static::以及forward_static_call()。
非转发调用:
明确指定类名的静态调用(例如Foo::foo())
非静态调用(例如$foo->foo())
2.后期静态绑定工作原理
原理:存储了在上一个“非转发调用”(non-forwardingcall)中的类名。意思是当我们调用一个转发调用的静态调用时,实际调用的类是上一个非转发调用的类。
例子分析:
3.更多静态后期静态绑定的例子
a)Self,Parent和Static的对比
selfname()."\n"; echo$apple->parentname()."\n"; echo$apple->staticname(); ?> 运行结果: Mango Orange Appleb)使用forward_static_call()
运行结果: Orangeis Orangeismyfavoritefruit Appleismyfather'sfavoritefruitc)使用get_called_class()
运行结果: Mango Orange应用
前面已经提到过了,引入后期静态绑定的目的是:用于在继承范围内引用静态调用的类。
所以,可以用后期静态绑定的办法解决单例继承问题。先看一下使用self是一个什么样的情况:
通过上面的例子可以看到,使用self,实例化得到的都是类A的同一个对象
再来看看使用static会得到什么样的结果
可以看到,使用static可以解决self时出现的单例继承问题。