How does it work?
Imagine you have a PHP code inside '<?php' and '?>' tags: you can just copy and paste the whole text of the PHP
file inside the text area above and click on "Compute complexity": the script will:
- first "distill" the sole PHP code, dropping everything outside '<?php' and '?>' tags (that is HTML and Javascript), comments, strings, etc.,
- then find the functions inside, and compute the McCabe's cyclomatic complexity for each one. The code outside any function will account for a virtual main function, and will always be present;
- an indented version of the input code (sole PHP code) will be output, hilighting the lines that contribute to increase complexity: this can help you to refactor your code and split it into smaller functions, whose single complexity is smaller.
How to interpret its output?
If you enter the following PHP code in the text area:
<?php
if ($error == 1)
{
die('error')
}
else
{
show_welcome_page(1,1,1);
}
//////////////////////////////////
function show_welcome($verbose,$cond,$unused_var)
{
echo "Some text";
if ( ($verbose == 1) && $cond)
{
echo "...and some verbose text";
}
elseif ($verbose == 2)
{
echo "...and all verbose text";
}
} // end function show_welcome_page($verbose)
?>
the output of the script will be:
Cyclomatic complexity:
The McCabe complexity is 2.
The McCabe complexity of 'show_welcome' is 4.
Input variable '$unused_var' appears never to be used.
Analisys details:
Line MC count Code
3 (->1) if ($error == 1),{
5 : die('_')
6 },else;,{
9 : show_welcome_page(1,1,1);
10 }
13 function show_welcome($verbose $cond $unused_var),{
16 echo "_";
18 (->2) if ( ($verbose == 1) && $cond),{
20 : echo "_";
21 (->1) },elseif ($verbose == 2),{
24 : echo "_";
25 }
27 }
28 ;
This output means that a function "show_welcome" has been found, and that input variable $unused_var has not been used in the body of the function: that could be an error, and should be checked.
The complexity of the function is 4 because it contains two "if" instructions, the first with 2 and the second with 1 logic condition: the McCabe complexity is given by 1 (standard complexity for simple sequential code) increased by 2+1 --> 4.
The code external to any function body has an if statement (with only one logic condition inside), so the complexity is given by 1 increased by 1 --> The McCabe complexity is 2. (here no function name is given, since a virtual main() function is assumed.
Why this page?
I first found the cyclomatic comlexity concepts in Matlab environment, where a Matlab static code analyzer exists, called mlint. By using command "mlint -cyc <filename>", a cyclomatic complexity evaluation of all functions present in Matlab script <filename> will be performed. This analisys greatly helps you to keep the code clean and easily maintainable.
To help improve my website's PHP code, I looked for a free tool to compute the McCabe's cyclomatic complexity of a generic PHP (inside HTML) source code, but couldn't find anything, so I decided to do something on my own.
Now the script, though not yet fail-proof, begins to do its job, so I decided to share it on the web: I used PHP developers work for building my website (PHP is a great language!), so I think it is fair to help someone else by giving out the result of my work.
Source code of these pages
You can download the whole lint_php source code as a compressed archive or from a git repository ("git clone [email protected]:pceres/lint_php.git" if you like command line and want to collaborate!): it is under GPL v3, so you can study it, modify it, use it as you want, but you must give the same rights to the people to which you redistribute it.
If you have an Apache-PHP system (virtually every GNU/Linux distribution), you can use the script offline, without using an Internet connection: this is the way I use it on my laptop, powered by a Slackware GNU/Linux distribution!
History
- rev 0.1: first issue; (04.11.2007)
- rev 0.2: html closing tag are ignored inside strings; (08.11.2007)
- rev 0.3: multiline string management; (12.11.2007)
- rev 0.4: new state (rem_state) added for heredoc string management; (22.11.2007)
- rev 0.5: bug fixing to properly manage (and cohordinate) different types of strings and comments; (23.11.2007)
- rev 0.6: bug fixing for PHP 5 compatibility (array_merge only accepts arrays as arguments); (18.06.2008)
- rev 0.7: function close tag now correctly detected (bug signalled by Charlew Rowe); (01.02.2009)
- rev 0.8: added management of public, protected and private functions (bug signalled by Anders Pallisgaard); (21.06.2009)
- rev 0.8.1: bug fixing for protected functions (solution by Anders Pallisgaard); (21.06.2009)
- rev 0.8.2: bug fixing for return-by-reference functions (bug signalled by Charlew Rowe); (17.12.2009)
- rev 0.8.3: bug fixing for comments inside function parameters (bug signalled by Charlew Rowe); (20.12.2009)
- rev 0.9: added management of ternary statements (bug signalled by Charlew Rowe); (23.12.2009)
- rev 0.10: bug fixing of multi-line ternary statements with comments inside; (29.12.2009)
- rev 0.11: bug fixing of /*...*/ comments in HTML\Javascript code; (06.01.2010)
- rev 0.12: command line usage; deprecated ereg functions replaced with preg counterparts; (28.02.2010)
- rev 0.13: all output available via browser is now available via CLI usage; (04.03.2010)
- rev 0.14: check for function output argument not set; (22.12.2010)
- rev 0.15: bug fixing for wrong counting of bitwise operators; (18.06.2016)
How can you contribute?
Writing this code took me pretty much time, so I'll be glad to know someone is using it!
Also let me know about any bugs, PHP source code that makes the script fail, or, even better, improvements to the code: I'll be happy to include them into lint_php!
You can email me, or just write a quick comment here.
Pasquale Ceres
Caposele (Avellino) - Italy
pasquale_c at hotmail dot com
GPG Public key id: 5FF1B40D; fingerprint: 2529 8665 212D D704 96DF 21EB 6531 8E32 5FF1 B40D
Webmaster of Genealogia di Caposele
Webmaster of StralacenoWeb
Webmaster of ArsWeb
Page viewed 23382 times.