今天不寫code,來看看怎樣利用一些工具來檢測PHP原始碼的品質。
自己比較常拿來參考的metric,除了coding style之外,常用的有LOC(lines of code)、CCN(Cyclomatic Complexity Number)等,就來看看這些工具怎麼用...其實都還蠻簡單的。
參考:
首先來安裝一下PDepend。PDepend現在也支援使用composer安裝,只要在require-dev中加上一條:"pdepend/pdepend":"版本"就可以,例如:
{
"require":{
},
"require-dev": {
"phpunit/phpunit":"~3.7.5",
"phpunit/php-invoker":"~1.1.0",
"phpunit/phpunit-selenium":"~1.3.2",
"pdepend/pdepend":"~1.1"
}
}
修改過composer.json之後,執行composer update就可以安裝好。不過安裝完之後,pdepend的執行檔會放在vendor目錄中,為了方便執行,可以做一下ln:
> ln -s vendor/pdepend/pdepend/src/bin/pdepend
然後就可以執行。首先來執行所有的測試,然後產出xml格式的報表:
Feng-Hsu-Pingteki-MacBook-Air:2-3a fillano$ ./pdepend --summary-xml=result.xml ~/Dropbox/Shared/b2c/src/class/GLF
PHP_Depend @package_version@ by Manuel Pichler
Parsing source files:
.......... 10
Executing CyclomaticComplexity-Analyzer:
... 64
Executing ClassLevel-Analyzer:
.. 55
Executing CodeRank-Analyzer:
14
Executing Cohesion-Analyzer:
.... 90
Executing Coupling-Analyzer:
... 68
Executing Hierarchy-Analyzer:
.. 58
Executing Inheritance-Analyzer:
18
Executing NPathComplexity-Analyzer:
... 64
Executing NodeCount-Analyzer:
.. 44
Executing NodeLoc-Analyzer:
.. 54
Generating pdepend log files, this may take a moment.
Time: 00:01; Memory: 11.75Mb
然後就會產出result.xml檔:
<?xml version="1.0" encoding="UTF-8"?>
<metrics generated="2013-10-16T22:23:22" pdepend="@package_version@" ahh="0.4" andc="0.44444444444444" calls="100" ccn="79" ccn2="81" cloc="116" clsa="0" clsc="9" eloc="550" fanout="3" leafs="7" lloc="342" loc="714" maxDIT="1" ncloc="598" noc="9" nof="0" noi="1" nom="30" nop="4" roots="2">
<files>
<file name="/Users/fillano/Dropbox/Shared/b2c/src/class/GLF/Acl/AclChecker.php" cloc="7" eloc="13" lloc="8" loc="23" ncloc="16"/>
<file name="/Users/fillano/Dropbox/Shared/b2c/src/class/GLF/Acl/AclRuleLogin.php" cloc="7" eloc="12" lloc="7" loc="21" ncloc="14"/>
<file name="/Users/fillano/Dropbox/Shared/b2c/src/class/GLF/Base/EventEmitter.php" cloc="13" eloc="20" lloc="12" loc="35" ncloc="22"/>
<file name="/Users/fillano/Dropbox/Shared/b2c/src/class/GLF/Controllers/Index.php" cloc="13" eloc="34" lloc="30" loc="56" ncloc="43"/>
<file name="/Users/fillano/Dropbox/Shared/b2c/src/class/GLF/Controllers/Shop.php" cloc="31" eloc="212" lloc="122" loc="252" ncloc="221"/>
<file name="/Users/fillano/Dropbox/Shared/b2c/src/class/GLF/Controllers/ViewCourses.php" cloc="13" eloc="159" lloc="96" loc="187" ncloc="174"/>
<file name="/Users/fillano/Dropbox/Shared/b2c/src/class/GLF/Web/Controller.php" cloc="11" eloc="62" lloc="40" loc="76" ncloc="65"/>
<file name="/Users/fillano/Dropbox/Shared/b2c/src/class/GLF/Web/MysmartyView.php" cloc="7" eloc="19" lloc="13" loc="27" ncloc="20"/>
<file name="/Users/fillano/Dropbox/Shared/b2c/src/class/GLF/Web/View.php" cloc="7" eloc="13" lloc="9" loc="21" ncloc="14"/>
</files>
<package name="GLF\Acl" cr="0.15" noc="2" nof="0" noi="1" nom="6" rcr="0.15">
<class name="AclChecker" ca="0" cbo="0" ce="0" cis="2" cloc="0" cr="0.15" csz="3" dit="0" eloc="8" impl="0" lloc="4" loc="11" ncloc="11" noam="0" nocc="0" nom="2" noom="0" npm="2" rcr="0.15" vars="1" varsi="1" varsnp="0" wmc="2" wmci="2" wmcnp="2">
<file name="/Users/fillano/Dropbox/Shared/b2c/src/class/GLF/Acl/AclChecker.php"/>
<method name="__construct" ccn="1" ccn2="1" cloc="0" eloc="3" lloc="1" loc="3" ncloc="3" npath="1"/>
<method name="check" ccn="1" ccn2="1" cloc="0" eloc="5" lloc="3" loc="5" ncloc="5" npath="1"/>
</class>
<class name="AclRuleLogin" ca="0" cbo="0" ce="0" cis="2" cloc="0" cr="0.15" csz="3" dit="0" eloc="7" impl="1" lloc="3" loc="10" ncloc="10" noam="0" nocc="0" nom="2" noom="0" npm="2" rcr="0.2775" vars="1" varsi="1" varsnp="0" wmc="2" wmci="2" wmcnp="2">
<file name="/Users/fillano/Dropbox/Shared/b2c/src/class/GLF/Acl/AclRuleLogin.php"/>
<method name="__construct" ccn="1" ccn2="1" cloc="0" eloc="3" lloc="1" loc="3" ncloc="3" npath="1"/>
<method name="check" ccn="1" ccn2="1" cloc="0" eloc="4" lloc="2" loc="4" ncloc="4" npath="1"/>
</class>
</package>
<package name="GLF\Base" cr="0.15" noc="1" nof="0" noi="0" nom="2" rcr="0.15">
<class name="EventEmitter" ca="0" cbo="0" ce="0" cis="2" cloc="0" cr="0.15" csz="3" dit="0" eloc="15" impl="0" lloc="8" loc="18" ncloc="18" noam="0" nocc="0" nom="2" noom="0" npm="2" rcr="0.15" vars="1" varsi="1" varsnp="0" wmc="5" wmci="5" wmcnp="5">
<file name="/Users/fillano/Dropbox/Shared/b2c/src/class/GLF/Base/EventEmitter.php"/>
<method name="on" ccn="2" ccn2="2" cloc="0" eloc="6" lloc="3" loc="6" ncloc="6" npath="2"/>
<method name="emit" ccn="3" ccn2="3" cloc="0" eloc="9" lloc="5" loc="9" ncloc="9" npath="3"/>
</class>
</package>
.....
每一個量測的mertic都是用簡稱,例如loc、ccn等,可以參考他的說明:http://pdepend.org/documentation/software-metrics/index.html
除了各個品質量測的資料,他也可以產出一些圖表,例如:
Feng-Hsu-Pingteki-MacBook-Air:2-3a fillano$ ./pdepend --overview-pyramid=result.svg ~/Dropbox/Shared/b2c/src/class/GLF
PHP_Depend @package_version@ by Manuel Pichler
Parsing source files:
.......... 10
Executing Coupling-Analyzer:
... 68
Executing CyclomaticComplexity-Analyzer:
... 64
Executing Inheritance-Analyzer:
18
Executing NodeCount-Analyzer:
.. 44
Executing NodeLoc-Analyzer:
.. 54
Generating pdepend log files, this may take a moment.
Time: 00:00; Memory: 11.50Mb
這樣就會把一些概要的品質量測數據圖以svg的格式輸出:
等等。
如果想直接抓出一些程式碼的缺陷,而不只是看到冷冰冰的數據....還有一些不錯的工具,例如PHP MESS Detector。他也可以透過Composer來安裝:
{
"require":{
},
"require-dev": {
"phpunit/phpunit":"~3.7.5",
"phpunit/php-invoker":"~1.1.0",
"phpunit/phpunit-selenium":"~1.3.2",
"pdepend/pdepend":"~1.1",
"phpmd/phpmd":"~1.5"
}
}
同樣透過composer update安裝好以後,把它link到方便執行的地方:
> ln -s vendor/phpmd/phpmd/src/bin/phpmd
然後就可以透過./phpmd來執行。他需要用三個參數:
執行後,結果會從stdout輸出,所以可以把它重導到檔案。例如想要輸出成html格式,指定用codesize規則集合,可以這樣執行:
Feng-Hsu-Pingteki-MacBook-Air:2-3a fillano$ ./phpmd ~/Dropbox/Shared/b2c/src/class/GLF html codesize > phpmd.html
然後可以用瀏覽器檢視輸出的結果:
指出的問題,也是一個超連結,指向phpmd文件中的說明:
例如在一個方法中,可能的執行路徑超過200,就會被指出有問題。這通常是程式邏輯比較複雜,容易發生錯誤,所以最好拆開或想辦法降低複雜度。
跟pdepend比較起來,phpmd更容易上手,而且他的說明很直接,如果對於這些品質量測不是那麼熟悉,phpmd應該會比較好用。
=====
除了這兩個工具,還有像是php code_sniffer可以找出程式碼違背coding standard的問題。php copy/paste detector可以檢查出程式碼中是否有使用copy/paste的地方,通常有這樣的問題,需要把重複的程式碼做成共用的函數或方法。通常更進一步改善的方式是做重構,不過這會需要花一些時間學習,而且最好要熟悉設計模式才容易下手執行就是了
偷偷測試一下...
<pre class="c" name="code">
<span style="color: green;">test</span>