Exakat 1.2.9 review

Exakat 1.2.9 review

Exakat 1.2.9 is out with a truck load of new analyzers. While we are preparing actively for IPC in Berlin and DPC in Amsterdam, we took time to add no less than 5 new analyzers : Flexible Heredoc Syntax for PHP 7.3, Use the blind var, Inexistent compact, Type hinted reference and Type hint / default mismatch . That’s going to be the longest Exakat 1.2.9 review.

Flexible Heredoc syntax

Starting with PHP 7.3, Heredoc and Nowdoc syntax get some new flexibility. In particular, the ending delimiter doesn’t have to be on a line of its own, and it may also be indented.

 
<?php
$bar = <<<EOT 
   bar 
   EOT;

?>

Also, the ending delimiter may be followed by more code: it doesn’t require a new line right after it.

 
<?php

stringManipulator(<<<END
  a b c 
  END);
?>

There are some restrictions on the indentation, such as the ending delimiter must be no further than the opening delimiter. Also, indentation may be space or tabulation, but not both nor mixed.

Read the whole RFC Flexible Heredoc and Nowdoc Syntaxes

Use the Blind Var

The blind variables of a loop are variables that are updated each loop. Here, they are $k and $v.

 
<?php

foreach($array as $k => $v) { 
$sum += $array[$k]; }

?>

Just as illustrated, it happens that the index is used on the original array to access a value, while the same value is actually available in the $v variable. This is slower, more cumbersome and harder to read.

This optimization falls in the realm of micro-optimization, though since it happens in a loop, it may quickly be charged multiple times, and finally bring a noticeable speed bump.

Typehint / default value mismatch

With class inheritance, PHP enforces typehint and default value between two classes. For example:

 
<?php

class x { 
  function foo(X $bar = null) {} 
}

class y extends x { 
  function foo(Y $bar = null) {} 
}

?>

Here, the typehint is changed between class x and class y, and PHP complains about it at linting time. It doesn’t matter if Y is compatible with X, for example sharing an interface, or extending each other.

The example here happens quite rarely: two classes in the same file is not the common behavior. Often, classes are segregated in different files, and PHP won’t lint both of them together until execution: that’s the first time when the code is brought together.

In the end, two important lessons are shown here: one, linting is done file by file, and some of the errors are only detected when two files are put together. This applies to every structure definition, like class, interfaces, traits, etc. There is a need for a tool that makes those checks early during the process of development, to prevent later and costly feedback.

Secondly, this should be caught by Unit Test. If it is not the case, then the incompatibility denotes a class that is abandoned. It may very well be removed now, since it just doesn’t work.

Inexistent Compact

Currently, the compact() function doesn’t report any missing variable.

 
<?php

$a = 'b'; 
$d = compact('a', 'c'); 
// ['a' => 'b'];

?>

This was brought to our attention by Gabriel Caruso, with his RFC: Make compact function reports undefined passed variables.

Gabriel’s patch to PHP will also deal with dynamical variables, but static analysis is able to help with any compact() call that has literal names included.

Don’t forget that compact is not just for packing arrays: it can replace longer and repetitive syntax. Exakat also helps you find those syntax with Could use compact

 
<?php

$a = 'b'; $d = ['a' => $a]; 
// ['a' => 'b'];

?> 

Type hinted reference

Probably inherited from older times, type hinted references are an oxymoron. Objects are passed by reference, so there is no need to enforce a reference on such argument.

 
<?php

function foo(Y &$x) {}

?>
 

The manual’s section Objects and references precises: “A PHP reference is an alias, which allows two different variables to write to the same value. As of PHP 5, an object variable doesn’t contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.”

All in all, this is useless, and reported as such since Exakat 1.2.8.

Happy PHP code reviews

All the 351 analyzers are presented in the docs, including the repulsive Unknown Pcre2 OptionPcre2 supports different options, compared to Pcre1. You’d better review your regex before moving to PHP 7.3: 9% of us are affected.

You can check all of the exakat reports at the gallery: exakat gallery.

Download Exakat on exakat.io, install it with Docker, upgrade it with ‘exakat.phar upgrade -u’ and like us on github.