PHP面向对象常见的关键字和魔术方法
?
?
在PHP5的面向對象程序設計中提供了一些常見的關鍵字,用來修飾類、成員屬性或成員方法,使他們具有特定的功能,例如final、static、const等關鍵字。還有一些比較實用的魔術方法,用來提高類或對象的應用能力,例如__call()、__toString()、__autoload等。
自己對部分關鍵字的理解:
Final:不讓兒子繼承夫類,也就是說不能夠對父類在進行調用,否則將會出錯。
①final關鍵字的應用
final關鍵字的作用如下:
a.實用final標識的類,不能被繼承。
b.在類中使用final標識的成員方法,在子類中不能被覆蓋。
在下面的例子中聲明一個MyClass類,并使用final關鍵字標識,MyClass類就是最終的版本。不能有子類,也就不能對它進行擴展。代碼如下所示:
| 1 2 3 4 5 6 7 8 9 10 | <?php ????final?class?MyClass{???? //聲明一個類,并使用final關鍵字標識,使其不能有子類 ????????//成員略 ????} ????class?MyClass2 extends?MyClass{???? //聲明另一個類并試圖去繼承final標識的類,結果出錯。 ????????//成員略 ????} ?> |
該程序運行后輸出的結果為:
Fatal error:Class MyClass2 may not inberit from final class(MyClass) //輸出錯誤
在上例中,試圖用MyClass2類去繼承用final標識的類MyClass時,系統報錯。同理,如果在類中的成員方法前加final關鍵字標識,則在子類中不能覆蓋它,被final標識的方法也是最終版本。代碼如下所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?php ????final?class?MyClass{???? //聲明一個類,并使用final關鍵字標識,使其不能有子類 ????????final?function?fun(){ ????????????//方法中的內容略 ????????} ????} ????class?MyClass2 extends?MyClass{???? //聲明另一個類并試圖去繼承final標識的類,結果出錯。 ????????function?fun(){ ????????????//方法中的內容略 ????????} ????} ?> |
該程序運行后輸出的結果為:
Fatal error:Cannot ovferride final method MyClass::fun() //系統報錯
在上面的代碼中聲明一個MyClass類,并在類中聲明一個成員方法fun(),在fun()方法前使用final關鍵字標識。又聲明一個類MyClass2類去繼承MyClass類,并在子類MyClass2中聲明一個方法fun()試圖去覆蓋父類中被final標識的fun()方法時,系統會出現報錯信息。
②static關鍵字的使用
使用static關鍵字可以將類中的成員標識為靜態的,既可以用來標識成員屬性,也可以用來標識成員方法。以Person類為例,如果在person類中有一個“$country=’china’”的成員屬性,任何一個Person類的對象都會擁有自己的一份$country屬性,對象之間不會干擾。而static成員是作為整個類的屬性存在,如果將$country屬性使用static關鍵字標識,則不管通過Person類創建多少個對象(甚至可以是沒有對象),這個static成員總是唯一存在的,在多個對象之間共享的。因為使用static標識的成員是屬于類的,所以與對象實例和其他的類無關。類的靜態屬性非常類似于函數的全局變量。類中的靜態成員時不需要對象而使用類名來直接訪問的,格式如下所示:
類名::靜態成員屬性名; ? ? ? ? ? ? ? ? ? ? ? ? ?//在類的外部和成員方法中都可以使用這種方式訪問靜態成員屬性
類名::靜態成員方法名(); ? ? ? ? ? ? ? ? ? ? //在類的外部和成員方法中都可以使用這種方式訪問靜態成員方法
在類聲明的成員方法中,因為靜態成員時屬于類的,而不屬于任何對象,所以你不能用$this來引用它,而在php中給我們提供了self關鍵字,就是在類的成員方法中用來代表本類的關鍵字。格式如下所示:
self::靜態成員屬性名; ? ? ? ? ? ? ? ? ? ? ? //在類中的成員方法中使用這種方式訪問本類中的靜態成員屬性
self::靜態成員方法名(); ? ? ? ? ? ? ? ? ?//在類中的成員方法中使用這種方式訪問本類中的靜態成員方法
如果在類的外部訪問類中的靜態成員,可以使用對象引用和使用類名訪問,通常使用類名來訪問。如果在類內部的成員方法中訪問其他的靜態成員,通常使用self的形式去訪問,最好不要直接使用類名稱。在下面的例子中聲明一個MyClass類,為了讓類中的count屬性可以在每個對象中共享,將其聲明為static成員,用來統計通過MyClass類一共創建了多少對象。代碼如下所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?php ????//聲明一個類,用來演示如何使用靜態成員 ????class?MyClass{???? ????????static?$count;?????? //在類中聲名一個靜態成員屬性count,用來統計對象唄創建的次數 ????????function?__construct(){???????? //每次創建一個對象就會自動調用這個構造方法 ????????????self::$count++;????????? //使用self訪問靜態成員count,使其自增1 ????????} ????????static?function?getCount(){???????????? //聲明一個靜態方法,在類外面直接使用類名就可以調用 ????????????return?self::$count;???????? //在方法中使用self訪問靜態成員并返回 ????????} ????} ????MyClass::$count=0;??????????? //在類外面使用類名訪問類中的靜態成員,為其初始化賦值0 ????$myc1?= new?MyClass();?????? //通過MyClass類創建第一個對象,在構造方法中將count累加1 ????$myc2?= new?MyClass();?????? //通過MyClass類創建第二個對象,在構造方法中將count累加1 ????$myc3?= new?MyClass();?????? //通過MyClass類創建第三個對象,在構造方法中將count累加1 ????echo?MyClass::getCount();?????? //在類外面使用類名訪問類中的靜態成員方法,獲取靜態屬性的值3 ????echo?$myc3?-> getCount();?????? //通過對象也可以訪問類中的靜態成員方法,獲取靜態屬性值3 ?> |
上例的MyClass類中,在構造方法內部和成員方法getCount()的內部,都使用self訪問本類中使用static標識為靜態的屬性count,并在類的外部使用類名訪問類中的靜態屬性。可以看到同一個類中的靜態成員在每個對象中共享,沒創建一個對象靜態屬性count就自增1,用來統計實例化對象的次數。
另外在使用靜態方法時需要注意,在靜態方法中只能訪問靜態成員。因為非靜態成員必須通過對象的引用才能訪問,通常是使用$this完成的。而靜態的方法在對象不存在的情況下也可以直接使用類名類訪問,沒有對象也就沒有$this引用,沒有了$this引用就不能訪問類中的非靜態成員,但是可以使用類名或self在非靜態方式中訪問靜態成員。
③const關鍵字
雖然const和static的功能不同,但使用的方法比較相似。在PHP中定義常量是通過調用define()函數來完成的,但要將類中的成員屬性定義為常量,則只能使用const關鍵字。將類中的成員屬性使用const關鍵字標識為常量,其訪問的方式和靜態成員一樣,都可以通過類名或在成員的方法中使用self關鍵字訪問,也不能用對象來訪問。標識常量的屬性是只讀的,不能重新賦值,所以在聲明常量時一定要給初值,因為沒有其他方式后期為常量賦值。在下面的示例中演示了再類中如何聲明常量,并在成員方法中使用self和在類外面通過類名來訪問常量。代碼如下所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php ????//聲明一個MyClass類,在類中聲明一個常量,和一個成員方法 ????class?MyClass{ ????????const?CONSTANT = 'CONSTANT value';?????? //使用const聲明一個常量,并直接附上初始值 ????????function?showConstant() { ????????????echo?self::CONSTANT."<BR>";????????????? //使用self訪問常量,注意常量前不要加"$" ????????} ????} ????echo?MyClass::CONSTANT . "<BR>";??????????? //在類外部使用類名稱訪問常量 ????$class?= new?MyClass();????????????????? //通過類MyClass創建一個對象引用$class ????$class?->showConstant();??????????? //調用對象中的方法 ?> |
④instanceof關鍵字
使用這個關鍵字可以確定一個對象是類的實例、類的子類,還是實現了某個特定接口,并進行相應的操作。例如,假設希望了解名為$man的對象是否為類Person的實例:
| 1 2 3 4 5 6 7 | <?php ????$man?=new?Person(); ????????... ????if($man?instanceof?Person) ????????echo?'$man 是Person類的實例對象'; ?> |
在這里有兩點值得注意。首先,類名沒有任何定界符(不使用引號),使用定界符將導致語法錯誤。其次,如果比較失敗,腳本將退出執行。instanceof關鍵字在同時處理多個對象時特別有用,例如,你可能要重復地調用某個函數,但希望根據對象類型調整函數的行為。
⑤clone關鍵字克隆對象和__clone()魔術方法。
在PHP中可以根據現有對象克隆出一個完全一樣的對象,克隆以后原本和副本兩個對象完全獨立,互不干擾。在PHP5中使用“clone”關鍵字克隆對象,代碼如下所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <?php ????class?Person{ ????????private?$name; ????????private?$sex; ????????private?$age; ????????//構造方法在對象誕生時為成員屬性付初值 ????????function?__construct($name="",$sex="",$age=1){ ????????????$this?->name = $name; ????????????$this?->sex = $sex; ????????????$this?->age = $age; ????????} ????????//聲明此方法則在對象克隆時自動調用,用來為新對象重新賦值 ????????function?__clone(){ ????????????$this?->name ="我是".$that?->name."的副本";???? //為副本對象中的name屬性重新賦值 ????????????$this?->age =10; ????????} ????????//一個成員方法用于打印出自己對象中全部的成員屬性值 ????????function?say() { ????????????echo?"我的名字:".$this?->name.",性別:".$this?->sex.",年齡:".$this?->age."<br>"; ????????} ????} ????$p1?= new?Person("張三","男",20); ????$p2?= new?clone?$p1; ????$p1?->say();????????? //調用源對象中的說話方法,打印原對象中全部屬性值 ????$p2?->say();????????? //調用副本對象中的說話方法,打印副本對象中全部屬性值 ?> |
改程序運行后輸出的結果為:
我的名字:張三, 性別:男,年齡:20
我的名字:我是張三的副本, 性別:男,年齡:10 //副本對象中的name和age都被賦上新值
在上面的程序中一共創建了兩個對象,其中有一個對象是通過clone關鍵字克隆出來的副本。兩個對象完全獨立,如果需要對克隆后的副本對象在克隆時重新為成員屬性賦初值,則可以在類中聲明一個魔術方法“__clone()”。該方法時在對象克隆時自動調用的,所以就可以通過此方法對克隆后的副本重新初始化。__clone()方法不需要任何參數,該方法中自動包含$this和$that兩個對象的引用,$this是副本對象的引用,$that是原本對象的引用。將上例中的代碼改寫一下,在類中添加魔術方法__clone(),為副本對象中的成員屬性重新初始化。代碼如下所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?php ????class?Person{ ????????private?$name; ????????private?$sex; ????????private?$age; ????????//構造方法在對象誕生時為成員屬性付初值 ????????function?__construct($name="",$sex="",$age=1){ ????????????$this?->name = $name; ????????????$this?->sex = $sex; ????????????$this?->age = $age; ????????} ????????//一個成員方法用于打印出自己對象中全部的成員屬性值 ????????function?say() { ????????????echo?"我的名字:".$this?->name.",性別:".$this?->sex.",年齡:".$this?->age."<br>"; ????????} ????} ????$p1?= new?Person("張三","男",20); ????$p2?= new?clone?$p1; ????$p1?->say();????????? //調用源對象中的說話方法,打印原對象中全部屬性值 ????$p2?->say();????????? //調用副本對象中的說話方法,打印副本對象中全部屬性值 ?> |
⑥類中通用的方法__toString()
“魔術”方法__toString()是快速獲取對象的字符串標識的最便捷的方式,它是在直接輸出對象引用時自動調用的方法。通過前面的介紹我們知道,對象引用是一個指針,即存放對象在堆內存中的首地址的變量。例如“$p=new Person()”語句中,$p就是一個對象的引用,如果直接使用echo輸出$p,則會輸出錯誤。如果在類中添加了“__toString()”方法,則直接輸出對象的引用時就不會產生錯誤,而是自動調用了該方法,并輸出“__toString()”方法中返回的字符串。所以__toString()方法中一定要有一個字符串作為返回值,通常在此方法中返回字符串是使用對象中多個屬性值鏈接而成的。在下面的例子中聲明一個測試類,并在類中添加了__toString()方法,該方法中將成員屬性的值轉化為字符串后返回。代碼如下所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php ????class?TestClass{ ????????private?$foo; ????????function?__construct($foo){ ????????????$this?-> foo = $foo; ????????} ????????public?function?__toString(){ ????????????return?$this?->foo; ????????} ????} ????$obj?= new?TestClass('hello'); ????echo?$obj; ?> |
⑦__call()方法的應用
如果嘗試調用對象中不存在的方法,一定會出現系統報錯,并推出程序不能繼續執行。在PHP中,可以在類中添加一個魔術方法__call(),則調用對象中不存在的方法時就會自動調用該方法,并且程序也可以繼續向下執行。所以我們可以借助__call()方法提示用戶,例如,用戶調用的方法及需要的參數列表不存在。__call()方法需要兩個參數:第一個參數是調用不存在的方法時,接收這個方法名稱字符串;而參數列表則以數組的形式傳遞到__call()方法的第二個參數中。下面的例子聲明的類中添加了__call()方法,用來解決用戶調用對象中不存在的方法的情況。代碼如下所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php ????class?TestClass{ ????????function?printHello(){ ????????????echo?"Hello<br>"; ????????} ????????function?__call($functionName,$arge) { ????????????echo?"你所調用的函數:".$functionName."(參數:"; ????????????print_r($arge); ????????????echo?")不存在!<br>\n"; ????????} ????} ????$obj?= new?TestClass(); ????$obj?-> myFun("one",2,"three");????????? //調用對象中不存在的方法,則自動調用了對象中的__call()方法 ????$obj?-> otherFun(8,9);?????????????????? //調用對象中不存在的方法,則自動調用了對象中的__call()方法 ????$obj?-> printHello();???????????? //調用對象中存在的方法,可以成功調用 ?> |
該程序運行后輸出的結果為:
你所調用的函數:myFun(參數:Array([0]=>one ,[1]=>2,[2]=>three))不存在!
你所調用的函數:myFun(參數:Array([0]=>8 ,[1]=>9))不存在!
Hello
⑧__autoload()自動加載類
在設計面向對象的程序開發時,通常為每個類的定義都單獨建立一個PHP源文件。當你嘗試使用一個未定義的類時,PHP會報告一個致命錯誤。可以用include包含一個類鎖子啊的源文件,畢竟你知道要用哪個類。如果一個頁面需要使用多個類,就不得不在腳本頁面開頭編寫一個長長的包含文件的列表,將本頁面需要的類全部包含進來。這樣處理不僅繁瑣,而且容易出錯。
PHP提供了類的自動加載功能,這可以節省編程的事件。當你嘗試使用一個PHP沒有組織到的類時,它會尋找一個__autoload()的全局函數(不是在類中聲明的函數)。如果存在這個函數,PHP會用一個參數來調用它,參數即類的名稱。
在下例中說明了__autoload()是如何使用的,它假設當前目錄下每個文件對應一個類,當腳本嘗試來創建一個類User的實例時,PHP會自動執行__autoload()函數。腳本假設user.class.php中定義有User類,不管調用時是大寫還是小寫,PHP將返回名稱小寫。所以你做項目時,在組織定義類的文件名時,需要按照一定的規則,一定要以類名為中心,也可以加上同意的前綴或后最形成文件名,比如classname.class.php、xxx_classname.php、lassname_xxx.php或是classname.php等,推薦類文件名使用“classname.class.php”格式。代碼如下所示:
| 1 2 3 4 5 6 7 8 | <?php ????function?__autoload($className){ ????????include(strtolower($className)."class.php"); ????} ????$obj?= new?User();???????? //User類不存在則自動調用__autoload()函數,將類名User作為參數傳入 ????$obj2?= new?Shop();??????? //Shop類不存在則自動調用__autoload()函數,將類名Shop作為參數傳入 ?> |
⑨serialize()對象串行化
對象通過寫出描述自己狀態的數值來記錄自己,這個過程稱對象的串行化。串行化就是把整個對象轉化為二進制字符串。在兩種情況下必須把對象串行化,如下所示:
a.對象需要在網絡中傳輸時,將對象串行化成二進制串后在網絡中傳輸。
b.對象需要持久保存時,將對象串行化后寫入文件或是數據庫中。
使用serialize()函數來串行化一個對象,把對象轉化為二進制的字符串。serialize()函數需要一個參數就是對象的引用名,返回值為一個對象被串行化后的字符串。另一個是反串行化,就是把對象串行化后轉化的二進制字符串再轉化為對象,我們使用unserialize()函數來飯串行化一個對象。
在PHP5中還有兩個魔術方法__sleep()和__wakeup()可以使用。在調用serialize()函數將對象串行化時,會自動調用對象中的__sleep()方法,用來將對象中的部分成員串行化。在調用unserialize()函數飯串行化對象時,則會自動調用對象中的__wakeup()方法,用來在二進制串重新組成一個對象時,為新對象中的成員屬性重新初始化。
__sleep()函數不需要接收任何參數,但需要返回一個數組,在數組中包含需要串行化的屬性。未被包含在數組中的屬性將在串行化時被忽略。如果沒有在類中聲明sleep()方法,對象中的所有屬性都將被串行化。代碼如下所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <?php ????class?Person { ????????private?$name; ????????private?$sex; ????????private?$age; ????????function?__construct($name="",$sex="",$age=1){ ????????????$this?->name = $name; ????????????$this?->sex = $sex; ????????????$this?->age = $age; ????????} ????????function?say() { ????????????echo?"我的名字:".$this?->name.",性別:".$this?->sex.",年齡:".$this?->age."<br>"; ????????} ????????//在類中添加此方法,在串行化時自動調用并返回數組 ????????function?__sleep(){ ????????????$arr?= array("name","age");????? //數組中的成員$name和$age將被串行化,成員$sex則被忽略 ????????????return($arr); ????????} ????????//在反串行化對象時自動調用該方法,沒有參數也沒有返回值 ????????function?__wakeup(){ ????????????$this?->age = 40;??????? //在重新組織對象時,為新對象中的$age屬性重新賦值 ????????} ????} ????$person1?= new?Person("張三","男",20);???? ????//把一個對象串行化,返回一個字符串,調用了__sleep()方法,忽略沒在數組中的屬性$sex ????$person_string=serialize($person_string); ????echo?$person_string."<br>"; ????//反串行化對象,并自動調用了__wakeup()方法重新為對象中的$age屬性賦值 ????$person2?= unserialize($person_string);?????????? //反串行化對象形成對象$P2重新賦值$age為40 ????$person2?->say(); ?> |
總結
以上是生活随笔為你收集整理的PHP面向对象常见的关键字和魔术方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java核心技术卷】I/O详析
- 下一篇: UE破解版安装