Maintaining code quality over time is a hard challenge. It becomes even harder in large projects developed by many programmers. Each person has different code styles and different ways to approach problems. Over time, this may result in confusing and unmaintainable code.
Static analysis tools can help developers solve this problem, they enforce coding standards, detect common errors and cleanup code blocks.
In this blog post I will take a look at the common code standards and tools used in PHP and show you how they can improve code quality and maintainability when integrated in the development process.
These are all tools you can start using today for free.
Make sure to check them for your PHP development.
Which tool should you choose? Let's try to answer this question.
1: Code Sniffer
Code Sniffer is arguably the most popular tool to enforce a strict style guide in your PHP code. It ships with support for popular coding standards such as PSR2, Zend, PEAR among others. The PSR standard family is used by most people nowadays because it was created by the FIG group so if you are looking for a standard to adopt, PSR2 is a good option. Code Sniffer also allows you to create your own coding standard. In most cases this won't be necessary, but if you are feeling adventurous you can take a look at the documentation.
Here is an example of the output generated by Code Sniffer
$ phpcs tests.php --report-full --standard=PSR2 FILE: tests.php -------------------------------------------------------------------------- FOUND 7 ERRORS AND 2 WARNINGS AFFECTING 6 LINES -------------------------------------------------------------------------- 2 | WARNING | [ ] Line exceeds 120 characters; contains 128 characters 3 | WARNING | [ ] Line exceeds 120 characters; contains 139 characters 8 | ERROR | [ ] Each class must be in a namespace of at least one leve 8 | ERROR | [ ] Class name "foo_foo" is not in camel caps format 16 | ERROR | [ ] Method name "foo_foo::bar_bar" is not in camel caps 23 | ERROR | [ ] Each class must be in a file by itself 23 | ERROR | [ ] Each class must be in a namespace of at least one leve 33 | ERROR | [x] Expected 1 newline at end of file; 0 found 33 | ERROR | [x] A closing tag is not permitted at the end of a file -------------------------------------------------------------------------- PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY --------------------------------------------------------------------------
As you can see, Code Sniffer shows you a detailed summary of the detected code violations. There are several output formats, so if you want a less human-readable report for parsing purposes you can output XML or CSV data. Recently they even introduced an option to output a blame report showing the percentage of errors introduced by each developer.
Although Code Sniffer can also prevent some common semantic errors, its main focus is enforcing code standards. There are other tools out there with better support for semantic error detection, but none can beat Code Sniffer when it comes to strictly following a code standard.
Analyses code complexity and warns you if your project is starting to become unmanageable. You can define thresholds for maximum class length, method length, cyclomatic complexity, etc.
Detects software design related issues, such as the use of
exit, excessive coupling, etc.
Ensures that your variables, class names and method names are appropriate (not too long, nor too short). Using good names is crucial for the person reading your code, so you should not underestimate this analysis.
A few rules about naming conventions and other best practices that do not apply to every project
Detects blocks of unused code that should be cleaned
Here is an example of PHPMD's output:
$ phpmd tests.php text ruleset tests.php:8 The class foo_foo is not named in CamelCase. tests.php:8 The property $my_property is not named in camelCase. tests.php:16 Avoid unused parameters such as '$arg1'. tests.php:16 Avoid unused parameters such as '$arg2'. tests.php:16 bar_bar accesses the super-global variable $_POST. tests.php:16 The method bar_bar is not named in camelCase. tests.php:19 Avoid unused local variables such as '$some_name'. tests.php:27 The method barBar has 11 parameters. Consider to reduce parameter number under 10. tests.php:29 Avoid unused local variables such as '$someName'.
ruleset is a XML file which contains a list of inspections that you want to enable. You can include any of the 5 main categories and even specify which rules should be used within these categories. For more information about how to create this file you can check the documentation.
Overall, PHPMD is a highly customisable static analyser. Although it does not enforce a specific code standard, you can use it to clean your code, detect possible bugs and manage the complexity of your project.
3: PHP Copy/Paste Detector
PHPCPD is a small tool created by Sebastian Bergmann to detect clones in your project. Here is a short example:
$phpcpd . phpcpd 2.0.1 by Sebastian Bergmann. Found 1 exact clones with 19 duplicated lines in 2 files: - foo.php:9-28 bar.php:18-37 1.32% duplicated lines out of 1439 total lines of code. Time: 21 ms, Memory: 2.50Mb
You can control the verbosity of the output and the minimum number of lines/tokens that are considered a clone.
Repeated code hides repeated bugs, therefore you should keep the percentage of duplicated lines as low as possible by refactoring the clones into a single method or class.
4: Automatic code fix
Some tools go beyond error detection and try to automatically patch the code for you.
PHP Coding Standards Fixer suggests fixes according to the coding standard you specified. The following example lists the problems found in two files:
$ php-cs-fixer fix --dry-run . --level=psr2 1) foo.php (php_closing_tag, eof_ending) 2) bar.php (braces, function_declaration, eof_ending)
PHPCBF is a script that can also fix some errors automatically for you. It ships with the latest version of Code Sniffer and you can run it simply like this:
$ phpcbf --standard=PSR2 tests.php Patched 2 files
There are other tools worth checking that I would like to mention. The first one is PHPDepend, which generates an impressive set of metrics from your project code: package dependencies, cyclomatic complexity, coupling, etc. You can easily detect parts of your application that need to be refactored with this.
PHPLOC also shows interesting statistics about your project. It is not as powerful as PHPDepend, but you can also get an interesting overview of your code size, complexity, number of classes, etc.
Finally, there is Security Advisory Checker. This tool from Sensio Labs checks for security vulnerabilities in Composer dependencies. It matches your
composer.lock file against a database with known security vulnerabilities and alerts you if an issue is found.
Which one should I choose?
Ultimately, this is a personal choice depending on the needs of the project you are working on. You probably want to combine more than one tool to cover a wide range of possible errors and to ensure that your code remains clean and consistent. For example, you can configure Code Sniffer with your style guide and use it along with PHP Mess Detector. This will enforce consistency and, at the same time, it will detect hot spots on your project: unusually complex code, unused code sections, short variable names , etc. On the top of that you can always add other tools to complement the analysis, such as copy paste detector for example.
To take the most out of static analysis you need to integrate it into your development cycle. If you use the tools independently you will forget about them after some time. There are several ways to do this.
Directly into the IDE
Some editors, such as PHP Storm or Sublime Text, already have plugins that support static analysis tools. After you install and configure everything you will receive warnings and suggestions as you type. This will avoid later bug fixes because it will make you write better code from the start.
If your IDE does not support your preferred tools, of if you want stricter rules regarding commits that do not adhere to your specification, you can write a pre-commit hook in git. With this solution you can automatically abort the commit process if errors are found during the analysis.
Finally, if you want a simple way to analyse your code without having to manually configure everything locally, you can use an online code review service such as Codacy (shameless plug here). We already integrate some of the mentioned detection tools in this article and we are working everyday to improve the service. The other main benefit of using a tool like Codacy is to allow you to monitor issues through time and to detect new and fixed issues one commit at a time
PHP has an impressive set of good tools to statically analyse your code and guide you through development. You can enforce strict standards, manage complexity and detect semantic problems, which is undeniably a great help to tackle the maintainability issue of large software projects. If your team is developing in PHP without any of this, you should give it a try. Let me know how it goes in the comments.