1.理解面向對象的概念php
面向對象軟件的一個重要優勢是支持和鼓勵封裝的能力。封裝也叫數據隱藏。web
在面向對象的軟件中,對象是一個被保存數據和操做這些數據的操做方法的惟1、可標識的集合。編程
對象能夠按類進行分類。編程語言
面向對象的編程語言必須支持多態性,多態性的意思是指不一樣的類對同一操做能夠有不一樣的行爲。語言支持多態性,能夠知道將哪一個操做應用於一個特定的對象。函數
多態性與其說是對象的特性,不如說是行爲的特性。在PHP中,只有類的成員函數能夠是多態的。this
例如,儘管自行車的「移動」和汽車的「移動」在概念上是類似的,可是移動一輛自行車和移動一輛汽車所包含的行爲是徹底不一樣的。一旦行爲做用的對象肯定下來,動詞「移動」就能夠和一系列特定的行爲聯繫起來。spa
繼承容許咱們使用子類在類之間建立層次關係。子類將從它的超類繼承屬性和操做。3d
2.在PHP中建立類、屬性和操做指針
當建立一個PHP類的時候,必須使用關鍵詞「class」。code
2.1 類的結構
以下所示代碼建立了一個名爲「classname」的類,它具備兩個屬性$attribute1和$attribute2:
class classname{ public $attribute1; public $attribute2; }
經過在類定義中聲明函數,能夠建立類的操做。
class classname{ function operation1() { } function operation2($param1,$param2) { } }
2.2 構造函數
大多數類都有一種稱爲構造函數的特殊操做。當建立一個對象時,它將調用構造函數,一般,這將執行一些有用的初始化任務:例如,設置屬性的初始值或者建立該對象須要的其餘對象。
構造函數其名稱必須是__construct()。這是PHP5中的變化。儘管能夠手工調用構造函數,但其本意是在建立一個對象時自動調用。聲明一個具備構造函數的類:
class classname{ function __construct($param){ echo 「Constructor called with parameter 」.$param.」<br />」; } }
PHP支持函數重載,這就意味着能夠提供多個具備相同名稱以及不一樣數量或類型的參數的函數。
2.3 析構函數
與構造函數相對的是析構函數。析構函數容許在銷燬一個類以前執行一些操做或完成一些功能,這些操做或功能一般在全部對該類的引用都被重置或超出做用域時自動發生。
與構造函數的名稱相似,一個類的析構函數名稱必須是__destruct()。析構函數不能帶有任何參數。
3.類的實例化
在聲明一個類後,須要建立一個對象(一個特定的個體,即類的一個成員)並使用這個對象。這也叫建立一個實例或實例化一個類。可使用關鍵詞「new」來建立一個對象。須要指定建立的對象是哪個類的實例,而且經過構造函數提供任何所需的參數。
以下所示的代碼聲明瞭一個具備構造函數、名爲classname的類,而後又建立3個classname類型的對象。
class classname{ function _construct($param){ echo 「Constructor called with parameter 」.$param.」<br />」; } } $a = new classname(「First」); $b = new classname(「Second」); $c = new classname();
運行發現如下報錯:
$c的參數補上:
class classname{ function __construct($param){ echo "Constructor called with parameter ".$param."<br />"; } } $a = new classname("First"); $b = new classname("Second"); $c = new classname("");
4.使用類的屬性
在一個類中,能夠訪問一個特殊的指針——$this。若是當前類的一個屬性爲$attribute,則當在該類中經過一個操做設置或訪問該變量時,可使用$this->attribute來引用。
以下所示的代碼說明了如何在一個類中設置和訪問屬性:
class classname{ public $attribute; function operation($param){ $this->attribute = $param; echo $this->attribute; } }
是否能夠在類的外部訪問一個屬性是由訪問修飾符來肯定的。
一般,從類的外部直接訪問類的屬性是糟糕的想法。面向對象方法的一個優勢就是鼓勵使用封裝。能夠經過使用__get()和__set()函數來實現對屬性的訪問。
若是不直接訪問一個類的屬性而是編寫訪問函數,那麼能夠經過一段代碼執行全部訪問。當最初編寫訪問函數時,訪問函數可能以下所示:
class classname{ public $attribute; function __get($name){ return $this->$name; } function __set($name,$value){ $this->$name = $value; } }
以上代碼爲訪問$attribute屬性提供了最基本的功能。__get()函數返回了$attribute的值,而__set()函數只是設置了$attribute的值。
注意,__get()函數帶有一個參數(屬性的名稱)而且返回該屬性的值。__set()函數須要兩個參數,分別是:要被設置值的屬性名稱和要被設置的值。
咱們並不會直接訪問這些函數。這些函數名稱前面的雙下劃線代表在PHP中這些函數具備特殊的意義,就像__construct()函數和__destruct()函數同樣。
這些函數的工做原理是怎樣的?若是實例化一個類:
$a = new classname();
能夠用__get()函數和__set()函數來檢查和設置任何屬性的值。
若是使用以下命令:
$a -> $attribute = 5;
該語句將間接調用__set()函數,將$name參數的值設置爲「attribute」,而$value的值被設置爲5。必須編寫__set()函數來完成任何所需的錯誤檢查。
__get()函數的工做原理相似。若是在代碼中引用:
$a -> attribute;
該語句將間接調用__get()函數,$name參數的值爲「attribute」。咱們能夠本身決定編寫__get()函數來返回屬性值。
咱們只使用一段代碼來訪問特定的屬性。只有一個訪問入口,就能夠實現對要保存的數據進行檢查,這樣就能夠確保被保存的數據是有意義的數據。
若是後來發現$attribute屬性值應該是0到100之間,咱們就能夠添加幾行代碼,在屬性值改變以前進行檢查:
function _set($name, $value){ if(($name=」attribute」)&&($value>=0)&&($value<=100)) $this->attribute = $value; }
經過單一的訪問入口,能夠方便地改變潛在的程序實現。
不管須要作什麼樣的改變,只要修改訪問器函數便可。只要保證這個訪問器函數仍然接收並返回程序的其餘部分指望的數據類型,那麼程序的其餘部分代碼就不會受影響。
5.使用private和public關鍵字控制訪問
PHP支持以下3種訪問修飾符:
· 默認選項是public。公有的屬性或方法能夠在類的內部和外部進行訪問。
· private訪問修飾符意味着被標記的屬性或方法只能在類的內部進行訪問。
· protected能夠理解成位於private和public之間的關鍵字,後面會詳細探討。
6.類操做的調用
與調用屬性大致上相同,可使用一樣的方式調用類的操做。
若是有以下類:
class classname{ function operation1() { } function operation2($param1,param2) { } }
而且建立了一個類型爲classname、名稱爲$a的對象,以下所示:
$a = new classname();
能夠像調用其餘函數同樣調用操做:經過使用其名稱以及將全部所需的參數放置在括號中。由於這些操做屬於一個對象而不是常規的函數,因此須要指定它們所屬的對象。對象名稱的使用方法與對象屬性同樣,以下所示:
$a -> operation1(); $a -> operation2(12,」test」);
若是操做具備返回值,能夠捕獲到以下所示的返回數據:
$x = $a->operation1(); $y = $a->operation2(12,」test」);
7.在PHP中實現繼承
繼承是單方向的。子類能夠從父類或超類繼承特性,父類缺不能從子類繼承特性。
7.1 經過繼承使用private和protected訪問修飾符控制可見性
可使用private和protected訪問修飾符來控制須要繼承的內容。 若是一個屬性或方法被指定爲private,它將不能被繼承。
若是一個屬性或方法被指定爲protected,它將在類外部不可見(就像一個private元素),可是能夠被繼承。
考慮以下實例:
<?php class A{ private function operation1(){ echo "operation1 called"; } protected function operation2(){ echo "operation2 called"; } public function operation3(){ echo "operation3 called"; } } class B extends A{ function __construct(){ $this->operation1(); $this->operation2(); $this->operation3(); } } $b = new B; ?>
$this->operation1();這句將產生報錯:
說明私有操做不能在子類中調用。
若是註釋掉這一行,其餘兩個函數調用將正常工做。
protected函數能夠被繼承可是隻能在子類內部使用。若是嘗試在該文件結束處添加以下所示的代碼:
$b->operation2();
將產生以下報錯:
7.2 重載
在子類中,再次聲明相同的屬性和操做也是有效的,並且在有些狀況下這將會是很是有用的。咱們可能須要在子類中給某個屬性賦予一個與其超類屬性不一樣的默認值,或者給某個操做賦予一個與其超類操做不一樣的功能。這就叫重載。
例如,若是有類A:
class A{ public $attribute = "default value"; function operation(){ echo "Something<br />"; echo "The value of \$attribute is ".$this->attribute."<br />"; } }
如今,若是須要改變$attribute的默認值,併爲operation()操做提供新的功能,能夠建立類B,它重載了$attribute和operation()方法,以下所示:
class B extends A{ public $attribute = "different value"; function operation(){ echo "Something else<br />"; echo "The value of \$attribute is ".$this->attribute."<br />"; } }
聲明類B並不會影響類A的初始定義:
$a = new A(); $a -> operation();
這兩行代碼建立了類A的一個對象而且調用了它的operation()函數:
注意$this->後的變量不帶$符。
若是建立了類B的一個對象:
$b = new B(); $b -> operation();
與子類中定義新的屬性和操做並不影響超類同樣,在子類中重載屬性或操做也不會影響超類。
若是不使用替代,一個子類將繼承超類的全部屬性和操做。若是子類提供了替代定義,替代定義將有優先級而且重載初始定義。
parent關鍵字容許調用父類操做的最第一版本。例如,要從類B中調用A::operation,可使用以下所示的語句:
parent::operation();
可是,其輸出結果倒是不一樣的。雖然調用了父類的操做,可是PHP將使用當前類的屬性值。
源碼:
<?php class A { public $attribute = "default value"; function operation() { echo "Something<br />"; echo "The value of \$attribute is ".$this->attribute."<br />"; } } class B extends A { public $attribute = "different value"; function operation() { echo "Something else<br />"; echo "The value of \$attribute is ".$this->attribute."<br />"; } function Aoperation() { parent::operation(); } } $a = new A(); $a->operation(); $b = new B(); $b->Aoperation(); ?>
繼承能夠是多重的。能夠聲明一個類C,它繼承了類B,所以繼承了類B和類B父類的全部特性。類C還能夠選擇重載和替換父類的那些屬性和操做。
7.3 使用final關鍵字禁止繼承和重載
當在一個函數聲明前面使用final關鍵字時,這個函數將不能被任何子類中被重載。也可使用final關鍵字來禁止一個類被繼承。
7.4 PHP不支持多重繼承
如題,每一個類只能繼承一個父類。一個父類能夠有多少個子類則並無限制。
7.5 實現接口
若是須要實現多重繼承功能,在PHP中,能夠經過接口。接口能夠看做是多重繼承問題的解決方法。
接口的思想是指定一個實現了該接口的類必須實現的一系列函數。例如,須要一系列可以顯示自身的類。除了能夠定義具備display()函數的父類,同時使這些子類都繼承該父類並重載該方法外,還能夠實現一個接口:
interface Displayable{ function display(); } class webPage implements Displayable{ function display(){ // ... } }
以上代碼示例說明了多重繼承的一種解決辦法,由於webPage類能夠繼承一個類,同時又能夠實現一個或多個接口。
若是沒有實現接口中指定的方法,將產生一個致命錯誤。
整理自《PHP和MySQL Web》開發