這篇文章不適合於初學者看,對php有一定瞭解的可以看一下,補充或者溫故一下php物件導向裡的一些特性。
一.何為物件導向?
介個問題,雖然略知一二,卻感覺依然拿不出手,只能說將萬事萬物皆看為對象,只有在開發中才能體會出何為物件導向,只說也是徒然,但因為php大多用在web開發,所以,即使不使用物件導向也能啟動並執行不錯,之前在做c++開發時,設計給你個功能介面,看到這個介面,第一件事就是像美工切圖一樣的切成一個個的對象,然後,確定各個對象之間的關係,最後進行開發,哪兒都充斥著此思想。
什麼是類?什麼是對象?
類是一組集合的抽象,什麼集合呢?是一組具有相似特性和操作的對象的集合。
對象是某一個類的具體執行個體。
畢業時候可能我會背給面試官聽,可現在,雖然感覺理解的還是想書本上的語句一樣的俗,但起碼不用再靠腦細胞說出這兩個定義。
二.php中的類結構
php中類也是那些存取控制符,也是有屬性和方法。
class Person { private $name = "PersonName"; public static $gender = "PersonGender"; public function test(){ echo $this->name, '
'; }};
三.建構函式
建構函式的名稱為__construct,在建構函式這裡我想強調的有以下幾點:
1. php不會像其他語言(c++或者java)那樣,當執行個體化子類的時候會自動調用你的父類建構函式,php裡需要手動調用父類的建構函式,這兒牽扯到繼承,可以先看一下繼承方面的東西。
class Person{public funciton __construct(){echo 'Person construct
';}};class Teacher extends Person{public function __construct(){//parent::__construct();echo 'Teacher construct
';}};$t1 = new Teacher; //產生Teacher對象
運行結果:
Teacher construct
如果想要在產生子類時初始化父類的一些資料,需要手動調用父類的建構函式,開啟注釋行即可。
2. 一個類中不能寫兩個參數不同的建構函式。
這兒牽扯到php中的一些規定,其他語言中,以下寫法是正確的:
class Person{public funciton __construct(){echo 'Person construct
';}public function __construct($param){echo 'Person with param construct
';}};
而在php是不允許的,究其根源為php是一種弱語言類型,對於類型的限制不是很敏感,進而提供了__call和func_get_args函數機制,因而可以用如下的方式實現:
class Person{public function __construct(){$param = func_get_arg(); //擷取參數資料$param_num = func_num_args(); //擷取參數個數if($param_num == 0){}else if($param_num == 1){if(is_array($param[0])){//...}}else{//...}}};
三.解構函式
解構函式是用於在此執行個體對象結束時,自動調用的函數,可以寫入一下釋放記憶體的語句來為執行個體的死亡畫上完美的句號,這兒與構造相同,有繼承關係時必須手動調用父類的析構,一個類中只有一個析構。
四.控制訪問符
public:公用訪問符,在類內,子類內,類外都可以訪問此屬性或方法。
protected:受保護的訪問符,只能在類內和其子類內訪問此屬性或方法,在類外不能訪問。
private:私人訪問符,只能在本類內訪問,屬於本類私人東東,不能繼承,不能重載,任何人訪問不了。
五.魔術方法__get和__set
這兩個方法的功能:對受保護和私人屬性訪問的一個訪問器,可以對從類外接收到的資料進行安全性和合理性的校正。
__set方法接收兩個參數,第一個是屬性名稱,第二個是要賦的新值。
__get方法接收一個參數,屬性名稱。
1. public屬效能提供在類外修改屬性的服務,因此,對於public屬性,不會走__get和__set流程。
class D{ public $name = 'D name'; protected $gender = 'male'; private $age = 18; public function __set($name, $value){ echo '__set
';//if(in_array($name, ['name', 'gender', 'age']))$this->$name = $value; } public function __get($name){ echo '__get
';//if(!in_array($name, ['name', 'gender', 'age'])) return NULL; return $this->$name; }};
運行結果:
new D name //name為public屬性,不會走get和set__set__getnew D gender__set__getnew D age
2. 我們也可以加入資料校正的功能,開啟注釋就可以進行校正。
3.兩個方法必須是public訪問,否則會提示錯誤,我們可以從這兩個函數的功能來出發思考,就不難想象為什麼需要public存取控制。
六.繼承
終於到了可以讓你的菊花開苞的特性,沒有繼承,所有類都是渣渣,因為有了繼承,所以...問題就特麼的一大波一大波的來啦...讓我們來深入淺出一下此繼承特性。
什麼繼承就不說了吧,文章的開頭就有一個繼承的小樣本。
有了繼承會出現什麼問題呢?想一下,如果B繼承了A...真的是難以想象...
1. 建構函式,這個放心,跟繼承沒有太多關係,相當於兩個類裡的建構函式,但是怎麼也有個父子關係啊,不能把事做的太絕,所以,上面講過,如果有需要,可以手動調用父類的建構函式,可以看下上面的樣本。
2.單方向繼承,繼承是單方向的,子類可以從父類繼承,但父類卻不能從子類繼承特性,樣本:
class A{public $attr1;public function oper1(){}};class B extends A{public $attr2;public function oper2(){}};//子類可以繼承父類$b = new B;$b->oper1();$b->attr1 = 'attr1 value';$b->oper2();$b->attr2 = 'attr2 value';//父類不能繼承子類$a = new A;$a->oper2();//出錯$a->attr1();//出錯
3. 重載,一提到php的重載就特別彆扭,因為他的重載放到其他語言裡叫做重寫overwrite,我還是習慣將這個特性說為重寫,大家隨便。
<1>public重載:
class E{ public $attr1 = 'E attr1 value'; public function oper1(){ echo 'E oper1
'; echo 'attr1 value = ', $this->attr1, '
'; }};class F extends E{ public $attr1 = 'F attr1 value'; public function oper1(){ //parent::oper1(); echo 'F oper1
'; echo 'attr1 value = ', $this->attr1, '
'; }};$f = new F;$f->oper1();
運行結果:
F oper1
attr1 value = F attr1 value
F繼承了E並且重寫了E的attr1和oper1,因此,在調用oper1時,$this->attr1顯示F attr1 value,如果開啟注釋parent::oper1調用父類的Oper1方法,運行結果如下:
E oper1
attr1 value = F attr1 value //attr1屬性已經被子類重寫的attr1屬性覆蓋
F oper1
attr1 value = F attr1 value
可以看出子類重寫父類的屬性和方法後,會覆蓋父類相應的屬性和方法。
<2>private重載
class E{ private $attr1 = 'E attr1 value'; public function oper1(){ echo 'E oper1
'; echo 'attr1 value = ', $this->attr1, '
'; }};class F extends E{ public $attr1 = 'F attr1 value'; public function oper1(){ parent::oper1(); echo 'F oper1
'; echo 'attr1 value = ', $this->attr1, '
'; }};$f = new F;$f->oper1();以上代碼只變動了一處地方,就是把父類$attr1的訪問屬性變成private,那重載機制如何執行呢?先看運行結果:
E oper1
attr1 value = E attr1 value //父類私人的屬性
F oper1
attr1 value = F attr1 value
之前我們說過,private屬性和方法子類是繼承不了的,這種情況,遵循一個原則:
private屬性在那個類裡調用的,就顯示哪個類裡的屬性值。
樣本中的parent::oper1方法調用的是E類的oper1方法,在E的oper1方法內又調用了$this->attr1,attr1是private並沒有被子類繼承,因此,調用的就是類E裡的attr1屬性值。
<3>protected重載與public重載一致
<4>類屬性的繼承
class G{ public static $attr1 = 'G attr1 value'; public function oper1(){ echo 'G oper1
'; echo 'attr1 value = ', self::$attr1, '
'; }};class H extends G{ public static $attr1 = 'H attr1 value'; public function oper1(){ parent::oper1(); echo 'H oper1
'; echo 'attr1 value = ', self::$attr1, '
'; }};$h = new H;$h->oper1();
運行結果:
G oper1
attr1 value = G attr1 value
H oper1
attr1 value = H attr1 value
其實不管G類的attr1屬性是public還是private,結果都一樣。
個人是這麼理解的,類屬性可以繼承,但談不上重載,那關於子類調用父類的屬性也有一規則:
self或者parent只代表本類,因此,根據這一原則可以斷定,屬性的值一定是本類屬性的值,與子類無關。(特殊情況時php的靜態消極式載入機制)。
七.靜態消極式載入
既然已經提到了靜態消極式載入,就趁熱打鐵講一下,H和G的例子大家已經看了,那我就是想要在子類中調用父類的東東怎麼辦?靜態消極式載入就是解決這個問題,請看兩個樣本:
樣本1:
還是H和G類的例子
class G{ public static $attr1 = 'G attr1 value'; public function oper1(){ echo 'G oper1
'; echo 'attr1 value = ', static::$attr1, '
'; }};class H extends G{ public static $attr1 = 'H attr1 value'; public function oper1(){ parent::oper1(); echo 'H oper1
'; echo 'attr1 value = ', self::$attr1, '
'; }};$h = new H;$h->oper1();運行結果:
G oper1
attr1 value = H attr1 value
H oper1
attr1 value = H attr1 value
上面代碼只是將G類裡的self::$attr1改寫成了static::$attr1,運行結果就不一樣了
樣本2:
class I { public static function who(){ echo __CLASS__, '
'; } public static function test(){ static::who(); }};class J extends I{ public static function who(){ echo __CLASS__,'
'; }};
運行結果:
J
通過這兩個例子,可以好好的領悟一下static的靜態延遲綁定。
寫的有點多,主要是因為一牽扯繼承就停不下來....物件導向還有一些只是點,後面有時間再補上吧...謝謝,如若有錯誤的地方,敬請大家指出,隨時更正,謝謝!!