探討面向對象
1.面向對象是什麼:
面向對象開發簡稱:OOP。它是一種程序設計的規範,同時也是一種開發方法。它的核心思想爲對象化(頂層的設計)、封裝化(代碼集合在一塊兒)、可重用性(減小冗餘)和可擴展性(方便後期維護)。
所謂對象化,就是將程序做爲一個基本的單元,經過命令式的去執行。
所謂封裝化和可重用性,就是將大量可能會冗餘的代碼集合在一塊兒模塊話,只留一些對外接口給開發者調用。
所謂可擴展性,就是造成一種規範,方便後續增長更多功能而不破壞原先的結構。
2.面向對象的核心:
面向對象有三個核心功能:封裝、繼承和多態。
封裝:即將大量實現代碼集合在一塊兒,留出可調用的接口對外。能夠想象一下電腦主機裏,用機箱將主板、CPU、硬盤、內存等封裝在裏面,防止噪音也防止灰塵,只留下一排對外的接口供你調用。
繼承:即將一些程序代碼有規則的複製到另外一個地方使用的方式。能夠理解爲,兒子繼承了父親房產,那麼房產屬於他們公有的部分。固然也會出現一些規則限制,好比父親的微信號或QQ號等,兒子沒法繼承。
多態:即一種事物的多種形態,在程序中體如今不一樣的對象執行同一個方法返回出不一樣的結果。一個很經典的例子:「剪」這個行爲。園丁去用剪這個動做,就是修理花草;理髮師用剪這個動做,就是打理頭髮;總裁去用剪這個動做,就是裁人。這也是面向對象的高級抽象以及精華所在。
3.面向過程和麪向對象的比較:
面向過程,是一種能夠理解爲按照必定的步驟一步一步的完成所須要的功能。這種方式的優勢很明顯,思惟單一,好理解,適合入門開發的人上手起步。缺點也很明顯,各類功能中相同的代碼冗餘太多,擴展性差,維護性差。能夠理解爲剛成立的小公司,只有本身一我的,凡事都是本身親力親爲。
使用面向對象,是一種自上而下的開發方式,頂層作好架構,封裝留出接口,下面具體實現。缺點呢,就是起步稍顯困難一些,在很小的程序感受有點臃腫;優勢是:稍微有些規模的項目,極大的釋放編碼的潛力,可重複性和可擴展性獲得的很大的提高。用現實的例子比如一家有些規模的公司,上層管理者制定計劃方案遞交給底層具體實施的人員去執行操做。
4.面向對象的目的:
1.解決代碼冗餘,沒法可重複性的問題,封裝模塊化後冗餘被大量減小;
2.解決擴展性和維護性,因爲制定了一些的規則後,並不像面向過程那麼隨意的進行編碼,這樣無論是一段時間後的維護擴展仍是換人更新,均可以迅速上手,不須要研讀他人思路的代碼;
3.可團隊化,每一個功能接口實現的規則都一致,多人開發造成了可能。php
類與對象
1.建立一個類:
面向對象有具體的語法,首先第一部須要建立一個類。
建立一個類有三個部分組成:第一部分:關鍵字class,第二部分:類名規範第一個字母大寫,第三部分:花括號{}
//建立一個類
class Person
{
}
一個類建立好了,在花括號裏暫時什麼都沒有,這是一個最基本的空類。
2.聲明對象:
(1)使用 new 類名;語法來建立一個對象。數據庫
//建立一個對象 new Person;
建立Person對象,咱們也能夠稱爲:聲明Person對象或實例化Person類。
當實例化後會在內存區域分配一個存儲空間,這個內存叫堆內存,在堆內存分配了一個存儲空間new Person,這個空間存放這個對象的具體內容
(2)查看對象
能夠經過print_r或var_dump函數來獲得這個對象的具體信息。編程
//查看對象 print_r(new Person); var_dump(new Person);
返回結果:Person Object ( )
返回結果:object(Person)[1]
推薦var_dump,信息更全,更加直觀
(3)建立多個對象
實例化一個類就分配一個內存區域,咱們也能夠聲明多個對象來實現各自獨立的功能。此時,咱們須要給每一個對象關聯上相應的引用地址(或叫對象變量標識)來區分每一個對象。注:有時咱們直接就稱這個引用變量爲對象。數組
//建立多個對象,把對象的引用地址賦值給變量,這個變量也能夠俗稱對象。 $p1 = new Person; $p2 = new Person; var_dump($p1); var_dump($p2);
打印結果:
object(Person)[1]
object(Person)[2]
3.類與對象的探討
(1)類是什麼?是一種抽象組織,比如一臺還沒有啓動的機器,它的結構是固定的統一的;
(2)對象是什麼?是具體實現者,比如操控這臺機器的人,它多是不同的;
(3)當人不去操控這臺機器時,這臺機器毫無做用;
(4)而不一樣的人去操控這臺機器時,獲得的效果也大相徑庭。微信
屬性和方法架構
屬性設置
1.屬性其實就是一種變量,只不過它是類裏面的變量。咱們還能夠稱做:字段或成員變量。
2.屬性和變量的設置差不了太多,只不過必須在類裏面設置。最重要的一點是,在屬性前面須要加上一個可見的修飾符,省略修飾符會報錯。修飾符有如下三種形式:
(1).public 表示公開的,在類內、子類和類外都可以讀寫;
(2).protected 表示受保護的,在類內或子類能夠能夠讀寫,類外不行;
(3).privte 表示私有的,只能在類內讀寫,子類和類外不行。
3.對於 public 公共屬性,能夠直接在類外經過對象的賦值與取值操做。
4.使用對象調用類裏面的屬性,能夠經過「->」符號來訪問屬性或方法。請注意,調用屬性的時候,這個變量將不須要再帶「$」符號。框架
<?php //屬性建立 class Person { public $name = 'Lee'; } //屬性的賦值和取值操做 $p1 = new Person; //輸出name echo $p1->name;
輸出結果:
Leeide
5.咱們在設置屬性的時候,能夠不用當即初始化賦值,只是單純的聲明,將賦值的操做留給後面動態處理。
6.建立多個對象實例後,每一個對象實例分配一個內存區域,而它們之間是沒有關聯的,本身運行着本身的屬性和方法。模塊化
<?php //屬性建立 class Person { public $name; } //對象1 $p1 = new Person; //賦值 $p1->name = 'Wang'; //取值 echo $p1->name; //對象2 $p2 = new Person; $p2->name = 'xixi'; echo $p2->name;
輸出結果:
Wangxixi函數
7.也有種狀況就是將其中的一個對象變量賦值給另一個變量,從而讓兩個變量同時指向一個對象實例。
<?php //屬性建立 class Person { public $name; } //對象1 $p1 = new Person; //賦值 $p1->name = 'Wang'; //取值 echo $p1->name; //對象2並無new,不new的話就不會開闢新的內存空間 $p2 = $p1; echo $p2->name; $p2->name = 'xixi'; echo $p1->name;
方法設置
1.方法就是類裏面的函數;
2.調用方法和屬性基本一致,而方法和函數的表現形式也是同樣的;
<?php //方法建立 class Person { public function run() { return '運行中...'; } } $p1 = new Person; echo $p1->run();
輸出結果:
運行中...
3.前面的修飾符默認狀況下,能夠省略,那麼默認就是公開的,也有受保護和私有的形式。但規範要求咱們,前面必須加上修飾符,以表示肯定。
4.使用$this 關鍵字,能夠在類的內部調用屬性或方法。
<?php //方法建立 class Person { public $name = 'Lee'; public function run() { //注意:$this表明當前實例化的對象,好比$p1 return $this->name.'運行中...'; } } $p1 = new Person; echo $p1->run();
輸出結果:
Lee運行中...
5.$this 關鍵字在多個實例時,只表示當前實例的屬性值。
<?php //方法建立 class Person { public $name; public function run() { //注意:$this表明當前實例化的對象,好比$p1 return $this->name.'運行中...'; } } //$p1調用了run,$this就表示$p1 $p1 = new Person; $p1->name = 'Wang'; echo $p1->run(); //$p2調用了run,$this就表示$p2 $p2 = new Person; $p2->name = 'XiXi'; echo $p2->run();
輸出結果:
Wang運行中...XiXi運行中...
讀寫方式
1.若是咱們想將屬性進行封裝保護起來,不對外直接訪問操做,也就是設置成private。
<?php //方法建立 class Person { private $name = 'Wang'; public function getName() { return $this->name; } } $p1 = new Person; echo $p1->getName();
輸出結果:
Wang
詳解:setName傳一個參數'Wang'給setName()裏的$name的變量,這個變量再傳給屬性$this->name = $name,經過public function getName()這個方法打印出
屬性和方法前置修飾符
可見性控制
1.public 是公共對外訪問的修飾符,若是默認不加修飾符,則就是 public。固然,規範要求嚴格必須加上修飾符,以保證程序的健壯性。
2.private 是將屬性或方法私有化,將沒必要要對外的屬性或方法封裝起來,能夠極大減小調用者的使用成本和難度。
3.面向對象的其中一種原則就是:若是沒有必要從讓這個屬性和方法對外訪問,那麼就不要將它公開,只有小量的對外接口便可。固然,若是過分的封裝會致使擴展不順暢,好比一個房子,四面均爲牆,只留了一個狗洞,那麼進出就很不方便。那麼,此時可使用protected 受保護的,它對外也是不可訪問的,但對於擴展類來講是能夠訪問的。
4.使用兩個方法進行對不直接公開的屬性進行賦值和取值,咱們成爲setter和getter。
<?php //受保護的 class Person { protected $name; public function setName($name) { $this->name = $name; } public function getName() { return $this->name; } } $p1 = new Person; //echo $p1->name; $p1->setName('Wang'); echo $p1->getName();
打印結果
Wang
靜態修飾符
1.靜態屬性存放在靜態內存區域,屬於公共區域,能夠覆蓋或累計。不須要實例化對象,直接經過「類名::靜態屬性名」方式調用。
2.靜態屬性僅屬於類的屬性,而不屬於對象的屬性。言下之意就是,它直接由類操控,而不併不是對象操控的。因此,不存在會分配多個內存區域,只有一個靜態區。
<?php //靜態屬性 class Person { public static $name = 'Lee'; } Person::$name = 'Wang'; echo Person::$name;
打印結果
Wang
3.在普通對象的方法裏怎麼調用靜態方法呢?可使用 self 關鍵「self::靜態屬性名」。
<?php //靜態屬性 class Person { //私有化,在類外沒法調用 private static $name = 'Lee'; public function getStaticName() { return self::$name; } } $p1 = new Person(); echo $p1->getStaticName();
打印結果
Wang
4.靜態屬性經常使用於一些數據的累計,好比統計次數。
<?php //靜態屬性,數據統計 class Person { private static $count = 0; public function addCount() { self::$count++; } public function getCount() { return self::$count; } } $p1 = new Person; $p1->addCount(); $p1->addCount(); $p1->addCount(); $p2 = new Person; $p2->addCount(); $p2->addCount(); $p2->addCount(); echo $p1->getCount();
打印結果:
6
5.靜態方法的功能就簡單明瞭,直接經過「類名::靜態方法名」調用,和麪向過程函數同樣調用。靜態方法經常使用於工具類的那種,不須要實例化直接調用便可的。
<?php class Tool { public static function back() { echo "<script>alert('非法操做!')</script>"; } } Tool::back();
執行結果:
彈出一句話:非法操做!
魔術方法
PHP中的魔術方法,這種方法由兩個下劃線「__」開頭,具備一些特殊的做用。
1.__set 與__get
1.對於封裝的屬性,咱們經過setter和getter方式來對屬性進行賦值和取值。而實際上,一個類中可能有十幾個或更多的屬性,那麼就必須有十幾組賦值和取值的對外方法。這樣的工做量也是很是龐大的,PHP 提供了這組魔術方法來解決這個問題。
?php //__set和__get class Person { private $gender; private $age; private $work; //動態通用賦值,$name表示屬性名稱,$value表示屬性的值 public function __set($name, $value) { //注意,這裏的name 帶$符號的,表示的是變量而不是屬性 //而$name可能就是某個屬性,根據傳遞過來的參數決定 //若是傳遞的是"gender"和"男",$this->gender = '男'; $this->$name = $value; } //動態通用取值 public function __get($name) { return $this->$name; } } $p1 = new Person; $p1->gender = '男'; //這裏至關於$p1->__set('gender', '男'); $p1->age = 30; $p1->work = '醫生'; echo $p1->gender.$p1->age.$p1->work;
返回值:
男30醫生
2.__set和__get主要是對沒法直接訪問的屬性起做用,若是是公共的屬性private,它會直接賦值取值。
3.以前獲取屬性方式是$this->name,這種形式。若是用__set則是$this->$name,$name 變量經過參數傳遞,多是$name表示的是gender、age或work,這是動態的。
2.__construct構造
1.構造方法或構造函數是一種特殊的類的方法,早期使用只須要和類同名的方法便可實現構造方法。
2.而目前爲了防止混淆,使用了魔術方法__construct 來取代類同名的方法,可讀性更加的高。
3.構造方法的參數,由實例化時進行傳遞。
<?php //構造方法 class Person { public function __construct($name) { echo $name.'魔術方法構造!'; } } $p1 = new Person('XiXi'); $p2 = new Person('Wang');
返回值:
XiXi魔術方法構造!Wang魔術方法構造!
4.因而可知,構造方法的目的是當對象實例化後,是對整個對象數據的初始化工做。就好像機器啓動後,各個環節進行充能就位同樣。
5.對於沒有參數傳遞時,之後默認的寫法就留着空括號便可,方便之後擴展,不須要刻意的去掉括號。
//不傳參
$p1 = new Person();
3.__destructor()析構
1.析構方法和構造方法正好相反,當對象的方法所有執行完畢後自動調用析構方法。這種方法通常用於清理和銷燬操做,好比清理內存,銷燬數據庫連接等。固然,這個方法不太經常使用,由於如今都自動清理(俗稱垃圾回收)。
//析構方法
public function __destruct()
{
echo '析構方法,運行結束後銷燬還原!';
}
4.__call 方法
1.因爲某種緣由,有時可能調用了不存在的方法。這樣,會報出一個找不到相關方法的錯誤
//調用不存在的方法語法: class Person { } $p1 = new Person(); $p1->run(); 2.可使用__call 魔術方法來屏蔽錯誤調用,當調用不存在方式時,則執行這個魔術方法。須要填寫兩個參數:$name 表示方法名;$arguments 表示參數列表。 <?php //調用不存在的方法 class Person { //沒有執行到指定方法則會自動執行__call魔術方法 public function __call($name, $args) { echo $name.'方法不存在!'; echo '<br>'; foreach ($args as $value) { echo $value; } } } $p1 = new Person(); $p1->run('Mr.', 'Lee', 25);
返回值:
run方法不存在!
Mr.Lee25
3.相對於了還有一種是靜態方法調用不存在時,使用__callStatic魔術方法。
<?php //調用不存在的方法 class Person { //沒有執行到指定方法則會自動執行__call魔術方法 public static function __callStatic($name, $args) { echo $name.'方法不存在!'; echo '<br>'; foreach ($args as $value) { echo $value; } } } Person::tool('Mr.', 'Lee', 25);
返回值:
tool方法不存在!
Mr.Lee25
5.__isset 方法
1.當不可對外訪問的屬性在類外調用了 isset/empty 方法判斷是否設置或有值時,會自動調用__isset 魔術方法,來避免錯誤和返回判斷結果。
<?php //__isset判斷非公開屬性是否存在或是否有值 class Person { private $name = 'Wang'; public function __isset($name) { return isset($this->$name); } } $p1 = new Person(); echo isset($p1->name);
返回值:
1
詳解:isset執行($this->$name)的時候發現private $name = 'Wang';是私有的執行不到,而後會自動跳到__isset($name)去執行
2.反之,還有一個__unset 魔術方法,即:調用unset不對外的屬性時觸發。
<?php //__isset判斷非公開屬性是否存在或是否有值 class Person { private $name = 'Wang'; public function __isset($name) { return isset($this->$name); } public function __unset($name) { unset($this->$name); } } $p1 = new Person(); echo empty($p1->name); unset($p1->name);
返回值:
1
6.__toString 方法
1.原則上,是沒法直接輸出(echo)對象信息的。而經過 var_dump 只能輸出系統自己格式化後的信息。有時,咱們完成一個類,相對調用的開發這顯示出這個類全部屬性和方法具體的信息介紹,可使用__toString 魔術方法來自定義對象的信息輸出格式。
<?php //輸出對象自定義信息 class Person { private $name = 'XIXI'; public function run() { return 'running...'; } public function __toString() { $str = ''; $str .= '私有字段:name,用於姓名的賦值和取值<br>'; $str .= '公共方法:run(),用於對外輸出名稱'; return $str; } } $p1 = new Person(); echo $p1;
私有字段:name,用於姓名的賦值和取值
公共方法:run(),用於對外輸出名稱
2.魔術方法的原理很簡單,當沒法執行或報錯時就會調用這個方法。
對象中使用繼承(解決代碼中大量冗餘和擴展的便利性)
繼承的概念
1.繼承是類與類之間相互結合的關係。通俗一點就是說:兒子(子類)從父親(父類)或母親那邊繼承了外貌(屬性)和性格(方法)。
2.子類能夠從父類那裏繼承或擴展,而父類並不知道子類繼承了它。因此,一個父類能夠有被多少個子類繼承沒有限制。
3.子類繼承了父類的全部特性,並在這個基礎上進行加強,最終獲得獨具一格的擴展。
4.繼承的關鍵字是:extends。
<?php //父類(基類) class Father { public $name = 'Mr.Wang'; public function run() { return $this->name.'running...'; } } //子類(派生類) class Children extends Father { //1.能夠把非私有的屬性繼承下來 //2.能夠把非私有的方法繼承下來 } $c1 = new Children(); echo $c1->name; echo $c1->run();
返回值:
Mr.WangMr.Wangrunning...
<?php //父類 class Father { protected $name = 'Mr.Wang'; protected function run() { return $this->name . 'running...'; } } //子類 class Children extends Father { //受保護的,是能夠繼承下來的,可是不能類外訪問 public function test() { echo $this->name; echo $this->run(); } } $c1 = new Children(); $c1->test();
返回值:
Mr.WangMr.Wangrunning...
5.子類繼承了父類的屬性和方法,那麼實例化子類對象後,可直接調用屬性和方法。
6.若是當父類的屬性或方法設置爲私有:private 時,那麼就沒法被子類繼承。
<?php //父類 class Father { private $name = 'Mr.Lee'; private function run() { return $this->name . 'running...'; } } //子類 class Children extends Father { //私有的屬性和方法沒法繼承 public function test() { //echo $this->name; //echo $this->run(); } } $c1 = new Children(); $c1->test();
7.若是父類建立了構造方法,而子類沒有建立構造方法,則聲明子類會自動執行父類的構造方法。
<?php //父類 class Father { public function __construct() { echo '父類構造'; } } //子類 class Children extends Father { } $c1 = new Children();
打印:
父類構造
覆蓋重寫
1.若是子類建立了構造方法,則父類的構造方法會被覆蓋(重寫),按規範要求須要在子類構造方法裏調用父類構造。
2.使用 parent::__construct()方式能夠調用父類的構造方法,parent 表示父類,也可使用父類名::__construct()調用,但推薦使用 parent。
3.普通的父類方法,也能夠被子類重寫,也可使用parent關鍵字調用父類方法。
<?php //父類 class Father { public function __construct() { echo '父類構造'; } } //子類 class Children extends Father { public function __construct() { //調用父類構造方法:父類名::__construct() //Father::__construct(); //推薦parent表明父類 //構造方法主要做用是初始化數據,父類的初始化也必須運行,因此子類構造須要調用父類構造 parent::__construct(); echo '子類構造'; } } $c1 = new Children();
打印:
父類構造子類構造
3.普通的父類方法,也能夠被子類重寫,也可使用parent關鍵字調用父類方法。
4.通常來講子類調用自身的方法使用$this 便可,也可使用 self::方法()來調用自身重寫的方法,來強調不是調用父類方法。
<?php //父類 class Father { public function run() { echo '父類run'; } } //子類 class Children extends Father { //1.父類方法被繼承,this就調用父類的方法 //2.子類方法重寫了,this就調用子類的方法 //3.this可使用self來強調,我是調用的子類。 public function run() { echo '子類run'; } public function test() { //$this->run(); self::run(); } } $c1 = new Children(); $c1->test();
子類run
6.繼承只支持單繼承,也就是說,不能夠同時繼承多個父類
面向對象中的抽象類和其它的抽象方法
抽象類
1.抽象類提供了一種機制,父類中的抽象方法並無實現(僅提供方法聲明),而是必需要求子類重寫這個方法去實現它。
2.若是一個類中有抽象方法,那麼此類必須聲明成抽象類。
3.抽象類和抽象方法的聲明修飾符是:abstract。
4.抽象方法聲明的修飾符不能夠是private的,必需要子類繼承,private沒法繼承實現,而protected(受保護的)或public(公有的)都可。
5.抽象類沒法實例化,也就是說,抽象方法的修飾符是protected和public並無什麼區別。因此不少狀況下,咱們發現都是省略不寫的,按照規範來講,建議寫上去可讀性高一些。
<?php //抽象類 abstract class Person { //抽象方法 abstract protected function run(); } //子類 class Man extends Person { //實現抽象方法 public function run() { echo '運行...'; } } $m1 = new Man(); echo $m1 ->run();
打印:
運行...
6.抽象方法裏面也可使用普通的屬性和普通方法,在子類繼承下來,正常使用。
<?php //抽象類 abstract class Person { protected $name = 'Wang'; public function getName() { return $this->name; } //抽象方法 abstract protected function run(); } //子類 class Man extends Person { //實現抽象方法 public function run() { return '運行...'; } } $m1 = new Man(); echo $m1 ->run(); echo $m1->getName();
打印:
運行...Wang
7.若是父類的抽象方法有參數,那麼子類實現時,也必須跟着實現這兩個參數。
<?php //抽象類 abstract class Person { protected $name = 'Wang'; public function getName() { return $this->name; } //抽象方法 abstract protected function run($key, $value); } //子類 class Man extends Person { //實現抽象方法 public function run($key,$value) { return '運行...'.$key.$value; } } $m1 = new Man(); echo $m1 ->run(1,'Wang'); echo $m1->getName();
返回值:
運行...1WangWang
8.爲什麼要設計抽象方法這種只提供方法名和參數的機制呢?這就是面向對象的一種思惟,頂層設計出相應的規範,而後底層子類按照這個規範進行實現。能夠提高代碼的可讀性、維護擴展性和協做性。
9.固然,抽象類不僅僅能夠提供規範讓子類實現,也能夠本身實現讓子類繼承直接使用,很是的靈活。
面向對象中的接口
interface接口的使用
1.接口有兩種概念:第一種是表示提供對外服務的出口,好比不少網站提供的API開發接口,支付寶、QQ登陸等等。而第二種是PHP的一個關鍵字語法:interface接口。
2.接口和抽象類很像,接口定義一條規範,總裁把各類標準計劃設計好,讓底層員工去具體實現。
3.接口比抽象類作的更加完全,它規定了全部方法都是抽象方法,只聲明不實現。而且不須要在前面加上abstract。
4.接口的抽象方法,修飾符必須是 public,其它修飾符直接報錯。
5.子類實現接口(相似繼承),必須重寫接口的抽象方法。
<?php //接口 interface Person { //抽象方法(作一個規範) public function run(); } //子類實現接口 class Man implements Person { //強制性實現抽象方法 public function run() { echo '運行...'; } } $m1 = new Man(); $m1->run();
返回:
運行...
6.接口不能設置屬性,只能設置常量
常量使用調用:
<?php class Person { const PI = 3.14; } echo Person::PI;
打印:
3.14
子類實現接口調用:
<?php //接口 interface Person { const PI = 3.14; //抽象方法 public function run(); } //echo Person::PI; //子類實現接口 class Man implements Person { //實現父類接口的抽象方法 public function run() { } } echo Man::PI;
返回:
3.14
7.子類能夠實現多個接口。
<?php //接口1 interface Person { //抽象方法 public function run(); } //接口2 interface Computer { //抽象方法 public function sleep(); } //子類實現兩個接口 class Man implements Person,Computer { public function run() { } public function sleep() { } }
//接口能夠多實現,繼承只能單繼承
面向對象中的多姿態
1.用術語來講明多態性,就是經過多種狀態或階段描述相同對象的編程方法。它的意義在於,實際開發中,咱們只要關心接口或父類編程,並不須要關心一個對象所屬於的具體類。
<?php //人抽象類(父類) abstract class Person { //作兩個規範聲明 abstract protected function type(); abstract protected function content(); } //理髮師類(子類1) class Barber extends Person { public function type() { return '理髮師'; } //content要操做的內容 public function content() { return '修理頭髮'; } } //園丁類(子類2) class Gardener extends Person { public function type() { return '園丁'; } public function content() { return '整理花卉'; } } //總裁類(子類3) class President extends Person { public function type() { return '總裁'; } public function content() { return '裁人'; } } //剪刀類(行爲類) class Cut { //這裏的run須要傳遞一個參數 //傳遞一我的的對象,好比園丁對象或理髮師對象 //能夠寫$object表示一個對象,可是用$person更具有語義 //由於我不知道是園丁仍是理髮師,仍是總裁,可是他們都是人,那麼用$person更加合理 public function run($person) { return $person->type().'正在'.$person->content().'中...'; } } //實例化三我的(理髮師,園丁,總裁)的對象 $b = new Barber(); $g = new Gardener(); $p = new President(); //實例化行爲對象 $cut = new Cut(); //這裏傳對象,就是根據不一樣的對象,去執行相同的方法,最終致使多態性 echo $cut->run($p);
傳的總裁$p這個對象返回:
總裁正在裁人中...
7.從上面的例子看出,多態就是同一類對象在運行時的具體化。不一樣的人物對象做爲參數傳入剪類,就會調用傳入類的方法。
8.而抽象父類,規定了這些人物類必須實現一樣的方法名,爲多態實現了可能。
9.其實,多態的本質仍是條件判斷語句。
類和對象的檢測機制
類和對象的檢測機制,這種機制可讓程序檢測對象的特性,包括對象名稱、
類的檢測
1.使用 class_exists()函數來肯定一個類是否存在。
//判斷 Person 類是否存在
echo class_exists('Person');
2.使用 get_declared_classes()函數返回目前可用類的數組列表,使用var_dump沒法全面打印。
//輸出可用類列表
var_dump(get_declared_classes());
3.使用 get_class_methods()函數返回類中全部的方法,包括繼承下來的。
//輸出類中的方法
var_dump(get_class_methods('Person'));
4.使用 get_class_vars()函數返回類中全部的屬性,包括繼承下來的。
//輸出類中的屬性
var_dump(get_class_vars('Person'));
<?php //類 class Person { public $name = 'Mr.Wang'; public function run() { return '運行...'; } } $p1 = new Person(); echo class_exists('Person'); var_dump(get_declared_classes()); var_dump(get_class_methods('Person')); var_dump(get_class_vars('Person'));
注意:不對外的方法和屬性獲取不到。
對象檢測
1.使用 get_class()函數來獲取對象所屬的類。
//獲取對象所屬的類
echo get_class($p1);
2.使用 method_exists()函數來判斷對象的某個方法是否存在。
//判斷對象的某個方法是否存在
echo method_exists($p1, 'run');
3.使用 get_object_vars()函數來獲取對象中的屬性列表。
//經過對象參數返回屬性了列表
var_dump(get_object_vars($p1));
4.使用 get_parent_class()函數來獲取父類的名稱。
//返回父類的名稱,傳參能夠是類名或對象名
echo get_parent_class('Person');
<?php //父類 class A { } //類 class Person extends A { public $name = 'Mr.Wang'; public function run() { return '運行...'; } } $p1 = new Person(); echo get_class($p1); echo method_exists($p1, 'run'); var_dump(get_object_vars($p1)); echo get_parent_class('Person');
打印:
Person1
array (size=1)
'name' => string 'Mr.Wang' (length=7)
A
檢查自省的反射API,是一種對類和對象的自查機制(只不過是面向對象方式的)
使用反射
1.建立一個基本的類,包含了屬性和方法
2.建立一個獲取對象的反射類。
3.獲取屬性列表和方法列表。
<?php //建立一個基本的類 class Person { private $name; private $age; public function __set($name, $value) { $this->$name = $value; } public function __get($name) { return $this->$name; } } //實例化 $p = new Person(); //聲明一個經過傳遞對象參數的反射類,這個類是系統內部類 $r = new ReflectionObject($p); //屬性列表 foreach ($r->getProperties() as $value) { var_dump($value); } //方法列表 foreach ($r->getMethods() as $value) { var_dump($value); }
打印結果:
//打印屬性列表
object(ReflectionProperty)[3]
public 'name' => string 'name' (length=4)
public 'class' => string 'Person' (length=6)
object(ReflectionProperty)[4]
public 'name' => string 'age' (length=3)
public 'class' => string 'Person' (length=6)
//打印方法列表
object(ReflectionMethod)[3]
public 'name' => string '__set' (length=5)
public 'class' => string 'Person' (length=6)
object(ReflectionMethod)[5]
public 'name' => string '__get' (length=5)
public 'class' => string 'Person' (length=6)
4.使用傳遞類名方式的反射類。
<?php //建立一個基本的類 class Person { private $name; private $age; public function __set($name, $value) { $this->$name = $value; } public function __get($name) { return $this->$name; } } $r = new ReflectionClass('Person'); //獲取屬性列表 foreach ($r->getProperties() as $value) { var_dump($value); } //獲取方法列表 foreach ($r->getMethods() as $value) { var_dump($value); }
打印:
//獲取屬性列表
object(ReflectionProperty)[2]
public 'name' => string 'name' (length=4)
public 'class' => string 'Person' (length=6)
object(ReflectionProperty)[3]
public 'name' => string 'age' (length=3)
public 'class' => string 'Person' (length=6)
//獲取方法列表
object(ReflectionMethod)[2]
public 'name' => string '__set' (length=5)
public 'class' => string 'Person' (length=6)
object(ReflectionMethod)[4]
public 'name' => string '__get' (length=5)
public 'class' => string 'Person' (length=6)
反射的做用
1.反射能夠用於生成類或對象的文檔,提供開發者閱讀;
2.可使用反射功能開發出各類插件系統,由於這種類型的系統老是要檢測;
3.不少框架使用反射的特性動態的加載須要的類,判斷方法等。
命名空間對類進行分裝
命名空間概念
1.命名空間是一種封裝事物的方法,就好像系統中的文件夾系統,若是文件名相同,能夠存放在不一樣的文件夾以免衝突。
2.命名空間就是爲了防止類與類之間可能產生的衝突,而制定的這套機制。
3.還能夠防止命名空間和PHP系統的類等發生衝突。
4.防止那些爲了緩解衝突,聲明很長的類名,提升可讀性。
5.命名空間不必定非要和目錄結構的名稱同樣,但同樣的話,可讀性會高。
定義命名空間
1.首先在第一個文件設置一個帶有命名空間的類文件。
1.php
<?php //設置命名空間(虛擬目錄App) namespace App; class Person { public function run() { return '1運行...'; } }
2.建立第二個文件2.php,引入1.php時,實例化Person。
2.php
<?php require '1.php'; require '3.php'; $p1 = new \App\Person(); echo $p1->run(); $p2 = new \Home\Person(); echo $p2->run();
3.若是在3.php 中再建立一個Person類,只要命名空間不一樣,就不會衝突了。
3.php
<?php //設置命名空間(虛擬目錄Home) namespace Home; class Person { public function run() { return '3運行...'; } }
4.不一樣命名空間的同名類,不會產生衝突。
//不衝突
$p1 = new \App\Person();
$p2 = new \Home\Person();
運行http://192.168.3.62/xiangmu3/2.php
1運行...3運行...
5.若是說,自己創建了命名空間機制,但並無重名類的問題,可使用use語法。
4.php
<?php require '1.php'; require '3.php'; use App\Person; $p1 = new Person(); echo $p1->run();
運行http://192.168.3.62/xiangmu3/4.php
1運行...
6.若是有重名的,就不適合使用 use 語法了。
7.也能夠像文件系統那樣定義多個子命名空間,讓層次結構更加細化。
1.php
<?php //設置命名空間(虛擬目錄) namespace App\Bev\Org; class Person { public function run() { return '1運行...'; } }
5.php
<?php require '1.php'; use App\Bev\Org\Person; //$p1 = new \App\Bev\Org\Person(); $p1 = new Person(); echo $p1->run();
運行http://192.168.3.62/xiangmu3/5.php
1運行...
8.使用__METHOD__常量能夠獲取方法的所有路徑。
9.使用__FUNCTION__常量能夠獲得單純的方法名
10.能夠在有命名空間的文件下使用__NAMESPACE__常量獲取命名空間路徑。
1.php
<?php //設置命名空間(虛擬目錄) namespace App\Bev\Org; class Person { public function run() { return '1運行...'.__METHOD__.__FUNCTION__.__NAMESPACE__; } }
5.php
<?php require '1.php'; use App\Bev\Org\Person; //$p1 = new \App\Bev\Org\Person(); $p1 = new Person(); echo $p1->run();
運行http://192.168.3.62/xiangmu3/5.php
分別獲得的返回值是:
1運行...
App\Bev\Org\Person::run
run
App\Bev\Org
11.使用use別名來簡化重名類的衝突問題。
1.php
<?php //設置命名空間(虛擬目錄) namespace App\Bev\Org; class Person { public function run() { return '1運行...'.__METHOD__.__FUNCTION__; } }
3.php
<?php //設置命名空間 namespace Home\Go\Back; class Person { public function run() { return '3運行...'; } }
7.php
<?php require '1.php'; require '3.php'; use App\Bev\Org\Person as One; use Home\Go\Back\Person as Two; $p1 = new One(); echo $p1->run(); $p2 = new Two(); echo $p2->run();
http://192.168.3.62/xiangmu3/7.php
1運行...App\Bev\Org\Person::runrun3運行...
異常類
異常的概念
1.異常就是在可能發生錯誤的代碼區域使用異常語法包裹住,當程序代碼發生可能出現的錯誤,及時拋出異常的一種策略。
2.異常通常來講須要如下四個步驟實現:
(1)程序嘗試執行一些代碼;
(2)若是執行失敗,則拋出一個異常;
(3)捕獲該異常;
(4)清理執行出現異常代碼而遺留的資源。
使用異常類
1.PHP 中內置一個基本的異常類(Exception),基本的異常類用於在腳本發生異常時創建異常對象,該對象能夠存儲、拋出和捕獲異常信息。
2.能夠先執行一個會產生錯誤的代碼。
若是被除數爲0的話返回被除數不能爲零!
<?php $a = 5; $b = 0; if ($b == 0) { exit('被除數不能爲零!'); } else { echo $a / $b; }
返回值:
被除數不能爲零!
3.若是使用異常方式,須要使用try catch語法。throw 是手動拋出異常,若是PHP有相關處理此異常的異常類,就會自動拋出,而不須要判斷。
<?php $a = 5; $b = 0; try { //throw new Exception手動拋出異常 if ($b == 0) throw new Exception(); //這句話可能會有錯誤 echo $a / $b; } catch (Exception $e) { echo '被除數不得爲零!'; }
返回值:
被除數不得爲零!
4.錯誤提示能夠經過構造傳參傳遞。
//經過構造傳參拋出錯誤信息
<?php $a = 5; $b = 0; try { //手動拋出異常 if ($b == 0) throw new Exception('被除數不得爲零'); //這句話可能會有錯誤 echo $a / $b; } catch (Exception $e) { echo $e->getMessage(); }
返回值:
被除數不得爲零
5.異常類有不少方法能夠調用。
(1).getMessage():返回傳遞給構造方法的信息;
(2).getCode():返回傳遞給構造方法的代碼;
(3).getFile():返回產生異常代碼文件的完整路徑;
(4).getLine():返回代碼文件中產生代碼的行號;
(5).getTrace():返回一個包含產生異常代碼回退路徑的數組;
<?php $a = 5; $b = 0; try { //手動拋出異常 if ($b == 0) throw new Exception('被除數不得爲零'); //這句話可能會有錯誤 echo $a / $b; } catch (Exception $e) { echo $e->getMessage(); echo $e->getCode(); echo $e->getLine(); echo $e->getFile(); }
返回值:.getMessage():被除數不得爲零.getCode():0.getLine():8.getFile():E:\Program\www\xiangmu3\1.php