面向对象的PHP初学者
原文鏈接
?
理解面向?qū)ο蟮木幊?/span>
面向?qū)ο缶幊淌且环N編碼風(fēng)格,允許開發(fā)人員將類似的任務(wù)分組到類中。這有助于保持代碼遵循“不要重復(fù)自己”(DRY)和易于維護(hù)的原則。
“面向?qū)ο缶幊淌且环N編碼風(fēng)格,允許開發(fā)人員將類似的任務(wù)分組到類中。”
DRY編程的一個主要好處是,如果程序中的一條信息發(fā)生變化,通常只需要進(jìn)行一次更改即可更新代碼。開發(fā)人員最大的噩夢之一就是維護(hù)代碼,一遍又一遍地聲明數(shù)據(jù),這意味著程序的任何變化都會成為Where's Waldo的一個無比令人沮喪的游戲?因?yàn)樗麄儗ふ抑貜?fù)的數(shù)據(jù)和功能。
OOP對許多開發(fā)人員來說是令人生畏的,因?yàn)樗肓诵抡Z法,并且一目了然,它似乎比簡單的過程代碼或內(nèi)聯(lián)代碼復(fù)雜得多。但是,仔細(xì)觀察后,OOP實(shí)際上是一種非常簡單且最簡單的編程方法。
了解對象和類
在深入了解OOP的細(xì)節(jié)之前,必須對對象和類之間的差異有基本的了解。本節(jié)將介紹類的構(gòu)建塊,它們的不同功能以及它們的一些用途。
認(rèn)識到對象和類之間的差異
照片即時杰斐遜和約翰·沃德爾
開發(fā)人員開始討論對象和類,它們似乎是可互換的術(shù)語。然而,事實(shí)并非如此。
馬上就有了混亂:經(jīng)驗(yàn)豐富的開發(fā)人員開始討論對象和類,它們似乎是可互換的術(shù)語。然而,事實(shí)并非如此,盡管起初差異很大。
例如,一個類就像一個房子的藍(lán)圖。它定義了紙房的形狀,房屋的不同部分之間的關(guān)??系明確定義和計(jì)劃,即使房子不存在。
那么,一個物體就像根據(jù)那個藍(lán)圖建造的實(shí)際房屋。存儲在物體中的數(shù)據(jù)就像組成房屋的木頭,電線和混凝土:沒有根據(jù)藍(lán)圖組裝,它只是一堆東西。然而,當(dāng)它們匯集在一起??時,它就變成了一個有組織的,有用的房子。
類構(gòu)成數(shù)據(jù)和動作的結(jié)構(gòu),并使用該信息來構(gòu)建對象。可以同時從同一個類構(gòu)建多個對象,每個對象獨(dú)立于其他對象。繼續(xù)我們的建筑類比,它類似于整個細(xì)分可以從同一個藍(lán)圖建立的方式:150個不同的房子,看起來都一樣,但
內(nèi)部有不同的家庭和裝飾。
構(gòu)建類
創(chuàng)建類的語法非常簡單:使用class關(guān)鍵字聲明一個類,然后是類的名稱和一組花括號({}):
| 1 2 3 4 五 6 7 8 | <?php ? class MyClass { ??// Class properties and methods go here } ? ?> |
創(chuàng)建類后,可以使用new關(guān)鍵字實(shí)例化一個新類并將其存儲在變量中:
| 1 | $obj = new MyClass; |
要查看該類的內(nèi)容,請使用var_dump():
| 1 | var_dump($obj); |
通過將所有前面的代碼test.php放在[your local] testing文件夾中調(diào)用的新文件中來嘗試此過程:
| 01 02 03 04 05 06 07 08 09 10 11 12 | <?php ? class MyClass { ????// Class properties and methods go here } ? $obj = new MyClass; ? var_dump($obj); ? ?> |
在瀏覽器中加載頁面,http://localhost/test.php應(yīng)顯示以下內(nèi)容:
| 1 | object(MyClass)#1 (0) { } |
在最簡單的形式中,您剛剛完成了第一個OOP腳本。
定義類屬性
要使用向類,屬性或類特定變量添加數(shù)據(jù)。這些工作與常規(guī)變量完全相同,除了它們綁定到對象,因此只能使用對象訪問。
要添加屬性MyClass,請將以下代碼添加到腳本中:
| 01 02 03 04 05 06 07 08 09 10 11 12 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; } ? $obj = new MyClass; ? var_dump($obj); ? ?> |
關(guān)鍵字public確定屬性的可見性,您將在本章后面稍后了解該屬性。接下來,使用標(biāo)準(zhǔn)變量語法命名該屬性,并指定一個值(盡管類屬性不需要初始值)。
要讀取此屬性并將其輸出到瀏覽器,請引用要讀取的對象和要讀取的屬性:
| 1 | echo $obj->prop1; |
因?yàn)榭梢源嬖陬惖亩鄠€實(shí)例,所以如果未引用單個對象,則腳本將無法確定要從哪個對象讀取。arrow(->)的使用是一個OOP構(gòu)造,它訪問給定對象的包含屬性和方法。
修改腳本test.php以讀取屬性,而不是通過修改代碼來轉(zhuǎn)儲整個類,如下所示:
| 01 02 03 04 05 06 07 08 09 10 11 12 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; } ? $obj = new MyClass; ? echo $obj->prop1; // Output the property ? ?> |
現(xiàn)在重新加載瀏覽器會輸出以下內(nèi)容:
| 1 | I'm a class property! |
定義類方法
方法是特定于類的函數(shù)。對象能夠執(zhí)行的各個動作在類中定義為方法。
例如,要創(chuàng)建設(shè)置和獲取類屬性值的方法$prop1,請將以下內(nèi)容添加到代碼中:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??public function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? $obj = new MyClass; ? echo $obj->prop1; ? ?> |
注?- OOP允許對象使用引用自己$this。在方法中工作時,使用$this與在類外部使用對象名稱相同的方式。
要使用這些方法,請像常規(guī)函數(shù)一樣調(diào)用它們,但首先,引用它們所屬的對象。閱讀該屬性MyClass,更改其值,并通過以下修改再次閱讀:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??public function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? $obj = new MyClass; ? echo $obj->getProperty(); // Get the property value ? $obj->setProperty("I'm a new property value!"); // Set a new one ? echo $obj->getProperty(); // Read it out again to show the change ? ?> |
重新加載您的瀏覽器,您將看到以下內(nèi)容:
| 1 2 | I'm a class property! I'm a new property value! |
“當(dāng)使用
同一類的多個實(shí)例時,OOP的力量變得明顯。”
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??public function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? // Create two objects $obj = new MyClass; $obj2 = new MyClass; ? // Get the value of $prop1 from both objects echo $obj->getProperty(); echo $obj2->getProperty(); ? // Set new values for both objects $obj->setProperty("I'm a new property value!"); $obj2->setProperty("I belong to the second instance!"); ? // Output both objects' $prop1 value echo $obj->getProperty(); echo $obj2->getProperty(); ? ?> |
在瀏覽器中加載結(jié)果時,其內(nèi)容如下:
| 1 2 3 4 | I'm a class property! I'm a class property! I'm a new property value! I belong to the second instance! |
正如您所看到的,OOP將對象保持為單獨(dú)的實(shí)體,這樣可以輕松地將不同的代碼片段分成小的相關(guān)包。
OOP中的魔術(shù)方法
為了更容易地使用對象,PHP還提供了許多魔術(shù)方法,或在對象中發(fā)生某些常見操作時調(diào)用的特殊方法。這允許開發(fā)人員相對容易地執(zhí)行許多有用的任務(wù)。
使用構(gòu)造函數(shù)和析構(gòu)函數(shù)
當(dāng)一個對象被實(shí)例化時,通常需要立即設(shè)置一些東西。為了解決這個問題,PHP提供了魔術(shù)方法__construct(),無論何時
創(chuàng)建新對象,都會自動調(diào)用該方法。
為了說明構(gòu)造函數(shù)的概念,添加一個構(gòu)造函數(shù)MyClass,只要創(chuàng)建了一個新的類實(shí)例,它就會輸出一條消息:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function __construct() ??{ ??????echo 'The class "', __CLASS__, '" was initiated!<br />'; ??} ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??public function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? // Create a new object $obj = new MyClass; ? // Get the value of $prop1 echo $obj->getProperty(); ? // Output a message at the end of the file echo "End of file.<br />"; ? ?> |
注?-?__CLASS__返回調(diào)用它的類的名稱;?這就是眾所周知的神奇常數(shù)。有幾個可用的魔術(shù)常量,您可以在PHP手冊中內(nèi)容。
在瀏覽器中重新加載文件將產(chǎn)生以下結(jié)果:
| 1 2 3 | The class "MyClass" was initiated! I'm a class property! End of file. |
要在銷毀對象時調(diào)用函數(shù),可以使用__destruct()魔術(shù)方法。這對于類清理很有用(例如,關(guān)閉數(shù)據(jù)庫連接)。
通過
__destruct()在MyClass以下位置定義魔術(shù)方法來銷毀對象時輸出消息:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function __construct() ??{ ??????echo 'The class "', __CLASS__, '" was initiated!<br />'; ??} ? ??public function __destruct() ??{ ??????echo 'The class "', __CLASS__, '" was destroyed.<br />'; ??} ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??public function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? // Create a new object $obj = new MyClass; ? // Get the value of $prop1 echo $obj->getProperty(); ? // Output a message at the end of the file echo "End of file.<br />"; ? ?> |
定義了析構(gòu)函數(shù)后,重新加載測試文件會產(chǎn)生以下輸出:
| 1 2 3 4 | The class "MyClass" was initiated! I'm a class property! End of file. The class "MyClass" was destroyed. |
“當(dāng)達(dá)到文件末尾時,PHP會自動釋放所有資源。”
要顯式觸發(fā)析構(gòu)函數(shù),可以使用以下
函數(shù)銷毀對象unset():
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function __construct() ??{ ??????echo 'The class "', __CLASS__, '" was initiated!<br />'; ??} ? ??public function __destruct() ??{ ??????echo 'The class "', __CLASS__, '" was destroyed.<br />'; ??} ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??public function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? // Create a new object $obj = new MyClass; ? // Get the value of $prop1 echo $obj->getProperty(); ? // Destroy the object unset($obj); ? // Output a message at the end of the file echo "End of file.<br />"; ? ?> |
現(xiàn)在,當(dāng)您在瀏覽器中加載時,結(jié)果將更改為以下內(nèi)容:
| 1 2 3 4 | The class "MyClass" was initiated! I'm a class property! The class "MyClass" was destroyed. End of file. |
轉(zhuǎn)換為字符串
為避免在腳本嘗試以MyClass字符串形式輸出時出現(xiàn)錯誤,請使用另一種魔術(shù)方法__toString()。
沒有__toString(),嘗試將對象輸出為字符串會導(dǎo)致致命錯誤。嘗試使用echo輸出對象而不使用魔術(shù)方法:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function __construct() ??{ ??????echo 'The class "', __CLASS__, '" was initiated!<br />'; ??} ? ??public function __destruct() ??{ ??????echo 'The class "', __CLASS__, '" was destroyed.<br />'; ??} ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??public function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? // Create a new object $obj = new MyClass; ? // Output the object as a string echo $obj; ? // Destroy the object unset($obj); ? // Output a message at the end of the file echo "End of file.<br />"; ? ?> |
這導(dǎo)致以下結(jié)果:
| 1 2 3 | The class "MyClass" was initiated! ? Catchable fatal error: Object of class MyClass could not be converted to string in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 40 |
要避免此錯誤,請?zhí)砑觃_toString()方法:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function __construct() ??{ ??????echo 'The class "', __CLASS__, '" was initiated!<br />'; ??} ? ??public function __destruct() ??{ ??????echo 'The class "', __CLASS__, '" was destroyed.<br />'; ??} ? ??public function __toString() ??{ ??????echo "Using the toString method: "; ??????return $this->getProperty(); ??} ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??public function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? // Create a new object $obj = new MyClass; ? // Output the object as a string echo $obj; ? // Destroy the object unset($obj); ? // Output a message at the end of the file echo "End of file.<br />"; ? ?> |
在這種情況下,嘗試將對象轉(zhuǎn)換為字符串會導(dǎo)致調(diào)用該getProperty()方法。在瀏覽器中加載測試腳本以查看結(jié)果:
| 1 2 3 4 | The class "MyClass" was initiated! Using the toString method: I'm a class property! The class "MyClass" was destroyed. End of file. |
提示?- 除了本節(jié)中討論的魔術(shù)方法之外,還有其他幾種方法可用。有關(guān)魔術(shù)方法的完整列表,請參閱?PHP手冊頁。
使用類繼承
類可以使用extends關(guān)鍵字繼承另一個類的方法和屬性。例如,要創(chuàng)建擴(kuò)展MyClass和添加方法的第二個類,您可以將以下內(nèi)容添加到測試文件中:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function __construct() ??{ ??????echo 'The class "', __CLASS__, '" was initiated!<br />'; ??} ? ??public function __destruct() ??{ ??????echo 'The class "', __CLASS__, '" was destroyed.<br />'; ??} ? ??public function __toString() ??{ ??????echo "Using the toString method: "; ??????return $this->getProperty(); ??} ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??public function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? class MyOtherClass extends MyClass { ??public function newMethod() ??{ ??????echo "From a new method in " . __CLASS__ . ".<br />"; ??} } ? // Create a new object $newobj = new MyOtherClass; ? // Output the object as a string echo $newobj->newMethod(); ? // Use a method from the parent class echo $newobj->getProperty(); ? ?> |
在瀏覽器中重新加載測試文件后,輸出以下內(nèi)容:
| 1 2 3 4 | The class "MyClass" was initiated! From a new method in MyOtherClass. I'm a class property! The class "MyClass" was destroyed. |
覆蓋繼承的屬性和方法
要更改新類中現(xiàn)有屬性或方法的行為,可以通過在新類中再次聲明它來覆蓋它:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function __construct() ??{ ??????echo 'The class "', __CLASS__, '" was initiated!<br />'; ??} ? ??public function __destruct() ??{ ??????echo 'The class "', __CLASS__, '" was destroyed.<br />'; ??} ? ??public function __toString() ??{ ??????echo "Using the toString method: "; ??????return $this->getProperty(); ??} ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??public function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? class MyOtherClass extends MyClass { ??public function __construct() ??{ ??????echo "A new constructor in " . __CLASS__ . ".<br />"; ??} ? ??public function newMethod() ??{ ??????echo "From a new method in " . __CLASS__ . ".<br />"; ??} } ? // Create a new object $newobj = new MyOtherClass; ? // Output the object as a string echo $newobj->newMethod(); ? // Use a method from the parent class echo $newobj->getProperty(); ? ?> |
這會將瀏覽器中的輸出更改為:
| 1 2 3 4 | A new constructor in MyOtherClass. From a new method in MyOtherClass. I'm a class property! The class "MyClass" was destroyed. |
覆蓋方法時保留原始方法功能
要在保持原始方法完整性的同時向繼承的方法添加新功能,請使用parent帶有范圍分辨率operator(::)的關(guān)鍵字:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function __construct() ??{ ??????echo 'The class "', __CLASS__, '" was initiated!<br />'; ??} ? ??public function __destruct() ??{ ??????echo 'The class "', __CLASS__, '" was destroyed.<br />'; ??} ? ??public function __toString() ??{ ??????echo "Using the toString method: "; ??????return $this->getProperty(); ??} ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??public function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? class MyOtherClass extends MyClass { ??public function __construct() ??{ ??????parent::__construct(); // Call the parent class's constructor ??????echo "A new constructor in " . __CLASS__ . ".<br />"; ??} ? ??public function newMethod() ??{ ??????echo "From a new method in " . __CLASS__ . ".<br />"; ??} } ? // Create a new object $newobj = new MyOtherClass; ? // Output the object as a string echo $newobj->newMethod(); ? // Use a method from the parent class echo $newobj->getProperty(); ? ?> |
這將輸出父構(gòu)造函數(shù)和新類的構(gòu)造函數(shù)的結(jié)果:
| 1 2 3 4 五 | The class "MyClass" was initiated! A new constructor in MyOtherClass. From a new method in MyOtherClass. I'm a class property! The class "MyClass" was destroyed. |
分配屬性和方法的可見性
為了增加對對象的控制,為方法和屬性分配可見性。這可以控制如何以及從何處訪問屬性和方法。有三種可見關(guān)鍵字:public,protected,和private。除了可見性之外,還可以將方法或?qū)傩月暶鳛閟tatic,這樣就可以在不實(shí)例化類的情況下訪問它們。
“為了增加對對象的控制,方法和屬性被賦予可見性。”
注?- 可見性是PHP 5中的一項(xiàng)新功能。有關(guān)OOP與PHP 4兼容性的信息,請參閱PHP手冊頁。
公共屬性和方法
到目前為止,您使用的所有方法和屬性都是公開的。這意味著它們可以在課堂內(nèi)和外部訪問任何地方。
受保護(hù)的屬性和方法
聲明屬性或方法時protected,只能在類本身或后代類(擴(kuò)展包含受保護(hù)方法的類的類)中訪問它。
將getProperty()方法聲明為protected in?MyClass并嘗試直接從類外部訪問它:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function __construct() ??{ ??????echo 'The class "', __CLASS__, '" was initiated!<br />'; ??} ? ??public function __destruct() ??{ ??????echo 'The class "', __CLASS__, '" was destroyed.<br />'; ??} ? ??public function __toString() ??{ ??????echo "Using the toString method: "; ??????return $this->getProperty(); ??} ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??protected function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? class MyOtherClass extends MyClass { ??public function __construct() ??{ ??????parent::__construct(); echo "A new constructor in " . __CLASS__ . ".<br />"; ??} ? ??public function newMethod() ??{ ??????echo "From a new method in " . __CLASS__ . ".<br />"; ??} } ? // Create a new object $newobj = new MyOtherClass; ? // Attempt to call a protected method echo $newobj->getProperty(); ? ?> |
嘗試運(yùn)行此腳本時,會顯示以下錯誤:
| 1 2 3 4 | The class "MyClass" was initiated! A new constructor in MyOtherClass. ? Fatal error: Call to protected method MyClass::getProperty() from context '' in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 55 |
現(xiàn)在,在MyOtherClass調(diào)用getProperty()方法時創(chuàng)建一個新方法:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function __construct() ??{ ??????echo 'The class "', __CLASS__, '" was initiated!<br />'; ??} ? ??public function __destruct() ??{ ??????echo 'The class "', __CLASS__, '" was destroyed.<br />'; ??} ? ??public function __toString() ??{ ??????echo "Using the toString method: "; ??????return $this->getProperty(); ??} ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??protected function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? class MyOtherClass extends MyClass { ??public function __construct() ??{ ??????parent::__construct(); echo "A new constructor in " . __CLASS__ . ".<br />"; ??} ? ??public function newMethod() ??{ ??????echo "From a new method in " . __CLASS__ . ".<br />"; ??} ? ??public function callProtected() ??{ ??????return $this->getProperty(); ??} } ? // Create a new object $newobj = new MyOtherClass; ? // Call the protected method from within a public method echo $newobj->callProtected(); ? ?> |
這會產(chǎn)生所需的結(jié)果:
| 1 2 3 4 | The class "MyClass" was initiated! A new constructor in MyOtherClass. I'm a class property! The class "MyClass" was destroyed. |
私有屬性和方法
聲明的屬性或方法只能從定義它的類中private訪問。這意味著即使新類擴(kuò)展了定義私有屬性的類,該屬性或方法也不會在子類中可用。
為了證明這一點(diǎn),聲明getProperty()為私有MyClass,并嘗試callProtected()從
MyOtherClass以下方面調(diào)用:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public function __construct() ??{ ??????echo 'The class "', __CLASS__, '" was initiated!<br />'; ??} ? ??public function __destruct() ??{ ??????echo 'The class "', __CLASS__, '" was destroyed.<br />'; ??} ? ??public function __toString() ??{ ??????echo "Using the toString method: "; ??????return $this->getProperty(); ??} ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??private function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} } ? class MyOtherClass extends MyClass { ??public function __construct() ??{ ??????parent::__construct(); ??????echo "A new constructor in " . __CLASS__ . ".<br />"; ??} ? ??public function newMethod() ??{ ??????echo "From a new method in " . __CLASS__ . ".<br />"; ??} ? ??public function callProtected() ??{ ??????return $this->getProperty(); ??} } ? // Create a new object $newobj = new MyOtherClass; ? // Use a method from the parent class echo $newobj->callProtected(); ? ?> |
重新加載瀏覽器,出現(xiàn)以下錯誤:
| 1 2 3 4 | The class "MyClass" was initiated! A new constructor in MyOtherClass. ? Fatal error: Call to private method MyClass::getProperty() from context 'MyOtherClass' in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 49 |
靜態(tài)屬性和方法
聲明的方法或?qū)傩詓tatic可以在不首先實(shí)例化類的情況下訪問;?您只需提供類名,范圍解析運(yùn)算符以及屬性或方法名稱。
“使用靜態(tài)屬性的一個主要好處是它們在腳本的持續(xù)時間內(nèi)保留它們的存儲值。”
為了演示這一點(diǎn),添加一個名為的靜態(tài)屬性$count和一個名為plusOne()to?的靜態(tài)方法MyClass。然后設(shè)置一個do...while循環(huán)以輸出遞增的值,$count只要該值小于10:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | <?php ? class MyClass { ??public $prop1 = "I'm a class property!"; ? ??public static $count = 0; ? ??public function __construct() ??{ ??????echo 'The class "', __CLASS__, '" was initiated!<br />'; ??} ? ??public function __destruct() ??{ ??????echo 'The class "', __CLASS__, '" was destroyed.<br />'; ??} ? ??public function __toString() ??{ ??????echo "Using the toString method: "; ??????return $this->getProperty(); ??} ? ??public function setProperty($newval) ??{ ??????$this->prop1 = $newval; ??} ? ??private function getProperty() ??{ ??????return $this->prop1 . "<br />"; ??} ? ??public static function plusOne() ??{ ??????return "The count is " . ++self::$count . ".<br />"; ??} } ? class MyOtherClass extends MyClass { ??public function __construct() ??{ ??????parent::__construct(); ??????echo "A new constructor in " . __CLASS__ . ".<br />"; ??} ? ??public function newMethod() ??{ ??????echo "From a new method in " . __CLASS__ . ".<br />"; ??} ? ??public function callProtected() ??{ ??????return $this->getProperty(); ??} } ? do { ??// Call plusOne without instantiating MyClass ??echo MyClass::plusOne(); } while ( MyClass::$count < 10 ); ? ?> |
注?- 訪問靜態(tài)屬性時,美元符號
($)位于范圍解析運(yùn)算符之后。
在瀏覽器中加載此腳本時,將輸出以下內(nèi)容:
| 01 02 03 04 05 06 07 08 09 10 | The count is 1. The count is 2. The count is 3. The count is 4. The count is 5. The count is 6. The count is 7. The count is 8. The count is 9. The count is 10. |
評論DocBlocks
“DocBlock評論風(fēng)格是一種廣泛
接受的記錄類的方法。”
雖然不是OOP的官方部分,但DocBlock評論風(fēng)格是一種廣泛接受的記錄類的方法。除了為
開發(fā)人員在編寫代碼時提供標(biāo)準(zhǔn)外,它還被許多最流行的軟件開發(fā)工具包(SDK)采用,例如Eclipse和NetBeans,并將用于生成代碼提示。
通過使用以附加星號開頭的塊注釋來定義DocBlock:
| 1 2 3 | /** ?* This is a very basic DocBlock ?*/ |
DocBlocks的真正強(qiáng)大之處在于能夠使用標(biāo)簽,標(biāo)簽以符號(@)后面緊跟標(biāo)簽名稱和標(biāo)簽值開頭。DocBlock標(biāo)簽允許開發(fā)人員定義文件的作者,類的許可,屬性或方法信息以及其他有用信息。
使用的最常見標(biāo)簽如下:
- @author:使用此標(biāo)記列出當(dāng)前元素的作者(可能是類,文件,方法或任何代碼)。如果記入多個作者,則可以在同一DocBlock中使用多個作者標(biāo)簽。作者姓名的格式是John Doe <john.doe@email.com>。
- @copyright:這表示當(dāng)前元素的版權(quán)所有者的版權(quán)年份和名稱。格式是2010 Copyright Holder。
- @license:這鏈接到當(dāng)前元素的許可證。許可證信息的格式是
http://www.example.com/path/to/license.txt License Name。 - @var:它包含變量或類屬性的類型和描述。格式是type element description。
- @param:此標(biāo)記顯示函數(shù)或方法參數(shù)的類型和描述。格式是type $element_name element description。
- @return:此標(biāo)記中提供了函數(shù)或方法的返回值的類型和描述。格式是type return element description。
使用DocBlocks評論的示例類可能如下所示:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | <?php ? /** ?* A simple class ?* ?* This is the long description for this class, ?* which can span as many lines as needed. It is ?* not required, whereas the short description is ?* necessary. ?* ?* It can also span multiple paragraphs if the ?* description merits that much verbiage. ?* ?* @author Jason Lengstorf <jason.lengstorf@ennuidesign.com> ?* @copyright 2010 Ennui Design ?* @license http://www.php.net/license/3_01.txt PHP License 3.01 ?*/ class SimpleClass { ??/** ???* A public variable ???* ???* @var string stores data for the class ???*/ ??public $foo; ? ??/** ???* Sets $foo to a new value upon class instantiation ???* ???* @param string $val a value required for the class ???* @return void ???*/ ??public function __construct($val) ??{ ??????$this->foo = $val; ??} ? ??/** ???* Multiplies two integers ???* ???* Accepts a pair of integers and returns the ???* product of the two. ???* ???* @param int $bat a number to be multiplied ???* @param int $baz a number to be multiplied ???* @return int the product of the two parameters ???*/ ??public function bar($bat, $baz) ??{ ??????return $bat * $baz; ??} } ? ?> |
一旦你掃描了上面的類,DocBlock的好處是顯而易見的:一切都是明確定義的,以便下一個開發(fā)人員可以獲取代碼,而不必想知道代碼片段的作用或應(yīng)該包含的內(nèi)容。
比較面向?qū)ο蠛统绦虼a
編寫代碼并不是一種正確和錯誤的方法。話雖如此,本節(jié)概述了在軟件開發(fā)中采用面向?qū)ο蠓椒ǖ膹?qiáng)有力論據(jù),特別是在大型應(yīng)用程序中。
原因1:易于實(shí)施
“雖然起初可能令人生畏,但OOP實(shí)際上提供了一種更簡單的數(shù)據(jù)處理方法。”
雖然起初可能令人生畏,但OOP實(shí)際上提供了一種更簡單的數(shù)據(jù)處理方法。因?yàn)閷ο罂梢栽趦?nèi)部存儲數(shù)據(jù),所以不需要將變量從函數(shù)傳遞到函數(shù)以正常工作。
此外,由于同一類的多個實(shí)例可以同時存在,因此處理大型數(shù)據(jù)集非常容易。例如,假設(shè)您在文件中處理了兩個人的信息。他們需要姓名,職業(yè)和年齡。
程序方法
以下是我們示例的程序方法:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 41 42 | <?php ? function changeJob($person, $newjob) { ??$person['job'] = $newjob; // Change the person's job ??return $person; } ? function happyBirthday($person) { ??++$person['age']; // Add 1 to the person's age ??return $person; } ? $person1 = array( ??'name' => 'Tom', ??'job' => 'Button-Pusher', ??'age' => 34 ); ? $person2 = array( ??'name' => 'John', ??'job' => 'Lever-Puller', ??'age' => 41 ); ? // Output the starting values for the people echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>"; echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>"; ? // Tom got a promotion and had a birthday $person1 = changeJob($person1, 'Box-Mover'); $person1 = happyBirthday($person1); ? // John just had a birthday $person2 = happyBirthday($person2); ? // Output the new values for the people echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>"; echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>"; ? ?> |
執(zhí)行時,代碼輸出以下內(nèi)容:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | Person 1: Array ( ??[name] => Tom ??[job] => Button-Pusher ??[age] => 34 ) Person 2: Array ( ??[name] => John ??[job] => Lever-Puller ??[age] => 41 ) Person 1: Array ( ??[name] => Tom ??[job] => Box-Mover ??[age] => 35 ) Person 2: Array ( ??[name] => John ??[job] => Lever-Puller ??[age] => 42 ) |
雖然這段代碼不一定是壞的,但在編碼時要記住很多。必須傳遞受影響人的屬性數(shù)組并從每個函數(shù)調(diào)用返回,這會留下誤差。
為了清理這個例子,我們希望盡可能少地留給開發(fā)人員。只需要將當(dāng)前操作的絕對必要信息傳遞給函數(shù)。
這是OOP介入的地方,可以幫助您清理。
OOP方法
以下是我們示例的OOP方法:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <?php ? class Person { ??private $_name; ??private $_job; ??private $_age; ? ??public function __construct($name, $job, $age) ??{ ??????$this->_name = $name; ??????$this->_job = $job; ??????$this->_age = $age; ??} ? ??public function changeJob($newjob) ??{ ??????$this->_job = $newjob; ??} ? ??public function happyBirthday() ??{ ??????++$this->_age; ??} } ? // Create two new people $person1 = new Person("Tom", "Button-Pusher", 34); $person2 = new Person("John", "Lever Puller", 41); ? // Output their starting point echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>"; echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>"; ? // Give Tom a promotion and a birthday $person1->changeJob("Box-Mover"); $person1->happyBirthday(); ? // John just gets a year older $person2->happyBirthday(); ? // Output the ending values echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>"; echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>"; ? ?> |
這將在瀏覽器中輸出以下內(nèi)容:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | Person 1: Person Object ( ??[_name:private] => Tom ??[_job:private] => Button-Pusher ??[_age:private] => 34 ) ? Person 2: Person Object ( ??[_name:private] => John ??[_job:private] => Lever Puller ??[_age:private] => 41 ) ? Person 1: Person Object ( ??[_name:private] => Tom ??[_job:private] => Box-Mover ??[_age:private] => 35 ) ? Person 2: Person Object ( ??[_name:private] => John ??[_job:private] => Lever Puller ??[_age:private] => 42 ) |
為了使方法面向?qū)ο?#xff0c;需要更多的設(shè)置,但是在定義了類之后,創(chuàng)建和修改人員變得輕而易舉;?一個人的信息不需要從方法傳遞或返回,只有絕對必要的信息傳遞給每個方法。
“如果實(shí)施得當(dāng),OOP將大大減少您的工作量。”
在小規(guī)模上,這種差異可能看起來不多,但隨著應(yīng)用程序規(guī)模的擴(kuò)大,如果正確實(shí)施,OOP將顯著減少您的工作量。
提示?-?并非所有內(nèi)容都需要面向?qū)ο蟆T趹?yīng)用程序內(nèi)的一個地方處理小事的快速函數(shù)不一定需要包含在類中。在決定面向?qū)ο蠛统绦蚍椒〞r,請使用您的最佳判斷。
原因2:更好的組織
OOP的另一個好處是它有助于輕松打包和編目。每個類通常可以保存在自己的單獨(dú)文件中,如果使用統(tǒng)一的命名約定,訪問類非常簡單。
假設(shè)您有一個包含150個類的應(yīng)用程序,這些類通過應(yīng)用程序文件系統(tǒng)根目錄下的控制器文件動態(tài)調(diào)用。所有150個類都遵循命名約定class.classname.inc.php并駐留在inc應(yīng)用程序的文件夾中。
控制器可以實(shí)現(xiàn)PHP的__autoload()功能,只在動態(tài)調(diào)入所需的類,而不是將所有150包含在控制器文件中,以防萬一或想出一些巧妙的方法將文件包含在你自己的代碼中:
| 1 2 3 4 五 6 | <?php ??function __autoload($class_name) ??{ ??????include_once 'inc/class.' . $class_name . '.inc.php'; ??} ?> |
將每個類放在一個單獨(dú)的文件中也可以使代碼更加便攜,并且更容易在新應(yīng)用程序中重用,而無需進(jìn)行大量復(fù)制和粘貼。
原因3:維護(hù)更方便
由于正確完成OOP的更緊湊性,代碼的更改通常比長意大利面條代碼程序?qū)崿F(xiàn)更容易發(fā)現(xiàn)和制作。
如果特定信息數(shù)組獲得新屬性,則程序性軟件可能需要(在最壞的情況下)將新屬性添加到使用該數(shù)組的每個函數(shù)中。
OOP應(yīng)用程序可能會更新為輕松添加新屬性,然后添加處理所述屬性的方法。
本節(jié)涉及的許多好處是OOP與DRY編程實(shí)踐相結(jié)合的產(chǎn)物。絕對有可能創(chuàng)建易于維護(hù)的過程代碼,不會導(dǎo)致惡夢,并且同樣可能創(chuàng)建可怕的面向?qū)ο蟮拇a。[?Pro PHP和jQuery?]將嘗試與OOP一起演示良好編碼習(xí)慣的組合,以生成易于閱讀和維護(hù)的簡潔代碼。
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的面向对象的PHP初学者的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ThinkPHP调用连连支付
- 下一篇: tp5中mysql使用REGEXP 正则