php中面向對象
一、面向對象基礎
一面向對象
1、什麽是類?
具有相同屬性(特征)和方法(行為)的一系列個體的集合,類是一個抽象的概念。
2、什麽是對象?
從類中,拿到的具有具體屬性值的個體,稱為對象。對象是一個具體的個體。
eg:人類;張三
3、類和對象的關系?
類是對象的抽象化!對象是類的具體化!
類僅僅表明這類對象有哪些屬性,但是不能有具體的值,所以類是抽象的。
對象是將類的所有屬性賦值後,產生具體的個體,所有對象是具體的。
二類的聲明與實例化
1、如何聲明一個類:
class 類名{
訪問修飾符 $屬性[=默認值];
[訪問修飾符] function 方法(){}
}
2、聲明一個類的註意事項:
①類名只能有字母數字下劃線組成,開頭不能是數字,必須符合大駝峰法則;
②類名必須使用class修飾,類名後面一定不能有();
③屬性必須要帶訪問修飾符,方法可以不帶訪問修飾符。
3、實例化對象及對象屬性方法的調用:
$對象名 = new 類名(); //()可以不帶
類外部調用屬性和方法:
$對象名 -> $屬性名; //使用->調用屬性時,屬性名不能帶$符號
類內部調用屬性和方法:
$this -> $屬性名;
三構造函數
1、什麽是構造函數?
構造函數是類中的一個特殊函數,當我們使用new關鍵字實例化對象時,相當於調用了類的構造函數。
2、構造函數有什麽作用?
實例化對象時,自動調用,用於給對象的屬性賦初值!
3、構造函數的寫法:
①構造函數名,必須與類同名
[public] function Person($name){
$this -> name = $name;
}
②使用魔術方法__construct
[public] function __construct($name){
$this -> name = $name;
}
4、構造函數註意事項:
①第一種寫法,構造函數名必須與類同名!!!!
②如果一個類沒有手寫構造函數,則系統默認會有一個空參構造,因此可以使用new Person();
如果我們寫了帶參數的構造函數,則將不會再有空參構造,也就是不能直接使用new Person();
Person後面的()中的參數列表,必須符合構造函數的要求!!!!
③如果兩種構造函數同時存在,將使用__construct。
5、析構函數:__destruct():
①析構函數在對象被銷毀釋放之前自動調用;
②析構函數不能帶有任何的參數;
③析構函數常用於對象使用完以後,釋放資源,關閉資源等。
6、魔術方法:
PHP中,給我們提供一系列用__開頭的函數,這些函數無需自己手動調用,
會在合適的時機自動調用,這類函數稱為魔術稱為魔術函數。
eg:function __construct(){} 在類new一個對象時自動調用
function __destruct(){} 在對象被銷毀時自動調用
我們要求,除了魔術方法之外,自定義的函數與方法不能使用__開頭。
最後,一般對於功能比較復雜的類,我們會單獨的寫到一個類文件中。
類文件的命名,同一小寫,使用"類名小寫.class.php"的方式命名。
在其他文件中使用這個類時,可以使用include導入這個".class.php"文件。
二、封裝和繼承
1、什麽是封裝?
通過訪問修飾符,將類中不需要外部訪問的屬性和方法進行私有化處理,以實現訪問控制。
*註意:是實現訪問控制,而不是拒絕訪問。也就是說,我們私有化屬性後,需要提供對應的方法,讓用戶通過我們提供的方法處理屬性。
2、封裝的作用?
①使用者只關心類能夠提供的功能,不關心功能實現的細節!(封裝方法)
②對用戶的數據進行控制,防止設置不合法數據,控制返回給用戶的數據(屬性封裝+set/get方法)
3、實現封裝操作?
①方法的封裝
對於一些只在類內部使用的方法,而不像對外部提供使用,那麽,這樣的方法我們可以使用private進行私有化處理。
|
②屬性的封裝+set/get方法
為了控制屬性的設置以及讀取,可以將屬性進行私有化處理,並要求用戶通過我們提供的set/get方法進行設置
|
$對象->getAge();
$對象->setAge(12);
③屬性的封裝+魔術方法
|
$對象->age; //訪問對象私有屬性時,自動調用__get()魔術方法,並且將訪問的屬性名傳給__get()方法;
$對象->age=12; //設置對象私有屬性時,自動調用__set()魔術方法,並且將設置的屬性名以及屬性值傳給__set()方法;
註意:在魔術方法中,可以使用分支結構,判斷$key的不同,進行不同操作。
4、關於封裝的魔術方法:
①__set($key,$value):給類私有屬性賦值時自動調用,調用時給方法傳遞兩個參數:需要設置的屬性名,屬性值。
②__get($key,$value):讀取類私有屬性時自動調用,調用時給方法傳遞一個參數,需要讀取的屬性名;
③__isset($key):外部使用isset()函數檢測私有屬性時,自動調用。
>>>類外部使用isset();檢測私有屬性,默認是檢測不到的。false
>>>所以,我們可以使用__isset();函數,在自動調用時,返回內部檢測結果。
|
當外部使用isset($對象名->私有屬性);檢測時,將自動調用上述__isset()返回的結果!
④__unset($key):外部使用unset()函數刪除私有屬性時,自動調用;
1 function __unset($key){ 2 unset($this -> $key); 3 }
當外部使用unset($對象名->私有屬性);刪除屬性時,自動將屬性名傳給__unset(),並交由這個魔術方法處理。
繼承的基礎知識:
1、如何實現繼承?
給子類使用extends關鍵字,讓子類繼承父類;
class Student extends Person{}
2、實現繼承的註意事項?
①子類只能繼承父類的非私有屬性。
②子類繼承父類後,相當於將父類的屬性和方法copy到子類,可以直接使用$this調用。
③PHP只能單繼承,不支持一個類繼承多個類。但是一個類進行多層繼承。
class Person{}
class Adult extends Person{}
class Student extends Adult{}
//Student 類就同時具有了Adult類和Person類的屬性和方法
3、方法覆蓋(方法重寫)
條件一: 子類繼承父類
條件二:子類重寫父類已有方法
符合上述兩個條件,稱為方法覆蓋。覆蓋之後,子類調用方法,將調用子類自己的方法。
同樣,除了方法覆蓋,子類也可以具有與父類同名的屬性,進行屬性覆蓋。
如果,子類重寫了父類方法,如何在子類中調用父類同名方法?
partent::方法名();
所以,當子類繼承父類時,需在子類的構造中的第一步,首先調用父類構造進行復制。
|
三、PHP關鍵字
1、final
①final修飾類,此類為最終類,不能被繼承!
②final修飾方法,此方法為最終方法,不能被重寫!
③final不能修飾屬性。
2、static
①可以修飾屬性和方法,分別稱為靜態屬性和靜態方法,也叫類屬性,類方法;
②靜態屬性,靜態方法,只能使用類名直接調用。
使用"類名::$靜態屬性" , "類名::靜態方法()"
Person::$sex; Person::say();
③靜態屬性和方法,在類裝載時就會聲明,先於對象產生。
④靜態方法中,不能調用非靜態屬性或方法;
非靜態方法,可以調用靜態屬性和方法。
(因為靜態屬性和方法在類裝載時已經產生,而非靜態的屬性方法,此時還沒有實例化誕生)
⑤在類中,可以使用self關鍵字,代指本類名。
|
⑥靜態屬性是共享的,也就是new出很多對象,也是共用一個屬性。
3、const關鍵字:
在類中聲明常量,不能是define()函數!必須使用const關鍵字。
與define()聲明相似,const關鍵字聲明常量不能帶$,必須全部大寫!
常量一旦聲明,不能改變。調用時與static一樣,使用類名調用Person::常量。
4、instanceof操作符:
檢測一個對象,是否是某一個類的實例。(包括爹輩,爺爺輩,太爺爺輩……)
|
【小總結】幾種特殊操作符:
① . 只能連接字符串; "".""
② => 聲明數組時,關聯鍵與值["key"=>"value"]
③ -> 對象($this new出的對象)調用成員屬性,成員方法;
④ :: ①使用parent關鍵字,調用父類中的同名方法:parent::say();
②使用類名(和self)調用類中的靜態屬性,靜態方法,以及常量。
四、單例
單例模式也叫單態模式。可以保證,一個類只能有一個對象實例。
實現要點:
①構造函數私有化,不允許使用new關鍵字創建對象。
②對外提供獲取對象的方法,在方法中判斷對象是否為空。
如果為空,則創建對象並返回;如果不為空則直接返回。
③實例對象的屬性以及獲取對象的方法必須都是靜態的。
④之後,創建對象只能使用我們提供的靜態方法。
eg:$s1 = Singleton::getSingle();
五、對象串行化和魔術方法
***關鍵詞:clone與__clone、__antoload()、串行化與反串行化(序列化與反序列化)、類型約束、魔術方法小總結(12個)
一clone與__clone
1、當使用=講一個對象,賦值給另一個對象時,賦的實際是對象的地址。
兩個對象指向同一地址,所以一個對象改變,另一個也會變化。
eg: $lisi = $zhangsan;
2、如果想要將一個對象完全克隆出另一個對象,兩個對象是獨立的,互不幹擾的,
則需要使用clone關鍵字;
eg: $lisi = clone $zhangsan; //兩個對象互不幹擾
3、__clone():
①當使用clone關鍵字,克隆對象時,自動調用clone函數。
②__clone()函數,類似於克隆時使用的構造函數,可以給新克隆對象賦初值。
③__clone()函數裏面的$this指的是新克隆的對象
某些版本中,可以用$that代指被克隆對象,絕大多數版本不支持。
4、__toString()
當使用echo等輸出語句,直接打印對象時調用echo $zhangsan;
那麽,可以指定__toString()函數返回的字符串;
|
5、__call()
調用類中未定義或未公開的方法時,會自動執行__call()方法。
自動執行時,會給__call()方法傳遞兩個參數;
參數一:調用的方法名
參數二:(數組)調用方法的參數列表。
二__antoload()
①這是唯一一個不在類中使用的魔術方法;
②當實例化一個不存在的類時,自動調用這個魔術方法;
③調用時,會自動給__autoload()傳遞一個參數:實例化的類名
所以可以使用這個方法實現自動加載文件的功能。
|
三面向對象串行化與反串行化(序列化與反序列化)
1、串行化:將對象通過一系列操作,轉化為一個字符串的過程,稱為串行化。
(對象通過寫出描述自己狀態的數值來記錄自己)
2、反串行化:將串行化後的字符串,再轉為對象的過程,稱為反串行化;
3、什麽時候使用串行化?
①對象需要在網絡中傳輸的時候
② 對象需要在文件或數據庫中持久保存的時候
4、怎樣實現串行化與反串行化
串行化: $str=serialize($zhangsan);
反串行化:$duixiang=unserialize($str);
5、__sleep()魔術方法:
①當執行對象串行化的時候,會自動執行__sleep()函數;
②__sleep()函數要求返回一個數組,數組中的值,就是可以串行化的屬性;不在數組中的屬性,不能被串行化;
function __sleep(){
return array("name","age"); //只有name/age兩個屬性可以串行化。
}
6、__wakeup()魔術方法
①當反串行化對象時,自動調用__wakeup()方法;
②自動調用時,用於給反串行化產生的新對象屬性,進行重新賦值。
1 function __wakeup(){ 2 $this -> name = "李四"; 3 }
四類型約束
1、類型約束:是指在變量時,加上數據類型,用於約束此變量只能存放對應的數據類型。
(這種操作常見於強類型語言,在PHP中,只能實現數組和對象的類型約束)
2、如果類型約束為某一個類,則本類以及本類的子類對象,都可以通過。
3、在PHP中,類型約束,只能發生在函數的形參中。
|
func(new Person()); √
func(new Student()); √
func("111"); ×
形如new Person();的形式,我們稱其為"匿名對象";
※※※基類:父類
※※※派生類:子類
五魔術方法小總結
1、__construct():構造函數,new一個對象時,自動調用。
2、__destruct():析構函數,當一個對象被銷毀前,自動調用。
3、__get():訪問類中私有屬性時,自動調用。傳遞讀取的屬性名,返回$this->屬性名
4、__set():給類的私有屬性賦值時,自動調用。傳遞需要設置的屬性名和屬性值;
5、__isset():使用isset()檢測對象私有屬性時,自動調用。傳遞檢測的屬性名,返回isset($this -> 屬性名);
6、__unset():使用unset()刪除對象私有屬性時,自動調用。傳遞刪除的屬性名,方法中執行unset($this -> 屬性名);
7、__toString():使用echo打印對象時,自動調用。返回想要在打印對象時,顯示的內容;返回必須是字符串;
8、__call():調用一個類中未定義或未公開的方法時,自動調用。傳遞被調用的函數名,和參數列表數組;
9、__clone():當使用clone關鍵字,克隆一個對象時,自動調用。作用是為新克隆的對象進行初始化賦值;
10、__sleep():對象序列化時,自動調用。返回一個數組,數組中的值就是可以序列化的屬性;
11、__wakeup():對象反序列化時,自動調用。為反序列化新產生的對象,進行初始化賦值;
12、__autoload():需要在類外部聲明函數。當實例化一個未聲明的類時,自動調用。傳遞實例化的類名,可以使用類名自動加載對應的類文件。
六、抽象類和抽象方法
1、什麽是抽象方法?
沒有方法體{}的方法,必須使用abstract關鍵字修飾。這樣的方法,我們稱為抽象方法。
abstract function say(); //抽象方法
2、什麽是抽象類?
使用abstract關鍵字修飾的類就是抽象類。
abstract class Person{}
3、抽象類的註意事項:
① 抽象類可以包含非抽象方法;
② 包含抽象方法的類必須是抽象類,抽象類並不一定必須包含抽象方法;
③ 抽象類,不能實例化。(抽象類中可能包含抽象方法,抽象方法沒有方法體,實例化調用沒有意義)
我們使用抽象類的目的,就是限制實例化!!!
4、子類繼承抽象類,那麽子類必須重寫父類的所有抽象方法,除非,子類也是抽象類。
5、使用抽象類的作用?
① 限制實例化。(抽象類是一個不完整的類,裏面的抽象方法沒有方法體,所以不能實例化)
② 抽象類為子類的繼承提供一種規範,子類繼承一個抽象類,則必須包含並且實現抽象類中已定的抽象方法。
七、接口與多態
一接口
1、什麽是接口?
接口是一種規範,提供了一組實現接口的類所必須實現的方法組合。
接口使用interface關鍵字聲明;
interface Inter{}
2、接口中的所有方法,必須都是抽象方法。
接口中的抽象方法不需要也不能使用abstract修飾。
3、接口中不能聲明變量,不能有屬性,只能使用常量!!!
4、接口可以繼承接口,使用extends關鍵字!
接口使用extends繼承接口,可以實現多繼承。
interface int1 extends Inter,Inter2{}
5、類可以實現接口,使用implements關鍵字!
類使用implements實現接口,可同時實現多個接口,多個接口間逗號分隔;
abstract class Person implements Inter,Inter2{}
一個類實現一個或多個接口,那麽這個類,必須實現所有接口中的所有抽象方法!
除非,這個類是抽象類。
【接口&&抽象類區別】:
①聲明方式上,接口使用interface關鍵字,抽象類使用abstract class。
②實現/繼承方式上,一個類使用extends繼承抽象類,使用implements實現接口。
③抽象類只能單繼承,接口可以多實現。(接口extends接口)、多實現(類implements接口)
④抽象類中可以有非抽象方法,接口中只能有抽象方法,不能有費抽象方法。抽象類中的抽象方法必須使用abstract關鍵字修飾,接口中抽象方法不能帶修飾詞。
⑤抽象類是個類,可以有屬性、變量;接口中只能有常量。
二多態
二、多態
1、一個類,被多個子類繼承。
如果,這個類的某個方法,在多個子類中,表現出不同的功能,我們稱這種行為為多態。
2、實現多態的必要途徑:
① 子類繼承父類;
② 子類重寫父類方法;
③ 父類引用指向子類對象
php中面向對象