Static analysis of PHP code using open-source code quality tools
While it does not replace good judgement and programming practice completely, it can be interesting to perform regular code quality analyses to make sure that your teams (and students) are writing good PHP code. This is a small guide on how to install them in macOS and how to use them to automatically produce metrics for all code repositories in a folder.
This is intended as a very short guide on how to perform static code analysis on projects that are not under Git source code control, with minimal configuration and without relying on a CI/CD solution. For those other cases, I recommend Codacy and Travis.CI. I have been using these myself for years and I think they are great!
Installing prerequisites
Before installing the tools themselves, you may have to install some supporting software in your Mac. If you already have these installed, please move on to the tool installation section.
Homebrew
First install Homebrew, the missing package manager for macOS.
1
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Install PHP using Homebrew
Here I am installing PHP 7.2, which is the same version used at FEUP servers. Changing the PHP version may be necessary as some of the tools may throw fatal errors if you are running an old version of PHP (like I was before I forced the system to use 7.2).
1
brew install php@7.2
To use this version of PHP instead of whatever you have installed in your system (5.3 on Sierra, which is very old but what I have), you need to add the following to your ~/.zshrc
file (if you use zsh
) or ~/.bash_profile
(if you use bash
).
1
2
export PATH="/usr/local/opt/php@7.2/bin:$PATH"
export PATH="/usr/local/opt/php@7.2/sbin:$PATH"
Check your PHP version:
1
2
3
4
5
6
joaorocha at modo in ~
$ php --version
PHP 7.2.26 (cli) (built: Jan 3 2020 18:47:49) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.26, Copyright (c) 1999-2018, by Zend Technologies
Install PHP Composer
1
brew install composer
Check your Composer version:
1
2
3
joaorocha at modo in ~
$ composer --version
Composer version 1.9.1 2019-11-01 17:20:17
Installing the tools
We are going to target 3 types of analyses: Detection of duplicates, size and complexity of code without considering OOP metrics, and detailed analysis of OOP structure in PHP.
Detecting Copy-Pastes (duplicate code)
An interesting tool to detect copy pasted code is PHP Copy/Paste Detector (PHPCPD).
Let’s install it:
1
composer global require sebastian/phpcpd
And run it:
1
phpcpd --fuzzy /folder/you/want/to/analyse
Getting code quality metrics (Generic)
phploc is a tool for quickly measuring the size and analyzing the structure of a PHP project.
Let’s install it:
1
composer global require phploc/phploc
And run it:
1
phploc /path/to/your/sources
Getting code quality metrics (OOP)
Another interesting open-source tool is PHPMetrics. It produces some nice HTML reports, with support for color blind people too!
According to the authors, PhpMetrics is intended for projects with usages of packages, namespaces, classes, interfaces, and other structures like that.
.
Let’s install it:
1
composer global require 'phpmetrics/phpmetrics'
The composer executables may not be added to your path by default. Let’s fix that by adding the following line to your ~/.zshrc
file (if you use zsh
) or ~/.bash_profile
(if you use bash
):
1
export PATH=$PATH:~/.composer/vendor/bin
And run the command:
1
phpmetrics --report-html=myreport.html /path/of/your/sources
Putting it all together
Here is a script to perform all the analyses shown before, and place the results in a neat folder called output
beside your source folders. For every folder, the script will run these utilities and produce a subfolder with the results of every single one.
Create a new file called evaluate.sh
in the folder that contains the subfolders that you want to analyse and copy and paste the following lines.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/env bash
NUMBER_OF_LINES_CONSIDERED_COPY_PASTE=2
MIN_TOKENS_CONSIDERED_COPY_PASTE=15
OUTPUT_DIR=$(pwd)/output
# exclude hidden directories
shopt -s dotglob
# delete existing results if they exist
if [[ -d "$OUTPUT_DIR" ]]; then
rm -rf "$OUTPUT_DIR"
fi
# for every folder
for subfolder in */ ; do
echo "####################################################"
echo "Analysing $subfolder ..."
echo "####################################################"
SUBFOLDER_NAME=$(basename "$subfolder")
RESULTS_SUBDIR="$OUTPUT_DIR/$SUBFOLDER_NAME"
if [[ ! -d "$RESULTS_SUBDIR" ]]; then
mkdir -p "$RESULTS_SUBDIR"
fi
# run phpcpd
phpcpd --min-tokens="$MIN_TOKENS_CONSIDERED_COPY_PASTE" --min-lines="$NUMBER_OF_LINES_CONSIDERED_COPY_PASTE" --fuzzy "$subfolder" > "$RESULTS_SUBDIR/phpcpd.txt"
# run phploc
phploc "$subfolder" > "$RESULTS_SUBDIR/phploc.txt"
#run phpmetrics
phpmetrics --report-html="$RESULTS_SUBDIR/phpmetrics" "$subfolder"
done
To get the results, cd
to the previously mentioned folder, and make the script executable with chmod +x evaluate.sh
and run it using ./evaluate.sh
.
Results
You will get something like this.
Output folder and file structure
Copy-paste detection
phpcpd 4.1.0 by Sebastian Bergmann.
No clones found.
Time: 35 ms, Memory: 4.00MB
Code-related statistics
phploc 5.0.0 by Sebastian Bergmann.
Size
Lines of Code (LOC) 1948
Comment Lines of Code (CLOC) 43 (2.21%)
Non-Comment Lines of Code (NCLOC) 1905 (97.79%)
Logical Lines of Code (LLOC) 627 (32.19%)
Classes 0 (0.00%)
Average Class Length 0
Minimum Class Length 0
Maximum Class Length 0
Average Method Length 0
Minimum Method Length 0
Maximum Method Length 0
Functions 318 (50.72%)
Average Function Length 6
Not in classes or functions 309 (49.28%)
Cyclomatic Complexity
Average Complexity per LLOC 0.22
Average Complexity per Class 0.00
Minimum Class Complexity 0.00
Maximum Class Complexity 0.00
Average Complexity per Method 0.00
Minimum Method Complexity 0.00
Maximum Method Complexity 0.00
Dependencies
Global Accesses 166
Global Constants 0 (0.00%)
Global Variables 50 (30.12%)
Super-Global Variables 116 (69.88%)
Attribute Accesses 0
Non-Static 0 (0.00%)
Static 0 (0.00%)
Method Calls 191
Non-Static 191 (100.00%)
Static 0 (0.00%)
Structure
Namespaces 0
Interfaces 0
Traits 0
Classes 0
Abstract Classes 0 (0.00%)
Concrete Classes 0 (0.00%)
Methods 0
Scope
Non-Static Methods 0 (0.00%)
Static Methods 0 (0.00%)
Visibility
Public Methods 0 (0.00%)
Non-Public Methods 0 (0.00%)
Functions 53
Named Functions 53 (100.00%)
Anonymous Functions 0 (0.00%)
Constants 0
Global Constants 0 (0.00%)
Class Constants 0 (0.00%)