基于 PHP5.3
PHP 的類及其實例,代碼如下:
- class Myclass{
- public $prop = 123;
- }
- $obj = new Myclass();
類的成員屬性(屬性的稱呼相對于“方法”而言)包括類常量和類變量,其中類常量在定義時不可為空,類的屬性在定義時如果被賦值,只能使用標量和數組,并且不能是表達式,因為類屬性在編譯期被初始化,PHP 在編譯期不執行表達式.
1、成員的訪問控制:
public:可以繼承,可以在類的方法之外被訪問,如 $obj->prop;
protected:可以繼承,不可以在類的方法之外被訪問
private:不可以繼承,不可以在類的方法之外訪問
PHP 4 使用 var 來聲明類的屬性,在PHP5之后不再使用,PHP5.3之前使用被警告,PHP5.3之后可以用在 public 之前或單獨使用作為 public 的別名.
這三個訪問控制關鍵字也可以修飾構造函數,當 private 和 protected 修飾類的構造函數時,你只能通過一個 publice static 的靜態方法來調用構造函數以實例化對象,因為夠在函數無法在類之外被訪問了,比如.單例類的實現,代碼如下:
- class Singleton {
- private static $instance=null;
- public $k = 88;
- private function __construct(){
- }
- public static function getInstance(){
- if(self::$instance==null){
- self::$instance = new self();
- }
- return self::$instance;
- }
- public function __clone(){ //pretend clone oprationg
- throw('Singleton class can not be cloned');
- return self::getInstance();
- }
- }
- //new Singleton(); // Error
- $in = Singleton::getInstance();
2、繼承禁止:final 關鍵字,僅用于修飾類或類的方法
如果一個類被 final 修飾,這個類不能被繼承,如果一個方法被final 修飾,則這個方法不能被子類重寫(override),代碼如下:
- class Myclass{
- public $prop = 123;
- final public static function methodA(){//不可繼承的,公開的靜態方法
- return 'this is a final method';
- }
- }
3、抽象類和抽象方法:abstract 僅用于 類和方法,抽象類不能直接用于實例化對象只能用于產生子類,代碼如下:
- abstract class Myclass{
- public $prop = 123;
- abstract public function methodA(); //抽象方法沒有實現函數體
- }
4、類的常量及其訪問,類的常量不能使用訪問限制修飾符,他是 public 的,可繼承,可以被子類重寫,訪問類的常量必須使用雙冒號 ::,可以使用類名或類的實例來訪問,代碼如下:
- class Myclass{
- public $prop = 123;
- const x =999;
- public static function methodA(){
- return 'this is a final method';
- }
- public function getConst(){
- return self::x; //或者 $this::x;
- }
- }
- $instance = new Myclass();
- echo Myclass::x;
- echo $instance::x;
- echo $instance->getConst();
類的常量是一個值,在代碼編譯期常量名被替換為相應的值,在運行期不可修改,因此,類的常量是與類本身相關,在實例化對象之前就已經存在了,因此類的常量可以直接使用類名訪問,代碼如下:
- class P{
- const m = 100;
- const n = self::m;
- }
- class S extends P{
- const m=200;
- public function getPConst(){
- return parent::n;
- }
- }
- $p = new P();
- $s = new S();
- echo $p::n; //100
- echo $s::n; //200 該常量名繼承自父類,在編譯期取 self::m 的值替換,注意區別類的方法中使用 self::m
- echo $s->getPConst(); //100
5、類的靜態成員及訪問
static 可 以修飾類的屬性及方法,被 static 修飾的成員屬于類而不屬于類的實例,靜態成員必須使用類名加雙冒號 :: 來訪問, 因為在實例化對象之前 靜 態成員就存在了,因此,在靜態方法內,禁止使用指向實例本身的偽變量 $this(或習慣上稱為 $this 指針),可以使用關鍵字 self 代替 類名(相當于類的魔術常量 __CLASS__).
static 不能用于修飾 類的構造函數,也不能用于修飾接口聲明的方法,代碼如下:
- class Myclass{
- public static $x = 99;
- public function getX(){
- return self::$x;
- }
- }
- echo Myclass::x; //99
靜態成員可以使用 訪問控制關鍵字修飾,可以被繼承和重寫,需要注意的是,如果一個子類繼承了父類的靜態方法(沒有重寫該方法),那么子類調用的實際是父類的靜態方法,因為靜態成員持有者是類不是對象,所以類的多個實例是共享同一個靜態屬性的,在一個實例中修改靜態屬性會影響到另一個實例中的靜態屬性,代碼如下:
- class A{
- public static $a1 = 11;
- public $a2 = 22;
- public static function showStatic(){
- return self::$a1;
- }
- public function getStatic(){
- return self::$a1;
- }
- public function getClassStatic(){
- $className = get_called_class();
- return $className::$a1;
- }
- public function getProp(){
- return $this->a2;
- }
- }
- class B extends A{
- public static $a1 = 88;
- public $a2 = 99;
- }
- $obj1 = new A();
- $obj2 = new B();
- echo A::showStatic(); //11
- echo $obj1->getStatic(); //11
- echo $obj1->getClassStatic(); //11
- echo $obj1->getProp(); //22
- echo B::showStatic(); //11 調用的是父類的方法,訪問父類的靜態成員
- echo $obj2->getStatic(); //11 調用的是父類的方法,方法中的 self 指向持有該靜態方法的類
- echo $obj2->getClassStatic(); //88
- echo $obj2->getProp(); //99
后期靜態綁定:為了避免子類重寫靜態屬性后,使用繼承來的方法仍然訪問父類的靜態屬性,PHP5.3 增加了一個新的語法:后期靜態綁定,使用 static 關鍵字替代 self 關鍵字,使得 static 指向與 get_called_class() 返回的相同的類,即當前調用該靜態方法的對象所屬的類,該關鍵字對于 靜態方法的訪問同樣有效,代碼如下:
- public function getClassStatic(){
- $className = get_called_class();
- return $className::$a1;
- }
- //可以寫成 :
- public function getClassStatic(){
- return static::$a1;
- }
- //用于靜態方法,代碼如下:
- //A類中:
- public static function testStatic(){
- echo "<p>testStatic of A </p>";
- }
- public function callStatic(){
- static::testStatic();
- }
- //B類中:
- public static function testStatic(){
- echo "<p>testStatic of B </p>";
- }
- //B類繼承A類的 callStatic 方法,可以正確訪問各自類的 testStatic 方法。
6、類的方法中幾個指向類或實例的關鍵字
$this->propName $this 指向類的實例
parent::xxx parent 指向父類,可以訪問父類的靜態常量、靜態屬性(parent::$xxx) ,不能訪問父類的非靜態屬性,可以調用父類的方法(不能是 private 方法,無論是否靜態)
self::xxx self 指向定義了當前被調用的方法的類,用于訪問靜態成員和類的常量
static::xxx 訪問實例化了調用當前方法的實例的那個類,用于訪問靜態成員和累的常量,他跟 self 的差別是訪問靜態成員時采用 “后期靜態綁定”.
7、類的繼承中的重寫問題:
重寫的成員的訪問控制程度不能被縮小,例如,public 的成員不能重寫為 protected,非靜態成員不能重寫為靜態成員,靜態成員也不能重寫為非靜態成員.
8、接口中定義的方法必須是 public
類在實現接口的方法時,這些方法也必須是 public 的,具體實現的(不能是 abstract ),接口也可以定義接口常量,用法與類常量完全一致,但是接口不可以定義非函數成員.
接口與接口之間可以繼承,接口的繼承可以是多繼承,用逗號隔開(字類與父類的繼承是單繼承的),一個類可以實現多個接口,用逗號隔開,代碼如下:
- interface Ix extends Iy,Iz{
- public function a();
- }
- class A implements Iy,Iz{
- .......
- }
9、類型約束
PHP 的函數(或類的方法)可以在聲明時限定參數的類型,但只能 限定 array 或 object(class/interface),如果限定為 string 型,PHP 會認為是限定為一個 string 類 的 object 參數,如果類型被限定為某個接口,則傳入的參數必須是實現該接口的類的實例.
在接口實現、子類重寫父類方法時,不能修改已經限定的參數類型,在方法、函數調用時,如果傳入了與限定的參數類型不同的數據將會報錯,但是可以接受 null 參數,代碼如下:
- interface Im{
- public function a( classm $m);
- }
- class A implements Im{
- public function a($x){ // error ,參數$x必須限定為 classm 類型以匹配接口的定義
- var_dump($x);
- }
- }
新聞熱點
疑難解答