程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> php5.3後靜態綁定用法詳解

php5.3後靜態綁定用法詳解

編輯:PHP綜合

本文實例講述了php5.3後靜態綁定用法。分享給大家供大家參考,具體如下:

手冊原文:

自 PHP 5.3.0 起,PHP 增加了一個叫做後期靜態綁定的功能,用於在繼承范圍內引用靜態調用的類。

准確說,後期靜態綁定工作原理是存儲了在上一個"非轉發調用"(non-forwarding call)的類名。當進行靜態方法調用時,該類名即為明確指定的那個(通常在 :: 運算符左側部分);當進行非靜態方法調用時,即為該對象所屬的類。所謂的"轉發調用"(forwarding call)指的是通過以下幾種方式進行的靜態調用:self::,parent::,static:: 以及 forward_static_call()。可用 get_called_class() 函數來得到被調用的方法所在的類名,static:: 則指出了其范圍。

該功能從語言內部角度考慮被命名為"後期靜態綁定"。"後期綁定"的意思是說,static:: 不再被解析為定義當前方法所在的類,而是在實際運行時計算的。也可以稱之為"靜態綁定",因為它可以用於(但不限於)靜態方法的調用。

self:: 的限制

使用 self:: 或者 __CLASS__ 對當前類的靜態引用,取決於定義當前方法所在的類:

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();
?> 

以上例程會輸出:

A

後期靜態綁定的用法 後期靜態綁定本想通過引入一個新的關鍵字表示運行時最初調用的類來繞過限制。簡單地說,這個關鍵字能夠讓你在上述例子中調用 test() 時引用的類是 B 而不是 A。最終決定不引入新的關鍵字,而是使用已經預留的 static 關鍵字。

Example #2 static:: 簡單用法

<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // 後期靜態綁定從這裡開始
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?> 

以上例程會輸出:

B

Note: 在非靜態環境下,所調用的類即為該對象實例所屬的類。由於 $this-> 會在同一作用范圍內嘗試調用私有方法,而 static:: 則可能給出不同結果。另一個區別是 static:: 只能用於靜態屬性。

Example #3 非靜態環境下使用 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
?> 

以上例程會輸出:

success!
success!
success!
Fatal error: Call to private method C::foo() from context 'A' in /tmp/test.php on line 9

Note: 後期靜態綁定的解析會一直到取得一個完全解析了的靜態調用為止。另一方面,如果靜態調用使用 parent:: 或者 self:: 將轉發調用信息。

Example #4 轉發和非轉發調用

<?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
C
C

下面示例分析了基於PHP後期靜態綁定功能解決在繼承范圍內引用靜態調用的類。

先看如下代碼:

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

很明顯,結果不是我們預期的,這是因為self::取決於定義時所在的類,而不是運行中的類。為了解決這個問題,你可能會在繼承類中重寫status()方法,更好的解決方案是PHP 5.3後添加了後期靜態綁定的功能。

代碼如下:

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::不在指向當前所在的類,實際上,它是在運行中計算的,強制獲取最終類的所有屬性。

因此,建議,以後不要再使用self::,使用static::

補充:

網友帖1

php的後期靜態綁定,怎麼解釋?下面的這幅圖輸出是A,C,C

由圖的繼承關系可知:C徹底包含了B和A。

在看答案結果以前,他細觀察發現,三個類裡都有同一個名稱who()方法。
系統會用最後一個優先級最高,進一步的說,你幾乎沒法通過C去調用A、B內的who(),只能重改方法,比如添加個getBWho(){echo B::who();}
然後通過C::getBWho();來調用B內的who();

下面來看運行結果:

test只在B中出現,所以結果必然是test()中運行的三個結果:

第一個:靜態直接指名到姓的調用A內靜態函數,這沒有懸念,必然是A
第二個:parent::是調用上一級的父類,在此題中為A,A中又直接調用static:who();上面說過了,這個who()優先級最高的在C裡面,無論在你ABC中哪裡調用,只要是static::who()必然是最後定義的那個,覆蓋效應,如果想調用A裡的必需指明A::who()或是通過去除static從作用域限制來實現。所以這個who()就是C中定義的who
第三個:self::who與第二個類似的問題,看樣該走B的,注意覆蓋效應,要想調用B內的who必須得B::who(),因為更高級的C已經重寫了這個方法,如果C中沒有who,肯定就是B,依次類推。所以必然還是調用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

網友帖2

(還是針對上面圖中的代碼)

手冊不是說得很清楚麼

”後期綁定“的意思是說,static::不再被解析為定義當前方法所在的類,而是在實際運行時計算的。也可以稱之為”靜態綁定“,因為它可以用於(但不限於)靜態方法的調用。

#1說的有個小問題

【self::foo(); // 這個self實際上是C類。明白嗎? C::test() C繼承了B的test()方法】

不准確,self還是B類,但是本身沒有覆寫foo方法,所以就調用父類A的foo方法。

如果self實際是C類,那你試下self::foo();改成self::who();,應當打印C,但是打印B,這也正是self和static的區別。

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

網友帖3

A::foo(); //A指代A類,訪問A類的foo方法和who方法
parent::foo();//調用B類的父類——A的foo方法,並告訴foo方法最原始的調用者是C
self::foo(); //self指代定義該方法的類,即B,但是B沒有定義foo方法,它將原始的調用者C向上傳遞,
// 訪問父類的foo方法,最後訪問c的who方法;

所以這就回答了樓上的疑問:若是把self::foo(); 改成self::who(),因為self指代B,而B有who方法,所以結果是變成了B

靜態調用使用 parent:: 或者 self:: 將轉發原始調用信息。

更多關於PHP相關內容感興趣的讀者可查看本站專題:《php面向對象程序設計入門教程》、《PHP基本語法入門教程》、《PHP運算與運算符用法總結》、《PHP網絡編程技巧總結》、《PHP數組(Array)操作技巧大全》、《php字符串(string)用法總結》、《php+mysql數據庫操作入門教程》及《php常見數據庫操作技巧匯總》

希望本文所述對大家PHP程序設計有所幫助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved