類似Javadoc的文檔
應(yīng)該有一種好的方法----如果你曾經(jīng)使用過(guò)Java語(yǔ)言,你將知道Javadoc文檔系統(tǒng)。這個(gè)工具允許你在源代碼文件注釋中插入一些標(biāo)記,這些標(biāo)記可以被Javadoc工具進(jìn)行分析以便生成一系列的HTML頁(yè)面把你的類文檔化。那樣在編程的同時(shí)你可以開著瀏覽器并且可以得到類列表和帶有說(shuō)明的類方法的列表。在你開發(fā)web應(yīng)用時(shí),這個(gè)可以成為你的參考,提高工作效率和加快開發(fā)速度。
我的意見(jiàn)是維護(hù)一個(gè)作為源代碼內(nèi)的引用文檔要比維護(hù)一個(gè)獨(dú)立的文檔要容易和更實(shí)用,因?yàn)檫@個(gè)方法更容易保持更新。否則就非常容易變得懶惰從而將對(duì)文檔的更新推后到無(wú)限期(如果一定要給它加個(gè)期限,我想是一萬(wàn)年)。相反使用象這樣的一個(gè)工具,只有一點(diǎn)工作量就是在你正在修改的源代碼附近更新一個(gè)標(biāo)記,接著運(yùn)行工具再一次生成更新過(guò)的HTML頁(yè)面。
一些php文檔工具的預(yù)覽
在對(duì)上面了解了之后,我搜索了一下哪些是可用的,并且我發(fā)現(xiàn)了如下一些有趣的工具:
phpSearchdoc是enzyme項(xiàng)目的一部分。因?yàn)閑nzyme 是一個(gè)巨大的項(xiàng)目,所以需要將其文檔化。那里的開發(fā)人員已經(jīng)編寫了他們自已的文檔系統(tǒng)并且他們非??犊貙⑵渥鳛橐粋€(gè)獨(dú)立的包進(jìn)行發(fā)布。得到的文檔首先被寫入數(shù)據(jù)庫(kù),然后可以被一些PHP腳本查看,象一個(gè)動(dòng)態(tài)的web站點(diǎn)。
從現(xiàn)存的信息中將用于分析的邏輯分離出來(lái)的想法相當(dāng)好,然而phpSearchdoc(版本 1.01)不具有一個(gè)真正的分析器,而是從源文件,甚至包括注釋中搜索關(guān)鍵字。事實(shí)上,對(duì)我來(lái)說(shuō)碰巧發(fā)生過(guò)在我的注釋中存在'function'單詞,結(jié)果分析器愚蠢地認(rèn)為在這個(gè)單詞后面的詞就是函數(shù)的名字。更不幸的是,我不巧在同一行放了一個(gè)單引號(hào)('),接著我試圖將數(shù)據(jù)寫到數(shù)據(jù)庫(kù)中,mysql作出了抱怨(出錯(cuò)了,因?yàn)閱我?hào)在 mysql中被用于分割字符串)。
而且它的安裝及運(yùn)行相當(dāng)困難,因?yàn)樗€是一個(gè)alpha測(cè)試版。畢竟比起文檔系統(tǒng)來(lái)說(shuō)它更象是一個(gè)交叉引用生成器,正如我知道的,你不能在函數(shù)和方法中加入自已的注釋。
phpxref,就象名字所指的比起一個(gè)真正 的文檔系統(tǒng)來(lái)似乎更象是面向交叉引用的生成處理。更進(jìn)一步說(shuō)它更適合于正常的過(guò)程化編程而不是面向?qū)ο缶幊獭?
phpautodoc的目標(biāo)是實(shí)現(xiàn)象Javadoc 應(yīng)用于Java那樣用于PHP。它看上去是滿足我的文檔需求的完美解決。為了試驗(yàn)它我不得不編譯了PHP的CGI版本(我通常使用模塊版本),因?yàn)樯善魇怯肞HP編的。我可能容易地在一個(gè)Linux系統(tǒng)下編譯和安裝靜態(tài)的執(zhí)行程序,可以使用這些命令:
rm config.chche
make clean
./configure
make
cp php /usr/local/bin
我決定對(duì)它自已的PHP源碼進(jìn)行測(cè)試,并且我發(fā)現(xiàn)它只有部分可以工作:它只能夠生成類的文檔(生成整齊的格式),但是不能生成小結(jié)。我不知道是否這個(gè)只是碰巧發(fā)生在我的機(jī)器上,但是在試圖生成小結(jié)時(shí)卻因?yàn)閏ore dump(內(nèi)核崩潰)而停止(PHP 4.0 pl2,RedHat 6.2環(huán)境)。假如在你的機(jī)器/usr/local/bin下安裝了PHP執(zhí)行版本,調(diào)用它的語(yǔ)法是(為了得到結(jié)果我不得不給出php文件和輸出目錄的全路徑)
./phpautodoc -o
phpdoc是一個(gè)用來(lái)維護(hù)在Web站點(diǎn)上的php 文件,并且它非常適合分布式開發(fā)方式。文檔是從數(shù)據(jù)庫(kù)中生成;在安裝之后,你可以使用web界面來(lái)增加你的類將其文檔化。這個(gè)的確有意思,但是它是一種低級(jí)的從源代碼中分離文檔的維護(hù)方法,這一點(diǎn)就我來(lái)說(shuō)不是非常方便。
通用工具
在經(jīng)受了試驗(yàn)所有這些工具但卻得不到怎么成功的挫折之后,直到Pear Project提出了一種標(biāo)準(zhǔn)的解決方法,我發(fā)現(xiàn)了一個(gè)與PHP完全無(wú)關(guān)的可工作的工具在Open Source Projects at Apple站點(diǎn)。項(xiàng)目的名字是 HeaderDoc。就象站點(diǎn)所說(shuō)的" HeaderDoc是一種從C或C++頭文件的注釋中生成HTML的引用文檔的工具。它是用Perl編寫的以便于移植。與JavaDoc 相似,它允許開發(fā)者容易地文檔化他們的接口,并且將接口信息輸出到HTML。"
是的,你看的沒(méi)錯(cuò),HeaderDoc只支持C和C++。沒(méi)有其它的語(yǔ)言,但是它不象JavaDoc,它大部分依賴寫在注釋中的標(biāo)記,所以只要做些小改動(dòng)(我會(huì)在后面解釋)就可以很好的用在PHP上。這些標(biāo)記同JavaDoc很象,HeaderDoc標(biāo)記的一些例子是@class,@function和@var。
文檔化一個(gè)類
OK,讓我們現(xiàn)在進(jìn)入細(xì)節(jié)吧。首先讓我們看一下一個(gè)類如何被文檔化。
--------------------------------------------------------------------------------
/*! @class BagItem
@abstract An item in the shopping bag - it is a shopitem with quantity
@discussion A BagItem object may be constructed without previous
instantiation of neither ShopItem nor Product
*/
--------------------------------------------------------------------------------
文檔化一個(gè)類??梢栽谧筮叺膸x擇類的方法。
第一件需要注意的事情是用在打開注釋上的風(fēng)格不完全象JavaDoc注釋/**(一個(gè)斜線和兩個(gè)星號(hào)),而是換成/*!(一個(gè)斜線,一個(gè)星號(hào)和一個(gè)感嘆號(hào)) 。標(biāo)記使用也不一樣,但是它們以相似的方式工作。例如,第一個(gè)標(biāo)記是@class標(biāo)記,它用于文檔化一個(gè)類,這個(gè)標(biāo)記跟著類的名字。下一個(gè)標(biāo)記是@abstract 標(biāo)記,它
是一個(gè)可選的標(biāo)記,用少量詞語(yǔ)來(lái)描述一個(gè)類的含義,同時(shí)@discussion 標(biāo)記是另一個(gè)可選的標(biāo)記,用于進(jìn)一步的討論。當(dāng)然由你來(lái)決定是在@discussion標(biāo)記中描述所有的事情還是使用@abstract來(lái)處理,但是要記住,一般來(lái)說(shuō),你使用的標(biāo)記越精確,結(jié)果就越好。
文檔化函數(shù)或方法
成員函數(shù)或方法使用@function標(biāo)記被文檔化。
--------------------------------------------------------------------------------
/*! @function getItemingroup
@abstract gets a bagitem of a given group and a given position
@param groupno int - the delivery group ordinal position in the bag
@param pos int - the position of the bagitem within the group
@result Object - the BagItem in a given position of given group
or -1 if it could not be found
*/
--------------------------------------------------------------------------------
文檔化一個(gè)方法。
@function標(biāo)記聲明了一個(gè)函數(shù)并且后面跟著函數(shù)或成員函數(shù)名。然后你可以象前面一樣使用 @abstract和@discussion標(biāo)記。然而還有兩個(gè)額外的標(biāo)記。@param標(biāo)記用于描述函數(shù)的參數(shù);第一個(gè)詞假設(shè)為變量的名字,其它的則為任意的文本描述。我建議要聲明想要的變量類型,盡管PHP不是一個(gè)強(qiáng)類型語(yǔ)言。 @result標(biāo)記被用于描述返回值。
文檔化變量
變量或類變量都使用@var標(biāo)記來(lái)描述。在這個(gè)標(biāo)記中,第一個(gè)詞被認(rèn)為是變量的名字,同時(shí)其它的則為任意的文本描述。象前面一樣,我建議寫出所期望的變量類型是好的做法。它也是一個(gè)文檔化所有類變量的好主意。
文檔化一個(gè)類變量。
--------------------------------------------------------------------------------
/*! @var idsession string - an unique session identifier */
var $idsession;
--------------------------------------------------------------------------------
最后接觸
--------------------------------------------------------------------------------
/*! @header myprojectname
@abstract a virtual store to shop on mars
@discussion The difference [...]
*/
--------------------------------------------------------------------------------
@header標(biāo)記用來(lái)提供一些關(guān)于被文檔化的項(xiàng)目或類組的一般性信息。@header標(biāo)記本身跟著項(xiàng)目的名字 ,而且可以用@abstract標(biāo)記和@discussion標(biāo)記來(lái)補(bǔ)充說(shuō)明。因?yàn)轭愅ǔ4嬖谟诓煌奈募校ㄒ粋€(gè)文件一個(gè)類,且用類的名字給文件名字是一種好的想法),你可能想知道應(yīng)該將@header 標(biāo)記放在什么地方。答案很讓人吃驚,哪都可以。我的建議是:如果它比較長(zhǎng)就把它放在一個(gè)獨(dú)立的文件中,或如果是一個(gè)簡(jiǎn)短的說(shuō)明就把它放在最重要的類的前面。
如何修改腳本用于PHP
從Apple得到的初始的HeaderDoc腳本是用于C或C++頭文件的,所以要用在PHP中需要對(duì)它做一些小改動(dòng) 。如果你對(duì)細(xì)節(jié)沒(méi)有興趣,你可以從這里下 載,并且跳過(guò)下面部分。
修改源程序所做的唯一的事情就是在主perl文件中,使腳本可以接受.php和.php3后綴。
--------------------------------------------------------------------------------
$ diff headerDoc2HTML.pl /usr/local/bin/headerdoc2html
195c195
< ($rootFileName = $filename) =~ s/.(h|i)$//;
---
> ($rootFileName = $filename) =~ s/.(h|i|php|php3)$//;
--------------------------------------------------------------------------------
運(yùn)行腳本
在安裝完腳本之后,假設(shè)你的類放在classes子目錄下,并且你想將生成的文檔放在docs目錄下,你應(yīng)該執(zhí)行這個(gè)命令:
headerdoc2html -o docs classes/*.php
不幸的是如果存在多個(gè)PHP文件,這個(gè)腳本有一個(gè)壞習(xí)慣就是將那些文件分割到不同的目錄中去,使得在類的文檔中瀏覽變得很困難。而且因?yàn)槌跏嫉哪_本是為C/C++頭文件所寫的(頭文件中只有類和函數(shù)的聲明而沒(méi)有他們的定義),腳本會(huì)將函數(shù)名下的所有代碼輸出,直到碰到";",所以典型的就是代碼的第一行。
但是在你好不容易讀到現(xiàn)在卻感到絕望之前,放松,因?yàn)槲覍懥艘欢魏?jiǎn)單的腳本來(lái)解決這兩個(gè)問(wèn)題。
--------------------------------------------------------------------------------
cat classes/*.php | sed 's/ *{/;#{/g' | tr "#" "
" > docs/all.php
headerdoc2html -o docs docs/all.php
rm docs/all.php
--------------------------------------------------------------------------------
如果你想知道為什么我在這里使用tr命令而不是都用sed來(lái)做,原因就是用在仍然用在RedHat 6.2上的sed 3.02版本不處理?yè)Q行符。應(yīng)該替換成新的版本sed 3.02a。如果你對(duì)sed感興趣,可以看SED FAQ。
祝你的文檔化工作好運(yùn)!
翻譯后話:
由于這篇文章是在Linux環(huán)境下使用的,所以在windows下的使用可能會(huì)有問(wèn)題。
新聞熱點(diǎn)
疑難解答
網(wǎng)友關(guān)注