在本教程中,您將學(xué)習(xí)如何在PHP中以面向?qū)ο蟮姆绞骄帉懘a。
面向?qū)ο缶幊?OOP)是一種基于類和對象概念的編程模型。與過程編程不同,過程編程的重點(diǎn)是編寫對數(shù)據(jù)執(zhí)行操作的過程或函數(shù),而在面向?qū)ο缶幊讨校攸c(diǎn)是創(chuàng)建同時包含數(shù)據(jù)和函數(shù)的對象。
相對于常規(guī)或過程式編程,面向?qū)ο缶幊叹哂卸鄠€優(yōu)勢。最重要的列出如下:
它為程序提供了清晰的模塊化結(jié)構(gòu)。
它可以幫助您遵守“不要重復(fù)自己”(DRY)原則,從而使您的代碼更易于維護(hù),修改和調(diào)試。
它使得可以用更少的代碼,更短的開發(fā)時間和高度的可重用性來創(chuàng)建更復(fù)雜的行為。
以下各節(jié)將描述類和對象在PHP中的工作方式。
提示:以過程編程風(fēng)格編寫的程序,意味著程序由一個或多個過程組成。 而過程是一組一起執(zhí)行特定任務(wù)的編程語句。
提示:“不重復(fù)自己”(Don‘t Repeat Yourself,DRY)原則背后的思想是,通過抽象出應(yīng)用程序常用的代碼并將它們放在單個位置并重用它們而不是重復(fù)它們,從而減少代碼的重復(fù)。
類和對象是面向?qū)ο缶幊痰膬蓚€主要方面。 類是獨(dú)立的變量和函數(shù)集合,它們協(xié)同工作以執(zhí)行一個或多個特定任務(wù),而對象是類的單個實(shí)例。
一個類充當(dāng)模板或藍(lán)圖,可以從中創(chuàng)建許多單個對象。創(chuàng)建單個對象時,盡管每個對象的某些屬性可能具有不同的值,但它們繼承相同的通用屬性和行為。
例如,將類視為房子的藍(lán)圖。藍(lán)圖本身不是房屋,而是房屋的詳細(xì)計(jì)劃。而對象就像是根據(jù)該藍(lán)圖建造的實(shí)際房屋。我們可以根據(jù)相同的藍(lán)圖建造幾座相同的房屋,但是每座房屋內(nèi)部可能具有不同的涂料,內(nèi)飾和家庭,如下圖所示。
可以使用class關(guān)鍵字聲明一個類,后跟該類的名稱和一對花括號({}),如以下示例所示。
讓我們創(chuàng)建一個名為Recangle.php的PHP文件,并將以下示例代碼放入其中,以便將我們的類代碼與程序的其余部分分開。 然后,我們只需包含Recangle.php文件,就可以在需要的任何地方使用它。
<?php class Rectangle { //聲明屬性 public $length = 0; public $width = 0; //求周長的方法 public function getPerimeter(){ return (2 * ($this->length + $this->width)); } //求面積的方法 public function getArea(){ return ($this->length * $this->width); } } ?>
public關(guān)鍵字在上面的實(shí)例中的屬性和方法之前,是一個訪問修飾符,表示該屬性或方法是可以從任何地方訪問。我們將在本章稍后了解更多有關(guān)此內(nèi)容的信息。
注意:從語法上講,類中的變量稱為屬性,而函數(shù)稱為方法。 此外,類名通常是用PascalCase(帕斯卡命名法)編寫的,也就是說,每個連接的單詞都以大寫字母開頭(例如,MyClass)。
創(chuàng)建另一個PHP文件名test.php,并將以下代碼放入其中。
<?php //包含類定義 class Rectangle { //聲明屬性 public $length = 0; public $width = 0; //求周長的方法 public function getPerimeter(){ return (2 * ($this->length + $this->width)); } //求面積的方法 public function getArea(){ return ($this->length * $this->width); } } //從Rectangle類創(chuàng)建一個新對象 $obj = new Rectangle; //獲取對象屬性值 echo $obj->length; // 輸出: 0 echo $obj->width; // 輸出: 0 //設(shè)置對象屬性值 $obj->length = 30; $obj->width = 20; //再次讀取對象屬性值以顯示更改 echo $obj->length; // 輸出: 30 echo "<br>"; echo $obj->width; // 輸出: 20 //調(diào)用對象方法 echo $obj->getPerimeter(); // 輸出: 100 echo "<br>"; echo $obj->getArea(); // 輸出: 600 ?>測試看看?/?
箭頭符號(->)是一個OOP構(gòu)造,用于訪問給定對象的包含的屬性和方法。而偽變量$this提供了對調(diào)用對象(即方法所屬的對象)的引用。
當(dāng)使用同一類的多個實(shí)例時,面向?qū)ο缶幊痰恼嬲惋@而易見了,如以下示例所示:
<?php //包含類定義 class Rectangle { //聲明屬性 public $length = 0; public $width = 0; //求周長的方法 public function getPerimeter(){ return (2 * ($this->length + $this->width)); } //求面積的方法 public function getArea(){ return ($this->length * $this->width); } } //從Rectangle類創(chuàng)建多個對象 $obj1 = new Rectangle; $obj2 = new Rectangle; //調(diào)用兩個對象的方法 echo $obj1->getArea(); //輸出:0 echo $obj2->getArea(); //輸出:0 //設(shè)置$obj1屬性值 $obj1->length = 30; $obj1->width = 20; //設(shè)置$obj2屬性值 $obj2->length = 35; $obj2->width = 50; //再次調(diào)用兩個對象的方法 echo $obj1->getArea(); //輸出:600 echo "<br>"; echo $obj2->getArea(); //輸出:1750 ?>測試看看?/?
如上例所示,在不同的對象上調(diào)用getArea()方法會使該方法對不同的數(shù)據(jù)集進(jìn)行操作。 每個對象實(shí)例都是完全獨(dú)立的,具有自己的屬性和方法,因此即使它們屬于同一類,也可以獨(dú)立地對其進(jìn)行操作。
為了簡化面向?qū)ο蟮木幊?,PHP提供了一些魔術(shù)方法,當(dāng)對象中發(fā)生某些操作時,這些方法會自動執(zhí)行。
例如,每當(dāng)創(chuàng)建新對象時,魔術(shù)方法__construct()(稱為構(gòu)造函數(shù))都會自動執(zhí)行。 同樣,魔術(shù)方法__destruct()(稱為析構(gòu)函數(shù))在對象被銷毀時會自動執(zhí)行。 銷毀對象后,析構(gòu)函數(shù)將清除分配給該對象的所有資源。
<?php class MyClass { // 構(gòu)造函數(shù) public function __construct(){ echo ' 類 "' . __CLASS__ . '" 已啟動<br>'; } // 析構(gòu)函數(shù) public function __destruct(){ echo '類 "' . __CLASS__ . '" 已銷毀<br>'; } } //創(chuàng)建一個新對象 $obj = new MyClass; //在文件末尾輸出消息 echo "到達(dá)文件末尾。"; ?>測試看看?/?
上面示例中的PHP代碼將產(chǎn)生以下輸出:
類 "MyClass" 已啟動 到達(dá)文件末尾。 類 "MyClass" 已銷毀
腳本結(jié)束時將自動調(diào)用析構(gòu)函數(shù)。但是,要顯式觸發(fā)析構(gòu)函數(shù),可以使用PHP unset()函數(shù)銷毀對象,如下所示:
<?php class MyClass { // 構(gòu)造函數(shù) public function __construct(){ echo ' 類 "' . __CLASS__ . '" 已啟動<br>'; } // 析構(gòu)函數(shù) public function __destruct(){ echo '類 "' . __CLASS__ . '" 已銷毀<br>'; } } //創(chuàng)建一個新對象 $obj = new MyClass; // 銷毀對象 unset($obj); //在文件末尾輸出消息 echo "到達(dá)文件末尾。"; ?>測試看看?/?
現(xiàn)在,以上示例中的PHP代碼將產(chǎn)生以下輸出:
類 "MyClass" 已啟動 類 "MyClass" 已銷毀 到達(dá)文件末尾。
提示:腳本完成后,PHP會自動清除執(zhí)行期間分配的所有資源,例如關(guān)閉數(shù)據(jù)庫連接,銷毀對象等。
注:__CLASS__是一個魔術(shù)常量,它包含它所在的類的名稱。如果它發(fā)生在類之外,則為空。
類可以使用extends關(guān)鍵字繼承另一個類的屬性和方法??蓴U(kuò)展性的過程稱為繼承。這可能是使用面向?qū)ο蟮木幊棠P捅澈笞顝?qiáng)大的原因。
<?php //包含類定義 class Rectangle { //聲明屬性 public $length = 0; public $width = 0; //求周長的方法 public function getPerimeter(){ return (2 * ($this->length + $this->width)); } //求面積的方法 public function getArea(){ return ($this->length * $this->width); } } //根據(jù)現(xiàn)有的類定義一個新的類 class Square extends Rectangle { //方法來測試矩形是否也是正方形 public function isSquare(){ if($this->length == $this->width){ return true; // 正方形 } else{ return false; //不是正方形 } } } //從Square類創(chuàng)建一個新對象 $obj = new Square; // 設(shè)置對象屬性值 $obj->length = 20; $obj->width = 20; // 調(diào)用對象方法 if($obj->isSquare()){ echo "正方形的面積是"; } else{ echo "矩形的面積是"; }; echo $obj->getArea(); ?>測試看看?/?
上面示例中的PHP代碼將產(chǎn)生以下輸出:
正方形的面積是 400
正如您在上面的示例中看到的,盡管Square的類定義既沒有顯式包含getArea()方法,也沒有顯式包含$length和$width屬性,但是Square類的實(shí)例可以使用它們,因?yàn)樗鼈兝^承自父Rectangle類。
提示:由于子類是從父類派生的,因此也稱為派生類,其父類稱為基類。
在使用類時,您甚至可以使用可見性關(guān)鍵字來限制對其屬性和方法的訪問,以實(shí)現(xiàn)更好的控制。 有三個可見性關(guān)鍵字(從最可見到最不可見):public,protected,private,它們確定如何以及從何處訪問和修改屬性和方法。
public - 可以從類內(nèi)部和外部的任何位置訪問公共屬性或方法。 這是PHP中所有類成員的默認(rèn)可見性。
protected - 受保護(hù)的屬性或方法只能從類本身或子類或繼承類(即擴(kuò)展該類的類)中訪問。
private - 私有屬性或方法只能從定義它的類中訪問。甚至子類或繼承的類也無法訪問私有屬性或方法。
以下示例將向您展示這種可見性實(shí)際上是如何工作的:
<?php //類定義 class Automobile { //聲明屬性 public $fuel; protected $engine; private $transmission; } class Car extends Automobile { // 構(gòu)造函數(shù) public function __construct(){ echo ' 類 "' . __CLASS__ . '" 已啟動<br>'; } } //從Automobile類創(chuàng)建對象 $automobile = new Automobile; //嘗試設(shè)置$automobile對象屬性 $automobile->fuel = 'Petrol'; // ok $automobile->engine = '1500 cc'; // fatal error $automobile->transmission = 'Manual'; // fatal error //從Car類創(chuàng)建對象 $car = new Car; //嘗試設(shè)置$car對象屬性 $car->fuel = 'Diesel'; // ok $car->engine = '2200 cc'; // fatal error $car->transmission = 'Automatic'; // undefined ?>
除了可見性之外,屬性和方法也可以聲明為static(靜態(tài)的),這使得它們無需類的實(shí)例即可訪問??梢允褂梅秶馕鲞\(yùn)算符(::)訪問靜態(tài)屬性和方法,如下所示:ClassName::$property和ClassName::method()。
盡管可以使用靜態(tài)方法,但不能通過該類的對象訪問聲明為靜態(tài)的屬性,如以下示例所示:
<?php //類定義 class HelloClass { //聲明靜態(tài)屬性 public static $greeting = "Hello World!"; //聲明靜態(tài)方法 public static function sayHello(){ echo self::$greeting; } } //嘗試直接訪問靜態(tài)屬性和方法 echo HelloClass::$greeting; //輸出:Hello World! HelloClass::sayHello(); //輸出:Hello World! //嘗試通過對象訪問靜態(tài)屬性和方法 $hello = new HelloClass; echo $hello->greeting; // Strict Warning $hello->sayHello(); //輸出:Hello World! ?>
上例中的關(guān)鍵字self表示“當(dāng)前類別”。 它絕不能以美元符號($)開頭,并且總是以::運(yùn)算符(例如self :: $ name)開頭。
self關(guān)鍵字不同于this關(guān)鍵字,它表示“當(dāng)前對象”或“類的當(dāng)前實(shí)例”。 此關(guān)鍵字始終以美元符號($)開頭,后跟->運(yùn)算符(例如$ this-> name)。
注意:由于靜態(tài)方法可以在沒有類實(shí)例(即對象)的情況下調(diào)用,因此在聲明為static的方法中,偽變量$this不可用。
我們希望您現(xiàn)在已經(jīng)了解了面向?qū)ο缶幊痰幕靖拍睢D鷮⒃赑HP和MySQL數(shù)據(jù)庫部分找到有關(guān)OOP的更多示例。