Scrutinizer has supported collecting code coverage since early 2013. During that time, we have received many requests whether we could add more detailed pages for changes in code coverage like we have for the rating algorithm.
I’m happy to announce that inspections now have a dedicated page for test coverage changes (both class coverage changes as a percentage of covered statements and functions/methods using the CRAP score).
With the addition of the dedicated pages for test coverage, we also updated the rating algorithm to not take into account the CRAP score anylonger, but it will now solely focus on assessing the design of your code.
Enjoy the changes and as always we love to hear your feedback.
Making sure that your code is not using any extension points which might be removed in the near future is important if you would like to avoid any extra work for refactoring code to other extension points.
PHP Analyzer comes with rich checks for usage of deprecated code. Instead of
hard-coding specific classes or functions which are deprecated, PHP Analyzer makes
use of the @deprecated
annotation which means that it can detect usage of
deprecated code for any library including your own project. For example, let’s
assume that you have renamed a method and you deprecate the old name:
class SomeClass
{
/**
* @deprecated Use getIssues() instead.
*/
public function getComments()
{
return $this->getIssues();
}
public function getIssues()
{
// ...
}
}
PHP Analyzer always displays the deprecation message when the issue is found. In the
example above the message would be “getComments()
was deprecated with message: use getIssues()
instead”.
When drafting the deprecation message, we would suggest to use something along the lines of “Deprecated since 1.2.3; use xyz() instead.”. Basically, try to point the reader into the direction of the new way of doing things, be that a single method or another location/URL where he/she can obtain more information. This not only helps PHP Analyzer be more useful, but any human reader of the source code will be grateful.
PHP Analyzer detects the following usages of deprecated code:
We have received many requests whether it would be possible to inspect code hosted on your own servers, and are happy to announce that besides GitHub and Bitbucket, Scrutinizer can now also inspect Git repositories hosted on any other server.
To add such a repository, simply select “Self-Hosted Git Repository” when adding the repository:
If you would like to have Scrutinizer continuously inspect your code each time when you push changes to your repository, you can also set-up a post-receive hook which notifies Scrutinizer. We provide a simple shell script which should work in most situations:
You would like to run Scrutinizer completely on your servers? No problem, just email support@scrutinizer-ci.com with your requirements for a quote.
Checking whether a variable exists should be really simple, right? However, let me show you that it is not that simple if you want to make it accurate.
As always this is best explained by looking at some code.
function someFunction() {
$x = 1;
echo $x;
}
Dead simple, you initialize a variable and then read from it. Obviously, if you reverse the order, i.e. you first read and then initialize it, this should be an error. Even if this is a bit of a contrived example, it shows that we need to take the execution flow of your code into account.
This is still quite easy, however PHP also has another feature, pass-by-reference parameters. If you pass a variable by reference to a function (or method), it is automatically initialized in the originating scope:
function initializes(&$x) { }
var_dump($a); // Undefined variable: a
initializes($a);
var_dump($a); // NULL
So, we actually need to also know all the called functions and also all the methods to determine if a parameter is passed by reference or not. No worries, PHP Analyzer takes care of that as well, and uses the results from its type inference analysis.
While most of the no cases - i.e. a variable never exists - should be taken care of by enough tests, verifying that a variable always exists is a bit harder to do with tests. Let’s take a look at another example:
function someFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// Is $x defined here?
echo $x;
}
This might look like valid code at first. After all, $x is defined in all the case statements, right? This is if you pass only “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.
Check for existence of the variable explicitly:
function someFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
if (isset($x)) { // Make sure it's always set.
echo $x;
}
}
Define a default value for the variable:
function someFunction($a) {
$x = ''; // Set a default which gets overridden for certain paths.
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
echo $x;
}
Add a value for the missing path:
function someFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
// Add the missing case statement.
default:
$x = '';
break;
}
echo $x;
}
PHP Analyzer helps you find the cases where your tests are not complete yet to avoid suddenly popping up errors in production.
As always try it out, and we love to hear your feedback.
We deployed this new code rating algorithm already a bit over a week ago. In this blog post, we would like to share the changes and the reasoning behind them with you.
So far, class ratings were weighted averages of their methods’ ratings. Some of you have asked for more detailed assessments of classes which better cover things like coupling and cohesion for example. To measure these characteristics reliably however, you need to have type information of the code. With the introduction of the new PHP Analyzer version, that type information is readily available and we can compute these metrics for you.
So, instead of just making class ratings averages of methods, they now have their own criteria which include:
In the cohesion analysis, we compute the number of un-connected components which you have in your class, a component basically represents a concern. So ideally, you would want to have exactly one component in your class.
Two methods are considered connected if either a method calls another method or if they access the same property. This is also called data cohesion, and works very well if your data resides in the same class like its behavior (which is one of the benefits of object-oriented programming).
As there are some exceptions to this rule like utility classes or simple getter/setter transport objects, PHP Analyzer has heuristics to detect these types of classes and will ignore such methods. Also, PHP Analyzer ignores connections between components which are created through cross-cutting concerns like logging for example. For more information, you can also check out the documentation.
The results of this analysis are also available as a graph which helps you for example if a class gets too big and you would like to split off one of the weakly connected components. The graph below for example shows a focused class with a single concern:
In the coupling analysis, we basically count the number of other types (like interfaces, classes) that your code depends on. This is an indication for how robust your class is to changes in other classes.
PHP Analyzer uses some heuristics to determine the stability of code. For example, it does not count any types defined by the PHP runtime, or also types and methods which are annotated with the @api annotation as these dependencies should rarely - if at all - change during the lifetime of a project.
Try it out and let us know what you think.