Howto create custom rule sets for PHPMD
In this blog post I will describe a useful feature in PHPMD that will simplify your life when it comes to create custom rule sets for PHPMD. PHPMD can be seen as an one level down/low level equivalent to PHP_CodeSniffer. It is a simple command line tool that can be used to check your application's source code for possible bugs, suboptimal or overcomplicated code. The current release of PHPMD ships with three default rule sets. The first set of rules tests the [codesize](Code Size Rules) of class, methods and functions. The second rule set contains rules that check your code for [unused](Unused Code Rules) variables, methods etc. and finally there is a rule set that tests the code against some [naming](Naming Rules ) conventions.
Normally when you start using a quality assurance tool, you will not want to use it's default configuration. Sometimes you would like to use only a subset, because the full stack will produce too much noise, or you would like to customize some thresholds, because the factory defaults do not fit to your environment. In this blog post I give a short introduction into PHPMD's rule set syntax and howto to create your own rule set, by reusing parts of the existing default configuration.
If you would like to only pick some of the rules that come with PHPMD and you want to customize some of the predefined thresholds, you can do this by creating your own rule set file that references a custom collection of rules with an individual configuration.
Starting with an empty ruleset.xml file
The simpliest way to start with a new rule set is to copy one of the existing files and remove all the rule-tags from the document body. Otherwise you can use the following example as a template for your own rule set file. You should change the content of the @name
attribute and <description />
element to something that describes the purpose of this set.
<?xml version="1.0"?>
<ruleset name="My first PHPMD rule set"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="
http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>
My custom rule set that checks my code...
</description>
</ruleset>
Adding rule references to the new ruleset.xml file
The first thing we would like to do is to add all unused code rules to the new rule set file. This can simply be done with a <rule />
element that references the entire unused code rule set that comes with PHPMD.
<?xml version="1.0"?>
<ruleset name="My first PHPMD rule set"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="
http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>
My custom rule set that checks my code...
</description>
<!-- Import the entire unused code rule set -->
<rule ref="rulesets/unusedcode.xml" />
</ruleset>
That's it. Now the custom rule set applies all unused code rules against the analyzed source code.
We would also like to use the cyclomatic complexity rule from the existing codesize set in our custom rule set. To achieve this we can reuse the same syntax with a <rule />
element and a @ref
attribute.
<?xml version="1.0"?>
<ruleset name="My first PHPMD rule set"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="
http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>
My custom rule set that checks my code...
</description>
<!-- Import the entire unused code rule set -->
<rule ref="rulesets/unusedcode.xml" />
<!-- Import the entire cyclomatic complexity rule -->
<rule ref="rulesets/codesize.xml/CyclomaticComplexity" />
</ruleset>
Now that the new rule set uses the cyclomatic complexity rule we would also like to customize some of the rule's properties. First we will increase the rule's priority to the highest possible priority value 1
and we also decrease the threshold when the rule reports a violation. This customization can be done with same xml elements that are used to configure the original rule, so that you can take a look at one of the original rule set file.
<?xml version="1.0"?>
<ruleset name="My first PHPMD rule set"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="
http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>
My custom rule set that checks my code...
</description>
<!-- Import the entire unused code rule set -->
<rule ref="rulesets/unusedcode.xml" />
<!--
Import the entire cyclomatic complexity rule and
customize the rule configuration.
-->
<rule ref="rulesets/codesize.xml/CyclomaticComplexity">
<priority>1</priority>
<properties>
<property name="reportLevel" value="5" />
</properties>
</rule>
</ruleset>
You should know that PHPMD handles all custom settings additive. This means that PHPMD keeps the original configuration for every setting that isn't customized in a rule reference.
Excluding rules from a rule set
Finally we would like to reuse the naming rule set of PHPMD. But we don't like the two variable naming rules, so that we must exclude them from out rule set file. This exclusion can be achieved by declaring an <exclude />
element within the rule reference. This element has an attribute @name
which specifies the name of the excluded rule.
<?xml version="1.0"?>
<ruleset name="My first PHPMD rule set"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="
http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>
My custom rule set that checks my code...
</description>
<!-- Import the entire unused code rule set -->
<rule ref="rulesets/unusedcode.xml" />
<!--
Import the entire cyclomatic complexity rule and
customize the rule configuration.
-->
<rule ref="rulesets/codesize.xml/CyclomaticComplexity">
<priority>1</priority>
<properties>
<property name="reportLevel" value="5" />
</properties>
</rule>
<!-- Import entire naming rule set and exclude rules -->
<rule ref="rulesets/naming.xml">
<exclude name="ShortVariable" />
<exclude name="LongVariable" />
</rule>
</ruleset>
Conclusion
With PHPMD's rule set syntax it is possible to customize all aspects of rules for your own needs and you can reuse every existing rule set xml file in your own set. You should take a look at PHPMD's rule documentation if it happens that you don't know what rules exist or you don't know exactly, which settings are available for one rule, while you create your own set of rules. Another good source of information are the rule set files that are shipped with PHPMD.
You can get the latest PHPMD version from its PEAR channel: pear.phpmd.org
mapi@arwen ~ $ pear channel-discover pear.pdepend.org
mapi@arwen ~ $ pear channel-discover pear.phpmd.org
mapi@arwen ~ $ pear install --alldeps phpmd/PHP_PMD-alpha
Or from our github repository:
mapi@arwen ~ $ git clone git://github.com/manuelpichler/phpmd.git
I would be glad if you file a ticket in PHPMD's issue tracker for all issues and/or enhancements you encounter while testing PHPMD.