PHP Scrutinizer Checks¶
Call Checks¶
Scrutinizer performs various checks on function and method calls:
Calls on Invalid Types¶
Scrutinizer checks if the method can be called on the given type:
$a = 1;
$a->foo(); // Raises foo() is not callable on integer type.
Function/Method Existence¶
Scrutinizer checks that functions and methods exist on the called types.
If a method does not exist, Scrutinizer tries to determine the cause of the error. This could be:
Typo in the Method Name¶
It could be that there is a typo and you meant to call another method. Scrutinizer will suggest the alternative name.
Coding against a Super-Type¶
It could be that you get an interface, but the method does not exist on the interface, but only in a specific implementation of said interface.
This could be resolved by adding the method to the super-type, for example as an abstract method, or you might want to add an assertion that you are sure to get the specific sub-type which has the method.
Undocumented Magic Calls¶
It could be that you are using a magic __call
method, but have not documented the method.
/**
* @method void foo()
*/
class A {
public function __call(/*...*/) { /*... */ }
}
$a = new A();
$a->foo(); // Ok, it's documented
$a->bar(); // Raises an issue suggesting to document bar()
Argument Checks¶
Scrutinizer checks if a method can be called with the given arguments. It also considers variadic
arguments and also supports function overloading for example in the case of built-in PHP functions
like strtr
that have different signatures.
Argument checks include:
- Checking that a compatible number of arguments was passed (not too few, not too many)
- Checking that the right types have been passed
- Checking that reference arguments can be passed by reference
Statically Calling Non-Static Methods¶
Scrutinizer checks if a non-static method is called statically:
class A {
public function foo() { return 'foo'; }
}
A::foo(); // Raises an issue
Property Access Checks¶
Scrutinizer checks accesses to properties:
Property Existence¶
Scrutinizer checks if called properties exist. If a property could not be found, Scrutinizer attempts to determine the cause. This could be:
- There is a typo, and you meant to call another property. Scrutinizer will suggest the alternative name instead.
- The property exists only in a sub-type, but you code against an interface. Scrutinizer will suggest to code against the expected implementation instead.
- You are using magic
__get
or__set
methods, but have not documented the properties.
Type Compatibility¶
Scrutinizer checks assignments to properties for compatibility with their documented type. Scrutinizer will for example raise an issue if a property is documented as an object, but you assign a string to it.
Unreachable/Infeasible Code¶
Scrutinizer checks for code that is unreachable:
function foo() {
return 'foo';
echo 'foo'; // Not reachable
}
It also checks conditions for feasibility:
$foo = 'foo';
if ($foo === true) { // Raises an issue that $foo can never be true.
}
Variable Checks¶
Scrutinizer checks your code for various variable errors:
- non-existent variables
- typos in variable names
- dead assignments which are not used in the code
- un-initialized array variables
- unintentionally overwriting variables in foreach loops
Method/Function Return Checks¶
Scrutinizer checks the implementation of methods/functions to make sure they are compatible with their signature.
If Scrutinizer detects an incompatibility, it tries to determine the cause for the error. This could be:
- the documented type is simply invalid and needs to be updated
- the returned expression could contain additional types that need to be ruled out. For example, adding assertions for certain error conditions.
- some code branches are missing a
return
statement and thus implicitly returnnull
- ? and more
In total, Scrutinizer checks for over 15 different causes for incompatibility and provides targeted issue messages for each of them to aid you in understanding and fixing the issue faster.
Doc Comment Checks¶
Scrutinizer checks for invalid doc-comments and suggests fixes.
Deprecated Code¶
Scrutinizer flags usage of deprecated code elements. Code elements include functions, methods, constants, or entire classes/interfaces/traits.
Suspicious Code¶
Scrutinizer flags various forms of suspicious code:
Loose Comparisons¶
Scrutinizer flags various loose comparisons (==
, !=
) when Scrutinizer deems them to be ambiguous and
a strict comparison (!==
, ===
) would produce a different outcome.
In total, Scrutinizer checks for more than 10 different causes and produces targeted issue messages and suggested fixes for each cause.
Switch Fallthrough¶
Scrutinizer checks switch
statements and their corresponding case
statements for fall-throughs.
If a fallthrough has no explicit explanatory comment in the source code, it will be flagged by Scrutinizer.
Empty Catch Statements¶
Scrutinizer will flag empty catch statements unless they have an explicit explanatory comment in the source code.
Binary Operations¶
Scrutinizer checks binary operations for common errors like:
- using
&
(bitwise-and) instead of&&
(boolean-and). - wrong placement or missing
()
to ensure correct precedence like in$a & $b === 0
Unused Code¶
Scrutinizer flags unused code such as:
- unused private method
- unused parameters
- unused imports
- unused private properties
and also provides automated fixes for some of them.
Best Practices¶
No Closing Tag¶
Scrutinizer flags usage of PHP's closing tag ?>
in most files. A notable exception where we do not flag it are
template files that are meant to produce output.
No Short PHP Opening Tags¶
Scrutinizer flags usage of PHP's short opening tag <?
and suggest to use <?php
instead.
Left-over Debug Code¶
Scrutinizer will check for left-over debug code such as var_dump
or similar.
Usage of exit
should be avoided in most cases¶
Scrutinizer will flag usages of exit
in many cases as it prevents code
from being properly tested and also makes it harder to integrate.
In some cases, like in CLI scripts, the usage is generally fine and Scrutinizer will not flag it.
Usage of eval
¶
Scrutinizer generally flags the usage of eval
. There are some rare cases where it is fine,
but that is typically in a framework context and not in userland code.
Usage of goto
¶
Scrutinizer generally flags usage of goto
as it is a generally agreed bad practice and makes code hard to read.
There are some specific situations when its usage can make sense like the optimization of very hot code paths, or optimizing generated code, or similar scenarios. These usually do not happen in userland, but rather in a framework context.
Usage of Superglobals¶
Depending on your application, you should try to avoid superglobals like $_GET
,
but instead use the abstraction that your framework or application provides.
This makes your code easier to test. Furthermore, frameworks usually provide additional features along with their request abstractions.
Readable Variable/Method Names¶
Scrutinizer can check if your variables are within certain length restrictions. The general goal is to ensure your code is optimized for easy reading by humans.
Casing of Properties/Parameters¶
Scrutinizer can check if your properties and parameters are using camel-casing which is used by most PHP projects.
Duplicate Code¶
Scrutinizer checks for similar code fragments in your code.
Verbatim Duplications¶
function foo($a, $b) {
if ($a === $b) {
do_something();
} else {
do_someting_else();
}
}
// bar() is exactly a duplicate of foo()
function bar($a, $b) {
if ($a === $b) {
do_something();
} else {
do_someting_else();
}
}
Structural Duplications¶
Scrutinizer also finds structural duplications where the structure could be abstracted:
function findUsersByName(array $users, string $name) {
$filteredUsers = array();
foreach ($users as $user) {
if ($user->getName() === $name) {
$filteredUsers[] = $user;
}
}
return $filteredUsers;
}
function findUsersById(array $users, int $id) {
$filteredUsers = array();
foreach ($users as $user) {
if ($user->getId() === $id) {
$filteredUsers[] = $user;
}
}
return $filteredUsers;
}
Scrutinizer will flag this code as a duplicate. You could for example refactor it like this:
function findMatchingUsers(array $users, callable $predicate) {
$filteredUsers = array();
foreach ($users as $user) {
if ($predicate($user)) {
$filteredUsers[] = $user;
}
}
return $filteredUsers;
}
$usersWithName = findMatchingUsers($user, function(User $user) { return $user->getId() === 'Foo'; });
Laravel-Specific Checks¶
Scrutinizer provides some Laravel specific checks.
Eloquent Models¶
Scrutinizer is able to understand Eloquent database migrations and builds a representation of the database before it starts its analysis.
This improves checks for Eloquent model classes because Scrutinizer is able to infer the types and names of the various properties available. It will also raise issues if you are accessing attributes for which no migration was found.
Routes¶
Scrutinizer also checks your route definitions to make sure action methods are present in the targeted controller class.