<?php /** * Created by PhpStorm. * User: cl * Date: 2019/8/12 * Time: 7:08 */ /*oop*/ class Person{ public $name; public $gender; public function say(){ echo $this->name,'is',$this->gender; } } $student = new Person(); $student->name = "CL"; $student->gender = "MAN"; $student->say(); // CLisMAN var_dump((array)$student); // array(2) { ["name"]=> string(2) "CL" ["gender"]=> string(3) "MAN" } // 對象由屬性組成,一個對象的屬性是它區別於另外一個對象的關鍵所在。因爲php的對象使用數組來模擬的 // 所以咱們把對象轉成數組,就能看見這個對象所擁有的屬性了。 // 到這裏,能夠直觀的認識到,對象就是一堆數據。既然如此,能夠把一個對象存儲起來,以便須要時用,這就是對象的序列化。 $str = serialize($student); var_dump($str); // string(60) "O:6:"Person":2:{s:4:"name";s:2:"CL";s:6:"gender";s:3:"MAN";}" // 在須要時,能夠反序列化取出這個對象 var_dump(unserialize($str)); // object(Person)#2 (2) { ["name"]=> string(2) "CL" ["gender"]=> string(3) "MAN" } // 能夠看到,對象序列化後,存儲的只是對象的屬性。類是由屬性和方法組成的,而對象則是屬性的集合,由同一個類生成的不一樣對象, // 擁有各自不一樣的屬性,但共享了類的代碼空間中方法區域的代碼。 /*對象與數組*/ // 數組是由鍵值對數據組成,數組的鍵值對和對象的屬性/屬性值對十分類似。對象序列化後和數組序列化後的結果是 // 驚人的類似 $student_arr = ['name' => 'CL' , 'gender' => 'MAN']; var_dump(serialize($student_arr)); // string(49) "a:2:{s:4:"name";s:2:"CL";s:6:"gender";s:3:"MAN";}" // 區別在於 : 對象中還包含指針,指向了它所屬的類。 /* 對象與類*/ // 若是對象中還包含對象,那麼序列化後會是什麼樣子呢? class Family{ public $people; public $location; public function __construct ($p,$loc){ $this->people = $p; $this->location = $loc; } /* public function __destruct(){ var_dump('魔術方法之析構方法'); }*/ } $tom = new Family($student,"peking"); var_dump(serialize($tom)); // string(118) "O:6:"Family":2:{s:6:"people";O:6:"Person":2:{s:4:"name";s:2:"CL";s:6:"gender";s:3:"MAN";}s:8:"location";s:6:"peking";}" /* 能夠看出,序列化後的對象會附帶所屬類型,這個類名保證此對象在執行類的方法(也是本身所能執行的方法)時, 可以正確地找到方法所在的代碼空間(即對象所擁有的方法存儲在類裏)。另外,當一個對象的實例變量引用其餘對象時,序列化對象 也會對引用對象進行序列化 由此能夠分析兩者的關係 : 類是定義一系列屬性和操做的模板,而對象則是把屬性進行具體化,而後交給類處理 對象就是數據,對象自己包含方法。可是對象有一個」指針「指向一個類,這個類裏能夠有方法。 方法描述不一樣屬性致使的不一樣表現 類和對象是不可分割的,有對象就一定有一個類與其對應,不然這個對象也就成了沒有親人的孩子(但有一個特殊的狀況,就是 由標量進行強制類型轉換的object,沒有一個類與它對應。此時,PHP中一個稱爲」孤兒「的stdClass類就會收留這個對象) 能夠看出,在面向對象層面,js和php區別仍是很大的。 */ /*魔術方法*/ /* * 魔術方法是以兩個下劃線開頭,具備特殊做用的一些方法,能夠看做是PHP的語法糖 * 語法糖是指那些沒有給計算機添加新功能,而對人類來講更甜蜜的語法 * Family類的__construct方法就是一個標準的魔術方法。這個魔術方法又稱構造方法。具備構造方法的類會每次建立對象時 * 先調用此方法,因此很是適合在使用對象以前作一些初始化工做,如:給屬性賦值,鏈接數據庫等 * 有構造方法就有析構方法,即destruct方法,這個方法會在某個對象的因此引用都被刪除,或者當對象被顯式銷燬時執行。 * 這兩個方法是最多見也是最有用的魔術方法 */ /*魔術方法之set 和 get*/ class Account{ private $user = 1; private $pwd = 2; public function __get($name){ echo '請求'.$name; } public function __set($name,$val){ echo "請求設置".$name."爲".$val; } public function __call($name ,$arguments){ // $name : 要調用的方法名稱 // $arguments : 數組,包含着要傳遞給方法的參數 var_dump($name); var_dump($arguments); } public static function __callStatic($name ,$arguments){ var_dump($name); var_dump($arguments); } public function __toString() { return '任意字符串'; } } $a = new Account(); $a->user; // 若是沒有 __get 魔術方法則會報錯,大體意思是不能訪問對象的私有屬性 // 請求user $a->name = '123'; // 由於對象沒有name屬性,因此會觸發 __set 魔術方法 // 請求設置name爲123 /* * 能夠直觀的看到,若類中定義了set 和 get這一對魔術方法,那麼當給對象屬性賦值或取值時,即便 * 這個屬性不存在,也不會報錯,必定程度上加強了程序的健壯性 */ // 那麼,若是防止調用一個不可訪問的方法(如未定義,或者不可見)時,call()會被調用。 $a->demo('1','2'); // "demo" // array(2) { [0]=> string(1) "1" [1]=> string(1) "2" } // 當調用的靜態方法不存在或權限不足時,callStatic() 會被調用 Account::demo(); // "demo" // array(0) { } // 固然,使用魔術方法"防止調用不存在的方法而報錯",並非魔術方法的本意。實際上,魔術方法使方法的動態建立變爲可能。 // 這在MVC等框架設計中是頗有用的語法。能夠經過一段代碼使用callStatic這一魔術方法進行方法的動態建立和延遲綁定 // toString方法 echo $a; //任意字符串 // 好比打印一個對象時,看看這個對象都有哪些屬性,其值是什麼,若是定義了toString方法,就能在測試時,echo打印對象體 // 對象會自動調用它所屬類定義的toString方法,格式化輸出這個對象所包含的數據。若是沒有這個方法,那麼echo一個對對象將報錯
<?php /** * Created by PhpStorm. * User: chenglin * Date: 2019/8/12 * Time: 7:08 */ /*oop高級*/ class Person{ public $name = 'tom'; public $gender; public $money = 1000; public function __construct(){ echo '這裏是父類'; } public function say(){ var_dump( $this->name); } } class Family extends Person{ public $name; public $gender; public $money = 100000; public function __construct(){ parent::__construct(); echo "這裏是子類"; } public function say(){ parent::say(); } } $poor = new Family(); $poor->say(); // 這裏是父類 // 這裏是子類 // NULL /* * 從上面的代碼中能夠了解繼承的實現。在繼承中,用parent指代父類,用self指代自身。 * 使用"::"操做符(範圍解析操做符)調用父類的方法。"::"操做符還能夠做爲類常量和靜態方法的調用,不要把這兩種應用混淆。 * 既然提到靜態,就再強調一點。若是聲明類成員或方法爲static,就能夠不實例化類而直接訪問 */ /*接口*/ /* * 這裏,首先強調一個概念,面向接口編程並非一種新的編程範式。本章開頭提到的三大範式中並無提到面向接口。其實, * 這裏是狹義的接口,即 interface 關鍵字。廣義的接口能夠是任何一個對外提供服務的出口,好比提供數據傳輸的usb接口, * 、淘寶網對其餘網站開放的支付寶接口。 * 接口定義一套規範,描述一個"物"的功能,要求若是現實中的"物"想成爲可用,就必須實現這些基本功能。接口這樣描述本身: * "對於實現個人因此類,看起來都應該向我如今這個樣子" * 在程序中,接口的方法必須被所有實現,不然會報fetal錯誤 */ interface mobile{ public function run(); // 驅動方法 } class plain implements mobile{ public function run() { // TODO: Implement run() method. echo "我是飛機"; } public function fly(){ echo "飛行"; } } (new plain())->fly(); // 飛行 // 思考: 接口自己並不提供實現,只要提供一個規範。 // php中,接口的語義是有限的,使用接口的地方並很少,php中接口能夠淡化爲設計文檔,起到一個團隊基本契約的做用 // 因爲php是弱類型,且強調靈活,因此並不推薦大規模使用接口,而僅在部分"內核"代碼中使用接口。從語義上考慮, // 能夠更多地使用抽象類 //抽象類 abstract class Fruits{ // 水果名稱 protected $name; // 抽象方法 abstract public function eat(); // 儘管不能實例化抽象類,但仍然能夠有構造方法 public function __construct(){ echo "抽象構造器,實例化時自動調用" ; } } class Apple extends Fruits{ protected $name = "蘋果"; public function eat(){ echo $this->name . "能夠直接生吃"; } // 子類構造方法 public function __construct() { echo parent::__construct(); } } $apple = new Apple(); echo $apple->eat(); // 抽象構造器,實例化時自動調用 // 蘋果能夠直接生吃 // 抽象類提供了具體實現的標準,而接口則是純粹的模板 /*反射*/ /* * 面向對象編程中對象被賦予了自省的能力,而這個自省的過程就是反射。 * 反射,直觀理解就是根據到達地找到出發地和來源。比方說:我給你一個光禿禿的對象,我能夠 * 僅僅經過這個對象就能直到它所屬的類,擁有哪些方法 */ // 反射API $reflect = new ReflectionObject($apple); // 獲取對象屬性列表 $props = $reflect->getProperties(); foreach ($props as $prop){ var_dump($prop->getName()); } // string(4) "name" // 獲取對象的方法列表 $m = $reflect->getMethods(); foreach ($m as $prop){ var_dump($prop->getName()); } // string(3) "eat" // string(11) "__construct" // 也能夠不用反射API,使用class函數,返回對象屬性的關聯數組以及更多信息 var_dump(get_object_vars($apple)); // 返回對象屬性的關聯數組 // array(0) { } var_dump(get_class_vars(get_class($apple))); // 類屬性 // array(0) { } var_dump(get_class_methods(get_class($apple))); // 返回由類的方法名組成的數組 // array(2) { [0]=> string(3) "eat" [1]=> string(11) "__construct" } // 在此。利用強大的反射API功能範元這個類的原型,包括方法的訪問權限: $obj = new ReflectionClass('Apple'); // 獲取類型 $className = $obj -> getName(); // 初始化方法和成量數組 $methods = $properties = []; foreach ($obj->getProperties() as $v){ $properties[$v->getName()] = $v; } foreach ($obj->getMethods() as $v){ $methods[$v->getName()] = $v; } echo "<br />class {$className}<br />{<br />"; is_array($properties) && ksort($properties); // 數組排序 // 遍歷出類的屬性 foreach ($properties as $k => $v){ echo "\t"; echo $v->isPublic() ? 'public' : '',$v->isPrivate() ? 'private' : '',$v->isProtected() ? 'protected' : '', $v->isStatic() ? 'static' : ''; echo "\t{$k}"; } // 遍歷出類的方法 is_array($methods) && ksort($methods); // 數組排序 foreach ($methods as $k => $v){ echo "<br />function $k(){}"; } echo "<br / >}"; /* class Apple{ protected name function __construct(){} function eat(){} } */ /* * 反射的做用: 用於文檔生成。所以能夠用它對文件裏的類進行掃描,逐個生成描述文檔 *