談談我對php中面向物件的理解
轉載自:http://www.php.cn/php-weizijiaocheng-372376.html
今天來和大家介紹一下PHP的面向物件。說到面向物件,我不得不提一下面向過程,因為本人在初學時,常常分不清楚面向物件和麵向過程,
面向物件程式設計(OOP)是我們程式設計的一項基本技能,PHP5對OOP提供了良好的支援。如何使用OOP的思想來進行PHP的高階程式設計,對於提高PHP程式設計能力和規劃好Web開發構架都是非常有意義的。下面我們就通過例項來說明使用PHP的OOP進行程式設計的實際意義和應用方法。
我們通常在做一個有資料庫後臺的網站的時候,都會考慮到程式需要適用於不同的應用環境。和其他程式語言有所不同的是,在PHP中,操作資料庫的是一系列的具體功能函式(如果你不使用ODBC介面的話)。這樣做雖然效率很高,但是封裝卻不夠。如果有一個統一的資料庫介面,那麼我們就可以不對程式做任何修改而適用於多種資料庫,從而使程式的移植性和跨平臺能力都大大提高。
下面就來給大家介紹一下它們的區別:
面向物件專注於由哪個物件來處理一個問題。
其最大特點是由一個一個具有屬性和功能的類,從類中拿到物件,進而處理問題。
面向過程專注於解決一個問題的過程。其最大特點是由一個一個的函式去解決處理這個問題的一系列過程。
一、面向物件基礎 |
一面向物件
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進行私有化處理。
1 | 1 private function formatName(){} //這個方法僅僅能在類內部使用$this呼叫2 function showName(){3 $this -> formatName();4 } |
②屬性的封裝+set/get方法
為了控制屬性的設定以及讀取,可以將屬性進行私有化處理,並要求使用者通過我們提供的set/get方法進行設定
1 | 1 private $age ;2 //set方法3 function setAge($age){4 $this->age=$age;5 }6 //get方法7 function getAge(){8 return $this->age;9 } |
$物件->getAge();
$物件->setAge(12);
③屬性的封裝+魔術方法
1 | __get( -> __set(, ->= } |
$物件->age; //訪問物件私有屬性時,自動呼叫__get()魔術方法,並且將訪問的屬性名傳給__get()方法;
$物件->age=12; //設定物件私有屬性時,自動呼叫__set()魔術方法,並且將設定的屬性名以及屬性值傳給__set()方法;
注意:在魔術方法中,可以使用分支結構,判斷$key的不同,進行不同操作。
4、關於封裝的魔術方法:
①__set($key,$value):給類私有屬性賦值時自動呼叫,呼叫時給方法傳遞兩個引數:需要設定的屬性名,屬性值。
②__get($key,$value):讀取類私有屬性時自動呼叫,呼叫時給方法傳遞一個引數,需要讀取的屬性名;
③__isset($key):外部使用isset()函式檢測私有屬性時,自動呼叫。
>>>類外部使用isset();檢測私有屬性,預設是檢測不到的。false
>>>所以,我們可以使用__isset();函式,在自動呼叫時,返回內部檢測結果。
1 | 1 function __isset( $key ){2 return isset( $this -> $key );3 } |
當外部使用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::方法名();
所以,當子類繼承父類時,需在子類的構造中的第一步,首先呼叫父類構造進行復制。
1 | 1 function __construct( $name , $sex , $school ){2 partent::__construct( $name , $sex );3 $this -> school = $school ;4 } |
三、PHP關鍵字 |
1、final
①final修飾類,此類為最終類,不能被繼承!
②final修飾方法,此方法為最終方法,不能被重寫!
③final不能修飾屬性。
2、static
①可以修飾屬性和方法,分別稱為靜態屬性和靜態方法,也叫類屬性,類方法;
②靜態屬性,靜態方法,只能使用類名直接呼叫。
使用"類名::$靜態屬性" , "類名::靜態方法()"
Person::$sex; Person::say();
③靜態屬性和方法,在類裝載時就會宣告,先於物件產生。
④靜態方法中,不能呼叫非靜態屬性或方法;
非靜態方法,可以呼叫靜態屬性和方法。
(因為靜態屬性和方法在類裝載時已經產生,而非靜態的屬性方法,此時還沒有例項化誕生)
⑤在類中,可以使用self關鍵字,代指本類名。
1 | 1 class Person{2 static $sex = "nan" ;3 function say(){4 echo self:: $sex ;5 }6 } |
⑥靜態屬性是共享的,也就是new出很多物件,也是共用一個屬性。
3、const關鍵字:
在類中宣告常量,不能是define()函式!必須使用const關鍵字。
與define()宣告相似,const關鍵字宣告常量不能帶$,必須全部大寫!
常量一旦宣告,不能改變。呼叫時與static一樣,使用類名呼叫Person::常量。
4、instanceof操作符:
檢測一個物件,是否是某一個類的例項。(包括爹輩,爺爺輩,太爺爺輩……)
1 | $zhangsan instanceof Person; |
【小總結】幾種特殊操作符:
① . 只能連線字串; "".""
② => 宣告陣列時,關聯鍵與值["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()函式返回的字串;
1 | 1 function __toString(){2 return "haha" ;3 }4 echo $zhangsan ; //結果為:haha |
5、__call()
呼叫類中未定義或未公開的方法時,會自動執行__call()方法。
自動執行時,會給__call()方法傳遞兩個引數;
引數一:呼叫的方法名
引數二:(陣列)呼叫方法的引數列表。
二__antoload()
①這是唯一一個不在類中使用的魔術方法;
②當例項化一個不存在的類時,自動呼叫這個魔術方法;
③呼叫時,會自動給__autoload()傳遞一個引數:例項化的類名
所以可以使用這個方法實現自動載入檔案的功能。
1 | 1 function __autoload( $className ){2 include "class/" . strtolower ( $className ). ".class.php" ;3 }4
|