php5.3后靜態(tài)綁定用法詳解
本文實(shí)例講述了php5.3后靜態(tài)綁定用法。分享給大家供大家參考,具體如下:
手冊原文:
自 PHP 5.3.0 起,PHP 增加了一個(gè)叫做后期靜態(tài)綁定的功能,用于在繼承范圍內(nèi)引用靜態(tài)調(diào)用的類。
準(zhǔn)確說,后期靜態(tài)綁定工作原理是存儲(chǔ)了在上一個(gè)"非轉(zhuǎn)發(fā)調(diào)用"(non-forwarding call)的類名。當(dāng)進(jìn)行靜態(tài)方法調(diào)用時(shí),該類名即為明確指定的那個(gè)(通常在 :: 運(yùn)算符左側(cè)部分);當(dāng)進(jìn)行非靜態(tài)方法調(diào)用時(shí),即為該對象所屬的類。所謂的"轉(zhuǎn)發(fā)調(diào)用"(forwarding call)指的是通過以下幾種方式進(jìn)行的靜態(tài)調(diào)用:self::,parent::,static:: 以及 forward_static_call()??捎?get_called_class() 函數(shù)來得到被調(diào)用的方法所在的類名,static:: 則指出了其范圍。
該功能從語言內(nèi)部角度考慮被命名為"后期靜態(tài)綁定"。"后期綁定"的意思是說,static:: 不再被解析為定義當(dāng)前方法所在的類,而是在實(shí)際運(yùn)行時(shí)計(jì)算的。也可以稱之為"靜態(tài)綁定",因?yàn)樗梢杂糜冢ǖ幌抻冢╈o態(tài)方法的調(diào)用。
self:: 的限制
使用 self:: 或者 __CLASS__ 對當(dāng)前類的靜態(tài)引用,取決于定義當(dāng)前方法所在的類:
Example #1 self:: 用法
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
以上例程會(huì)輸出:
A
后期靜態(tài)綁定的用法 后期靜態(tài)綁定本想通過引入一個(gè)新的關(guān)鍵字表示運(yùn)行時(shí)最初調(diào)用的類來繞過限制。簡單地說,這個(gè)關(guān)鍵字能夠讓你在上述例子中調(diào)用 test() 時(shí)引用的類是 B 而不是 A。最終決定不引入新的關(guān)鍵字,而是使用已經(jīng)預(yù)留的 static 關(guān)鍵字。
Example #2 static:: 簡單用法
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // 后期靜態(tài)綁定從這里開始
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
以上例程會(huì)輸出:
B
Note: 在非靜態(tài)環(huán)境下,所調(diào)用的類即為該對象實(shí)例所屬的類。由于 $this-> 會(huì)在同一作用范圍內(nèi)嘗試調(diào)用私有方法,而 static:: 則可能給出不同結(jié)果。另一個(gè)區(qū)別是 static:: 只能用于靜態(tài)屬性。
Example #3 非靜態(tài)環(huán)境下使用 static::
<?php
class A {
private function foo() {
echo "success!\n";
}
public function test() {
$this->foo();
static::foo();
}
}
class B extends A {
/* foo() will be copied to B, hence its scope will still be A and
* the call be successful */
}
class C extends A {
private function foo() {
/* original method is replaced; the scope of the new one is C */
}
}
$b = new B();
$b->test();
$c = new C();
$c->test(); //fails
?>
以上例程會(huì)輸出:
success!
success!
success!
Fatal error: Call to private method C::foo() from context 'A' in /tmp/test.php on line 9
Note: 后期靜態(tài)綁定的解析會(huì)一直到取得一個(gè)完全解析了的靜態(tài)調(diào)用為止。另一方面,如果靜態(tài)調(diào)用使用 parent:: 或者 self:: 將轉(zhuǎn)發(fā)調(diào)用信息。
Example #4 轉(zhuǎn)發(fā)和非轉(zhuǎn)發(fā)調(diào)用
<?php
class A {
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
A::foo();
parent::foo();
self::foo();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
?>
以上例程會(huì)輸出:
A
C
C
下面示例分析了基于PHP后期靜態(tài)綁定功能解決在繼承范圍內(nèi)引用靜態(tài)調(diào)用的類。
先看如下代碼:
class Person
{
public static function status()
{
self::getStatus();
}
protected static function getStatus()
{
echo "Person is alive";
}
}
class Deceased extends Person
{
protected static function getStatus()
{
echo "Person is deceased";
}
}
Deceased::status(); //Person is alive
很明顯,結(jié)果不是我們預(yù)期的,這是因?yàn)閟elf::取決于定義時(shí)所在的類,而不是運(yùn)行中的類。為了解決這個(gè)問題,你可能會(huì)在繼承類中重寫status()方法,更好的解決方案是PHP 5.3后添加了后期靜態(tài)綁定的功能。
代碼如下:
class Person
{
public static function status()
{
static::getStatus();
}
protected static function getStatus()
{
echo "Person is alive";
}
}
class Deceased extends Person
{
protected static function getStatus()
{
echo "Person is deceased";
}
}
Deceased::status(); //Person is deceased
可見,static::不在指向當(dāng)前所在的類,實(shí)際上,它是在運(yùn)行中計(jì)算的,強(qiáng)制獲取最終類的所有屬性。
因此,建議,以后不要再使用self::,使用static::
補(bǔ)充:
網(wǎng)友帖1
php的后期靜態(tài)綁定,怎么解釋?下面的這幅圖輸出是A,C,C

由圖的繼承關(guān)系可知:C徹底包含了B和A。
在看答案結(jié)果以前,他細(xì)觀察發(fā)現(xiàn),三個(gè)類里都有同一個(gè)名稱who()方法。
系統(tǒng)會(huì)用最后一個(gè)優(yōu)先級最高,進(jìn)一步的說,你幾乎沒法通過C去調(diào)用A、B內(nèi)的who(),只能重改方法,比如添加個(gè)getBWho(){echo B::who();}
然后通過C::getBWho();來調(diào)用B內(nèi)的who();
下面來看運(yùn)行結(jié)果:
test只在B中出現(xiàn),所以結(jié)果必然是test()中運(yùn)行的三個(gè)結(jié)果:
第一個(gè):靜態(tài)直接指名到姓的調(diào)用A內(nèi)靜態(tài)函數(shù),這沒有懸念,必然是A
第二個(gè):parent::是調(diào)用上一級的父類,在此題中為A,A中又直接調(diào)用static:who();上面說過了,這個(gè)who()優(yōu)先級最高的在C里面,無論在你ABC中哪里調(diào)用,只要是static::who()必然是最后定義的那個(gè),覆蓋效應(yīng),如果想調(diào)用A里的必需指明A::who()或是通過去除static從作用域限制來實(shí)現(xiàn)。所以這個(gè)who()就是C中定義的who
第三個(gè):self::who與第二個(gè)類似的問題,看樣該走B的,注意覆蓋效應(yīng),要想調(diào)用B內(nèi)的who必須得B::who(),因?yàn)楦呒壍腃已經(jīng)重寫了這個(gè)方法,如果C中沒有who,肯定就是B,依次類推。所以必然還是調(diào)用C中的who;
所以答案為:ACC
代碼如下:
<?php
class A {
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
A::foo();
parent::foo();
self::foo();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
//public static function who() {
// echo __CLASS__."\n";
//}
}
C::test();
?>
輸出為:A B B
網(wǎng)友帖2
(還是針對上面圖中的代碼)
手冊不是說得很清楚么
”后期綁定“的意思是說,static::不再被解析為定義當(dāng)前方法所在的類,而是在實(shí)際運(yùn)行時(shí)計(jì)算的。也可以稱之為”靜態(tài)綁定“,因?yàn)樗梢杂糜冢ǖ幌抻冢╈o態(tài)方法的調(diào)用。
#1說的有個(gè)小問題
【self::foo(); // 這個(gè)self實(shí)際上是C類。明白嗎? C::test() C繼承了B的test()方法】
不準(zhǔn)確,self還是B類,但是本身沒有覆寫foo方法,所以就調(diào)用父類A的foo方法。
如果self實(shí)際是C類,那你試下self::foo();改成self::who();,應(yīng)當(dāng)打印C,但是打印B,這也正是self和static的區(qū)別。
<?php
class A {
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
A::foo();
parent::foo();
self::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
?>
輸出為:A C B
網(wǎng)友帖3
A::foo(); //A指代A類,訪問A類的foo方法和who方法 parent::foo();//調(diào)用B類的父類——A的foo方法,并告訴foo方法最原始的調(diào)用者是C self::foo(); //self指代定義該方法的類,即B,但是B沒有定義foo方法,它將原始的調(diào)用者C向上傳遞, // 訪問父類的foo方法,最后訪問c的who方法;
所以這就回答了樓上的疑問:若是把self::foo(); 改成self::who(),因?yàn)閟elf指代B,而B有who方法,所以結(jié)果是變成了B
靜態(tài)調(diào)用使用 parent:: 或者 self:: 將轉(zhuǎn)發(fā)原始調(diào)用信息。
更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《php面向?qū)ο蟪绦蛟O(shè)計(jì)入門教程》、《PHP基本語法入門教程》、《PHP運(yùn)算與運(yùn)算符用法總結(jié)》、《PHP網(wǎng)絡(luò)編程技巧總結(jié)》、《PHP數(shù)組(Array)操作技巧大全》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫操作入門教程》及《php常見數(shù)據(jù)庫操作技巧匯總》
希望本文所述對大家PHP程序設(shè)計(jì)有所幫助。
相關(guān)文章
PHP的數(shù)組中提高元素查找與元素去重的效率的技巧解析
這篇文章主要介紹了PHP的數(shù)組中提高元素查找與元素去重的效率的技巧解析,文中對比了相關(guān)方法的執(zhí)行速度來總結(jié)數(shù)組中使元素查找和去重更加高效的辦法,需要的朋友可以參考下2016-03-03
那些年我們錯(cuò)過的魔術(shù)方法(Magic Methods)
PHP 對象的一個(gè)優(yōu)勢是可以使用魔術(shù)方法,這些方法可以不需要修改外部代碼而重寫一個(gè)類的默認(rèn)行為,這使得PHP 語法有更少的冗余性和更具有擴(kuò)展性。這些方法很好識別,他們都是以雙下劃線(__)開始的2014-01-01
php環(huán)境套包 dedeampz 偽靜態(tài)設(shè)置示例
這篇文章主要介紹了php環(huán)境套包 dedeampz 偽靜態(tài)設(shè)置,需要的朋友可以參考下2014-03-03

