大(dà)家好,在這裡(lǐ)【源美設計(jì)】就(jiù)和大(dà)家一起談下關于對PHP接口的思考,我們在PHP的接口自(zì)始至終一直在被争議(yì),有人(rén)說(shuō)接口很好,有人(rén)說(shuō)接口像雞肋。首先要明白(bái),好和不好的判斷标準是什麽。無疑,這是和Java/C++相(xiàng)比。在上面的例子中,已經討(tǎo)論了PHP的接口在“面向契約編程”中是不足的,并沒有起到應有的作(zuò)用。
其實,在上面的interface.php代碼中,machine類的聲明應該在plain類前面。接口提供了一套規範,這是系統提供的,然後machine類提供一組針對接口的API并實現,最後才是自(zì)定義的類。在Java裡(lǐ),接口之所以盛行(多線程的runable接口、容器的collection接口等)就(jiù)是因爲系統爲我們做了前面兩部分(fēn)的工(gōng)作(zuò),而程序員(yuán),隻需要去(qù)寫具體(tǐ)的實現類,就(jiù)能保證接口可(kě)用可(kě)控。
爲什麽要用接口?接口到底有什麽好處?接口本身(shēn)并不提供實現,隻是提供一個規範。如(rú)果我們知道一個類實現了某個接口,那麽就(jiù)知道了可(kě)以調用該接口的哪些方法,我們隻需要知道這些就(jiù)夠了。
PHP中,接口的語義是有限的,使用接口的地方并不多,PHP中接口可(kě)以淡化爲設計(jì)文檔,起到一個團隊基本契約的作(zuò)用,代碼如(rú)下所示:
<?php
interface cache{
/**
@describe:緩存管理(lǐ),項目經理(lǐ)定義接口,技術(shù)人(rén)員(yuán)負責實現
**/
const maxKey=10000;//最大(dà)緩存量
public function getc($key);//獲取緩存
public function setc($key,$value);//設置緩存
public function flush();//清空緩存
}
PHP是強調靈活,所以并不推薦大(dà)規模使用接口,而是僅在部分(fēn)“内核”代碼中使用接口,因爲PHP中的接口已經失去(qù)很多接口應該具有的語義。從(cóng)語義上考慮,可(kě)以更多地使用抽象類。至于抽象類和接口的比較,不再贅述。
另外,PHP5對面向對象的特性做了許多增強,其中就(jiù)有一個SPL(标準PHP庫)的嘗試。SPL中實現一些接口,其中最主要的就(jiù)是Iterator叠代器接口,通過實現這個接口,就(jiù)能使對象能夠用于foreach結構,從(cóng)而在使用形式上比較統一。比如(rú)SPL中有一個DirectoryIterator類,這個類在繼承SplFileInfo類的同時,實現Iterator、Traversable、SeekableIterator這三個接口,那麽這個類的實例可(kě)以獲得(de)父類SplFileInfo的全部功能外,還(hái)能夠實現Iterator接口所展示的那些操作(zuò)。
Iterator接口的原型如(rú)下:
*current()
This method returns the current index's value.You are solely
responsible for tracking what the current index is as the
interface does not do this for you.
*key()
This method returns the value of the current index's key.For
foreach loops this is extremely important so that the key
value can be populated.
*next()
This method moves the internal index forward one entry.
*rewind()
This method should reset the internal index to the first element.
*valid()
This method should return true or false if there is a current
element.It is called after rewind()or next().
如(rú)果一個類聲明了實現Iterator接口,就(jiù)必須實現這五個方法,如(rú)果實現了這五個方法,那麽就(jiù)可(kě)以很容易對這個類的實例進行叠代。這裡(lǐ),DirectoryIterator類之所以拿來(lái)就(jiù)能用,是因爲系統已經實現了Iterator接口,所以可(kě)以像下面這樣使用:
<?php
$dir=new DirectoryIterator(dirname(_FILE_));
foreach($dir as$fileinfo){
if(!$fileinfo->isDir()){
echo
$fileinfo->getFilename(),"\t",$fileinfo->getSize(),PHP_EOL;
}
}
可(kě)以想象,如(rú)果不用DirectoryIterator類,而是自(zì)己實現,不但(dàn)代碼量增加了,而且循環時候的風(fēng)格也不統一了。如(rú)果自(zì)己寫的類也實現了Iterator接口,那麽就(jiù)可(kě)以像Iterator那樣工(gōng)作(zuò)。
爲什麽一個類隻要實現了Iterator叠代器,其對象就(jiù)可(kě)以被用作(zuò)foreach的對象呢(ne)?其實原因很簡單,在對PHP實例對象使用foreach語法時,會檢查這個實例有沒有實現Iterator接口,如(rú)果實現了,就(jiù)會通過内置方法或使用實現類中的方法模拟foreach語句。這是不是和前面提到的_toString方法的實現很像呢(ne)?事(shì)實上,_toString方法就(jiù)是接口的一種變相(xiàng)實現。
接口就(jiù)是這樣,接口本身(shēn)什麽也不做,系統悄悄地在内部實現了接口的行爲,所以隻要實現這個接口,就(jiù)可(kě)以使用接口提供的方法。這就(jiù)是接口“即插即用”思想。
我們都(dōu)知道,接口是對多重繼承的一種變相(xiàng)實現,而在講繼承時,我們提到了用來(lái)實現混入(Mixin)式的Traits,實際上,Traits可(kě)以被視爲一種加強型的接口。
來(lái)看(kàn)一段代碼:
<?php
trait Hello{
public function sayHello(){
echo'Hello';
}
}
trait World{
public function sayWorld()
echo'World';
}
}
class MyHelloWorld{
use Hello,World;
public function sayExclamationMark(){
echo'!';
}
}
$o = new MyHelloWorld();
$o ->sayHello();
$o ->sayWorld();
$o ->sayExclamationMark();
?>
上面的代碼運行結果如(rú)下:
Hello World!
這裡(lǐ)的MyHelloWorld同時實現了兩個Traits,從(cóng)而使其可(kě)以分(fēn)别調用兩個Traits裡(lǐ)的代碼段。從(cóng)代碼中就(jiù)可(kě)以看(kàn)出,Traits和接口很像,不同的是Traits是可(kě)以導入包含代碼的接口。從(cóng)某種意義上來(lái)說(shuō),Traits和接口都(dōu)是對“多重繼承”的一種變相(xiàng)實現。
總結關于接口的幾個概念:
接口作(zuò)爲一種規範和契約存在。作(zuò)爲規範,接口應該保證可(kě)用性;作(zuò)爲契約,接口應該保證可(kě)控性。
接口隻是一個聲明,一旦使用interface關鍵字,就(jiù)應該實現它。可(kě)以由程序員(yuán)實現(外部接口),也可(kě)以由系統實現(内部接口)。接口本身(shēn)什麽都(dōu)不做,但(dàn)是它可(kě)以告訴我們它能做什麽。
PHP中的接口存在兩個不足,一是沒有契約限制,二是缺少足夠多的内部接口。
接口其實很簡單,但(dàn)是接口的各種應用很靈活,設計(jì)模式中也有很大(dà)一部分(fēn)是圍繞接口展開的。
本站(zhàn)文章(zhāng)爲深圳網站(zhàn)建設·源美網絡原創策劃,如(rú)有版權糾紛或者違規問(wèn)題,請(qǐng)聯系我們删除,謝謝!
上一篇: 電源裡(lǐ)的病毒
售後保障
承諾任何問(wèn)題1小時内解決數據備份
更安全、更高效、更穩定價格公道精準
項目經理(lǐ)精準報價不弄虛作(zuò)假合作(zuò)無風(fēng)險
重合同講信譽,無效全額退款