在 PHP 中收集指标
在本节中,我们将介绍 PHP 世界中用于收集代码质量指标的工具。正如你即将看到的,这些指标不仅仅是数字,它们还能让你对重构代码所需的工作量做出有根据的猜测。它们还能帮助你确定代码中最需要关注的部分。
我们再次为你精选了一些工具:
-
phploc
-
PHP Depend
-
PhpMetrics
phploc
正如我们在上一节中了解到的,缩写 LOC 代表代码行数,因此这个名称已经揭示了这个工具的主要用途。作为一个基本指标,它已经告诉了我们关于代码库的很多信息。phploc
还提供了更多指标,如 CC,因此值得仔细研究一下。
安装和使用
该工具的作者 Sebastian Bergmann 因 phpunit
而闻名,phpunit 是 PHP 世界自动测试的事实标准。他建议不要使用 Composer 安装,而是直接使用 phar
。我们将在下一章讨论这种方法的利弊。现在,让我们听从作者的建议,直接下载 phar
:
$ wget https://phar.phpunit.de/phploc.phar
这将把最新版本的 phploc
下载到当前目录。下载完成后,我们就可以直接使用它来扫描项目了:
$ php phploc.phar src
前面的命令将扫描 src
文件夹及其所有子文件夹并收集相关信息,这些信息将直接显示在命令行中,如图 8.1 所示:

这比 LOC 的信息要多得多。这些信息分为以下几类:
-
规模:显然,该工具存在的主要原因是通过计算代码行数来衡量项目的规模,我们在上一节介绍了几种计算方法。重点在于 LLOC,你将得到每个类、类方法和函数的平均值。
-
CC:phploc 将计算每个 LLOC、类和方法的平均 CC 值。
-
依赖关系:这部分将告诉你有多少次对全局状态的访问,以及有多少次对属性和方法的静态访问。全局访问和静态访问都被认为是应避免的做法,因此这些数字能为你提供有关代码质量的更多提示。
-
结构:在最后一个输出部分(前面的截图中没有),phploc 会返回代码结构的更多细节。如何解释它们并没有明确的规则;不过,你可以从中得出一些结论。例如,请看下面的内容:
-
关于整体代码大小,使用了多少命名空间?如果代码量很大,但命名空间却很少,说明项目结构不完善。
-
是否使用了接口,与项目规模相比使用了多少接口?接口的使用增加了类之间的互换性,表明代码结构良好。
-
以上就是我们目前需要了解的 phploc
功能。它是一个简单易用但很有帮助的工具,可以帮助你快速掌握项目的整体代码质量和结构,因此应该成为你工具包的一部分。不过,它不会告诉你如何解释这些数字,这需要一些经验。
PHP Depend
如果要评选在一个工具中集成最多指标的奖项,那么 PHP Depend (PDepend)
肯定会榜上有名。它涵盖了我们在上一节中讨论过的所有指标,还有更多。不过,它并不是最方便用户使用的工具。另外,网站和资源库文档也不完善。尽管如此,你还是应该看看它。
安装和使用
和以前一样,可以使用 Composer 或直接下载 phar
安装该工具。我们将暂时采用基于 Composer 的安装方式:
$ composer require pdepend/pdepend --dev
如果没有不愉快的意外,就可以直接执行:
$ vendor/bin/pdepend --summary-xml=pdepend_summary.xml src
在这里,我们已经可以看出 PDepend 的祖先是 Java 代码质量工具 JDepend,因为输出结果被写入了一个 XML 文件。文件名使用 --summary-xml
选项指定。此外,我们还必须指定要扫描的文件夹作为参数。
不过,PDepend
确实会输出一些数字,下面的输出示例就说明了这一点:
PDepend 2.10.3
Parsing source files:
............................................... 47
Calculating Cyclomatic Complexity metrics:
................. 355
Calculating Node Loc metrics:
............. 279
Calculating NPath Complexity metrics:
................. 355
Calculating Inheritance metrics:
..... 101
这里我们跳过了一些行。这些数字只会告诉你每个指标在给定文件夹中的计算频率,因此直接输出并没有什么特别的帮助。要查看实际指标,我们需要打开 XML 报告。在我们的案例中,生成的文件名为 pdepend_summary.xml
。
XML 报告非常庞大,无法在本书中打印出来,所以你最好自己尝试一下,看看它的全貌。不过,我们可以向你展示它的结构:
<?xml version="1.0" encoding="UTF-8"?>
<metrics>
<files>
<file name="/path/to/Namespace/Classname.php"/>
<!-- ... -->
</files>
<package name="Namespace">
<class name="Classname" fqname="Namespace\Classname">
<file name="/path/to/Namespace/Classname.php"/>
<method name="methodName"/>
<!-- ... -->
</class>
<!-- ... -->
</package>
</metrics>
<metrics>
节点表示完整扫描过的目录。它有以下子节点:
-
<files>
,列出使用<file>
子节点扫描的所有文件。 -
<package>
,列出所有命名空间。在这个节点中,还有<class>
子节点。每个类都有一个<method>
节点列表,类中的每个方法都有一个节点。最后,在另一个<file>
节点中提到了类的文件名。
当然,这并不是 PDepend 生成的全部输出。对于每个节点,它都会添加数十个属性,其中包含计算指标的名称和值。这是根据 PDepend 源代码生成的 XML 报告中的一个节点示例:
<method name="setConfigurationFile" start="80" end="89"
ccn="2" ccn2="2" loc="10" cloc="0" eloc="8" lloc="3"
ncloc="10" npath="2" hnt="15" hnd="21"
hv="65.884761341681" hd="7.3125" hl="0.13675213675214"
he="481.78231731105" ht="26.765684295058"
hb="0.020485472371812" hi="9.0098818928795"
mi="67.295865328327"/>
你应该已经能够识别一些指标,如 lloc
(LOC)或 ccn
(CC 编号)。至于其它指标,你可以在在线文档 https://pdepend.org/documentation/softwaremetrics/index.html 中找到 XML 报告中缩写的解释或至少是长名称。
更多选项
PDepend 有两个你应该了解的选项:
-
--exclude
:这将从扫描中排除一个命名空间(在此术语中为软件包)。可以使用多个命名空间,以逗号分隔。确保在命名空间周围加上引号:$ vendor/bin/pdepend --summary-xml=pdepend_summary.xml --exclude="Your\Namespace,Another\Namespace" src
-
--ignore
:允许你忽略一个或多个文件夹。再次强调,不要忘记引号:$ vendor/bin/pdepend --summary-xml=pdepend_summary.xml --ignore="path/to/folder,path/to/other/folder" src
它还可以生成 SVG 格式的图像,并提供更多信息。不过我们不会在本书中介绍这些内容,因为有一个更好的工具可以实现这一功能,你将在下一节中找到它。
PDepend 功能强大,但同时也很难监督。生成的输出很难阅读,一旦项目稍大,就无法使用,除非使用其它工具解析 XML 文件。不过,也许有一天你会需要它提供的高级度量指标,或者你可能在某个项目中已经使用了它。所以,至少你现在已经做好了准备。
PHP指标
到目前为止,PHP 质量指标的世界还只是基于文本的。现在,这种情况将有所改变,因为我们现在将看到 PhpMetrics,它生成的报告更适合人眼,甚至可以交互。
安装和使用
让我们使用 Composer 将 PhpMetrics 添加到你的项目中:
$ composer require phpmetrics/phpmetrics --dev
下载完所有文件后,你就可以立即开始生成第一份报告了:
$ vendor/bin/phpmetrics --report-html=phpmetrics_report src
--report-html
选项指定了创建报告的文件夹。你可以用逗号分隔的列表指定多个要扫描的文件夹。但在我们的示例中,我们将只使用 src
文件夹。
因此,PhpMetrics 会列出一些统计数据,让你对代码有一些了解。图 8.2 显示了输出结果的摘录,这可能会让你想起 phploc
生成的输出结果:

要打开刚刚生成的 HTML 报告,只需在浏览器中打开该文件夹中的 index.html
文件即可。在仔细查看生成的报告之前,让我们先看看 PhpMetrics 还提供了哪些有用的选项:
-
--metrics:该选项将返回可用度量的列表。它有助于破译缩写,如 mIwoC。
-
--exclude:使用该选项,你可以指定一个或多个目录不被扫描。
-
--report-[csv|json|summary-json|violations]:允许以 HTML 以外的不同报告格式保存结果,例如:
--report-json
。
理解报告
如果你是第一次打开 PhpMetrics 报告,你会发现里面有各种各样的信息。我们不会深入研究每一个小细节,但会向你展示我们认为报告中最有价值的部分。
为了更好地说明 PhpMetrics 的用法,我们随机选择了一个名为 thephpleague/container
的现有开源软件包作为代码库。它是一个优秀的符合 PSR-11 标准的依赖注入容器,大小正好适合作为示例。图 8.3 显示了我们为其生成的示例报告的概览页面:

关键指标
左侧是菜单,可以进入报告的其它页面。页面上部有几个关键指标,其中最有趣的是:
-
通过代码行数可以进一步了解项目的规模。点击标签,你将进入另一个页面,那里有所有类的详细列表及其相关的大小指标,如 LOC。
-
违规显示了 PhpMetrics 发现的违规数量。同样,点击标签,你将进入另一个页面,那里有一个类及其违规行为的列表—例如,如果它们太复杂(方法代码太复杂),有很高的错误概率(可能有错误),或者使用了太多其它类或其它依赖(太依赖)。
-
按类划分的平均循环复杂度会告诉你它的真正含义。详细视图可为你提供更多有关类级别复杂性的信息。
其它方框也提供了有趣的信息,但前面的方框已经非常适合快速查看代码中最有问题的部分。
可维护性或复杂性
在关键指标下方,PhpMetrics 还显示了一个图表,你在第一次打开报告时肯定已经发现了:可维护性/复杂性 图表。它由项目中每个命名空间的彩色圆圈组成,圆圈的大小代表类的 CC。圆圈越大,复杂度越高。颜色表示可维护性指数,从绿色(高)到红色(低)不等。
如果将鼠标悬停在圆圈上,就可以看到圆圈所代表的命名空间以及这两个指标的详细信息:

这张图对于快速掌握整体代码质量非常有用—大红圈越少越好。这样,你就能轻松看到代码中存在问题的部分。
对象关系
从左侧菜单中选择 "对象关系" 时,会出现一个显示每个命名空间之间关系的图表。将鼠标指针悬停在文本标签上会突出显示其关系。该图表非常庞大,因此我们无法在本书中向你展示它的全貌,但至少可以给你一个初步印象:

耦合
类的耦合说明了它们如何相互依赖。有两个主要指标:
-
传入耦合(Ca)告诉你依赖于该类的类的数量。过多的依赖关系表明类对项目的重要性。
-
传出耦合(Ce)可让你了解一个类使用了多少个依赖项。该值越高,说明该类对其它类的依赖性越强。
面向包的指标
我们要向大家展示的最后一张图表是 "抽象性与不稳定性关系图"。顾名思义,它显示了软件包的抽象性与不稳定性之间的关系。它是由罗伯特-马丁(Robert Martin)根据他在面向对象度量方面的研究成果提出的。图 8.6 展示了一个示例:

但在软件开发中,这两个术语究竟是什么意思呢?让我们看看以下定义:
-
抽象性 (A) 是指抽象基类和接口与命名空间或软件包中所有类的数量之比。包中包含的抽象类型越多,变更就越容易,风险也越小。A 的范围从 0(具体)到 1(抽象)。
-
不稳定性 (I) 通过 Ce 与总 Ce 和 Ca 的比值(Ce + Ca)来表示一个软件包在变化面前的脆弱程度。换句话说,依赖关系越多,稳定性越差。I 的范围从 0(稳定)到 1(不稳定)。
马丁指出,稳定的、因此高度独立于其它类的软件包也应该具有较高的 A 值,反之亦然,不稳定的软件包应该由具体的类组成。因此,从理论上讲,一个类的 A 与它的 I 相加,即理想情况下,A 加 I 应为 1(A + I = 1)。这个等式也画出了从图表左上角到右下角的斜线。你应该努力使你的数据包靠近这条线。
在实际报告中,你会发现图表下方有一个表格,你可以在其中找到更详细的值。如果将鼠标指针悬停在圆圈上,会弹出一个窗口,告诉你圆圈代表的类的名称,以及 A(第一位数字)和 I(第二位数字)。