PHP語言中有一種屬性訪問級別被稱作protected,這種訪問級別是指這個屬性可以被該類及其子類所訪問。在實際應用開發中,經常使用這種訪問控制,以使得某些屬性只能被特定的類所操作。本文將會詳細闡述PHP protected屬性的各種用法,幫助讀者更好地掌握和應用這種屬性,提高PHP程序的設計水平。
Protected屬性的聲明
使用protected聲明一個屬性時,該屬性的真正訪問權限如下:
- 可以被當前類以及其子類所訪問; - 不能被實例化后的對象所訪問,但可以在類中被訪問; - 可以被其它在同一個類中的方法所訪問。
protected屬性的使用
使用protected屬性,雖然會給程序的類結構帶來更多的復雜度,但也能使得程序的函數模板和變量成員更加簡潔清晰。
在下面的代碼中,有一個基類Base,其中有一個被聲明為protected的$num屬性。在該基類中,我們提供了一個getNum方法,該方法能夠獲取基類中的num屬性并返回它的值。由于在基類中無法實例化對象,因此這里我們在getNum函數里面設置了一個類似于單例類的機制,使得每次獲取$num屬性的時候,只會獲取到它的一個實例。
我們看到,在上例中,即使我們在客戶端實例化了一個Base對象并調用了它的getNum方法,getNum方法內部也會按照基類中設置的邏輯進行處理。這樣做的好處是getNum方法可以在基類的所有的子類中被公用。即使我們在子類Child中實現與getNum完全相同的方法,也不會影響到基類中的getNum方法。
繼承中的protected屬性應用
在繼承體系中,protected訪問控制常常被用來控制被繼承的屬性的訪問情況。在下面的代碼中,我們新建了一個類Child,該類繼承自Base類。在Child類中,我們增加了一個加載一個CSV文件的方法loadCSV,該方法使用了繼承自Base類的getNum方法來獲取到Base類中的$num屬性,并從CSV文件中讀取一個新的值然后賦給$num屬性。
在上例中,由于Child類是繼承自Base類的,因此可以調用Base類中的getNum方法。但是在loadCSV方法中,我們將Base類中的$num賦值給了Child類的$num,這就是子類和基類共享屬性的體現。
當然,在使用protected訪問控制時,也需要注意一些代碼的特殊情況。下面的代碼展示了這種特殊情況:在Child類中,雖然有一個$num的屬性名與被繼承父類中的$num屬性名是一致的,但是它們確實不同的屬性,在內存中占據不同的地址。
在上例中,$num屬性雖然在繼承類中也被聲明過,但是它的值并不會由基類中繼承而來。因此在調用$child->loadCSV('data.csv')以后,$num屬性的值會被覆蓋為基類中的$num屬性的值。這就是在使用protected訪問控制時要注意的細節的一個體現。
結語
使用protected屬性,可以幫助我們更加有效地控制類和繼承體系中共享的屬性和方法。雖然它會帶來一定程度的復雜性,但卻可以使得程序的代碼更加簡潔和可讀性更強,增強了程序的可維護性和可擴展性。所以我們在使用PHP類型開發的時候,應該盡可能地掌握和應用PHP protected屬性的各種用法。
Protected屬性的聲明
使用protected聲明一個屬性時,該屬性的真正訪問權限如下:
- 可以被當前類以及其子類所訪問; - 不能被實例化后的對象所訪問,但可以在類中被訪問; - 可以被其它在同一個類中的方法所訪問。
protected屬性的使用
使用protected屬性,雖然會給程序的類結構帶來更多的復雜度,但也能使得程序的函數模板和變量成員更加簡潔清晰。
在下面的代碼中,有一個基類Base,其中有一個被聲明為protected的$num屬性。在該基類中,我們提供了一個getNum方法,該方法能夠獲取基類中的num屬性并返回它的值。由于在基類中無法實例化對象,因此這里我們在getNum函數里面設置了一個類似于單例類的機制,使得每次獲取$num屬性的時候,只會獲取到它的一個實例。
class Base { protected $num = 0; protected static $inst = null; <br> public function getNum() { if (self::$inst === null) { self::$inst = new Base(); } return $this->num; } } <br> $base = new Base(); $base->getNum(); // 輸出 0
我們看到,在上例中,即使我們在客戶端實例化了一個Base對象并調用了它的getNum方法,getNum方法內部也會按照基類中設置的邏輯進行處理。這樣做的好處是getNum方法可以在基類的所有的子類中被公用。即使我們在子類Child中實現與getNum完全相同的方法,也不會影響到基類中的getNum方法。
繼承中的protected屬性應用
在繼承體系中,protected訪問控制常常被用來控制被繼承的屬性的訪問情況。在下面的代碼中,我們新建了一個類Child,該類繼承自Base類。在Child類中,我們增加了一個加載一個CSV文件的方法loadCSV,該方法使用了繼承自Base類的getNum方法來獲取到Base類中的$num屬性,并從CSV文件中讀取一個新的值然后賦給$num屬性。
class Child extends Base { public function loadCSV($filepath) { $this->num = $this->getNum(); $csv = array_map('str_getcsv', file($filepath)); $this->num += $csv[0][0]; } } <br> $child = new Child(); $child->loadCSV('data.csv'); echo $child->getNum(); // 輸出CSV中的值
在上例中,由于Child類是繼承自Base類的,因此可以調用Base類中的getNum方法。但是在loadCSV方法中,我們將Base類中的$num賦值給了Child類的$num,這就是子類和基類共享屬性的體現。
當然,在使用protected訪問控制時,也需要注意一些代碼的特殊情況。下面的代碼展示了這種特殊情況:在Child類中,雖然有一個$num的屬性名與被繼承父類中的$num屬性名是一致的,但是它們確實不同的屬性,在內存中占據不同的地址。
class Child extends Base { protected $num = 10; <br> public function loadCSV($filepath) { $this->num = $this->getNum(); $csv = array_map('str_getcsv', file($filepath)); $this->num += $csv[0][0]; } <br> public function getNum() { return $this->num; } } <br> $child = new Child(); $child->loadCSV('data.csv'); echo $child->getNum(); // 輸出11,而不是CSV中的值
在上例中,$num屬性雖然在繼承類中也被聲明過,但是它的值并不會由基類中繼承而來。因此在調用$child->loadCSV('data.csv')以后,$num屬性的值會被覆蓋為基類中的$num屬性的值。這就是在使用protected訪問控制時要注意的細節的一個體現。
結語
使用protected屬性,可以幫助我們更加有效地控制類和繼承體系中共享的屬性和方法。雖然它會帶來一定程度的復雜性,但卻可以使得程序的代碼更加簡潔和可讀性更強,增強了程序的可維護性和可擴展性。所以我們在使用PHP類型開發的時候,應該盡可能地掌握和應用PHP protected屬性的各種用法。