基於 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; static $k = 99; public function getStatic(){ return self::$k; } public function getStatic2(){ return static::$k; } } class S extends P{ const m=200; static $k = 88; public function getPConst(){ return parent::n; } } $p = new P(); $s = new S(); echo $p::n; //100 echo '<br />'; echo $s::n; //200 該常量名繼承自父類,在編譯期就已經直接取 self::m 的值替換了 ,注意區別類的方法中使用 self::m echo '<br />'; echo $s->getPConst(); //100 echo '<br />'; echo $s->getStatic(); //99 調用方法時 echo '<br />'; echo $s->getStatic2(); //111
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); } }