Exakat 1.5.7 Review

This week, on the Exakat 1.5.7 review : the ambassador report is augmented with the traits matrix and the ‘New issues’ section. We added support for ext/wasm and ext/async, two very interesting new extensions. Self referring traits and methods that could be static are some of the new rules. And the old rules have now support of ‘static’, as an array for callbacks. And now, the Exakat 1.5.7 review.

The traits matrix

Traits are “intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies.”. They represent a set of methods, along with their properties, and stored in a separate structure.

    
<?php 
trait name { 
  private $name; 
  public function setName($name) { 
    $this->name = $name;
  }

  public function getName() {   
    return $this->name;
  } 
}

class Dog {   
  use name;
}

class Car {   
  use name;
}
?>

Here, both classes Dog and Car may have names. The trait name is the same code, used in both classes. (If you don’t know cars that have names, think Herby or Lightning McQueen).

Since traits may give the same name to methods, there may be conflicts between traits. The same final class that uses two traits providing the same-named method are in conflict. This is where the keyword insteadof is important.

    
<?php 
  trait a { 
   function t() {} 
  } 

 trait b { 
   function t() {} 
 } 

 class Foo { 
   use a, b { 
      a::t insteadof b; // This sets the priority of a::t over b::t 
      b::t as u; // This aliases b::t as Foo::c 
   } 
} 
?>

When the number of traits is small, solving the conflict is easily done at coding time : few methods, few conflicts. With larger code bases, larger teams and longer history, traits will inevitably grow in size and number, to the point where conflict is common.

Exakat’s Ambassador provides a new automated documentation for traits, helping developers navigate the maze of conflicts : the trait matrix. It provides two crucial pieces of information.

First, the list of methods which are in conflict between traits. Each conflicting method is listed in the cells,

The first analysis shows that a lot of code will benefit from this new suggestion.

Self referring traits

Directly inherited from the previous matrix, exakat now includes a check on self-using traits. That definition actually covers three different situations that have different roots.

The first is the use of a trait in itself. Something like that :

    
<?php 
  trait t { 
    use t; 
    function foo() {} 
} 

?>

A trait may use itself, and there won’t be any conflict, as the including trait has priority over the included traits. So, all redeclared methods (here, all of them) are actually ignored.

The only usage of that situation appears when you want to alias a method, to avoid repeating the code.

    
<?php 
trait t { 
  use t{ foo as bar; }; 
  function foo() {} 
} 
?>

Now, t has two methods : foo and bar.

The second situation is the multiple inclusion of the same trait, in particular when the list of included traits is long. For example :

    
<?php 
trait t { 
  use a, b, c, b, e, f, g; 
  function foo() {} 
} 
?>

PHP include trait only once, so, that list is valid and runs correctly. It is simply too much to include a trait twice, and that should be cleaned.

Finally, traits may end up in cycles of inclusion : they include one another. Since PHP only does use_once style, this is OK :

    
<?php 
trait a { 
  use b; 
  function a() {} 
} 

trait b { 
  use c; 
  function b() {} 
} 

trait c { 
  use a; // Back to the first one 
  function c() {} 
} 
?>

The whole structure is now a single trait with the methods a(), b() and c(). It is sufficient to include only one of them, to get them all. Yet, it may suddenly be problematic once one of the inclusion is removed : with an open cycle, the final class may lack a method or two. It is better to keep the traits in the shape of a tree, rather than include cycles.

Exakat 1.5.7 detects those situations, and reports them.

The static is in the strings

self, static and parent are three useful keywords, used to represent the current class, the called class or its parents. They must be used only inside a class, as they need class context to be useful.

    
<?php 
class x { 
  function a() { 
  // display the current class 
  echo self::class; 
  } 
} 
?>

PHP has multiple ways to reference a method : using the full qualified name, or the self, static and parent, or even, an array with two elements : the class, or an object of that class, and the method name.

    
<?php 
  $for_a_static_call = array('x', 'a'); 
  class x { 
     static function a() { 
     // display the current class 
     echo self::class; 
  } 
} 

?>

Here, self, static and parent can’t be used as first argument, since they require class context. But they may be called as a string.

    
<?php 
  class x { 
    static function a() { 
    // display the current class 
    echo self::class; 
  } 

  static function b($method) { 
   // display the current class with method a above 
   call_user_func($method); 
   echo self::class; 
   } 
} 

(new x)->method(array('static', 'a'));

?>

With ‘static’, the class context is only needed at execution time. So, the method may be defined anywhere, passed as argument, and finally, executed.

Note : at the moment, this only works with calluserfunc() and related functions. Using the dynamic syntax $method( ) would yield an error Fatal error: Uncaught Error: Class 'static' not found. Bug 77295 was filed for review.

Support for the ext/wasm and ext/async extension

We added support for two extensions this week : ext/wasm and ext/async.

 

php-ext-wasm is an extension by no one other than Ivan Enderlin from the Hoa project. “The goal of the php-ext-wasm project is to be able to run WebAssembly binaries from PHP directly.”

 

What is WebAssembly ? “WebAssembly (abbreviated WASM) is a binary instruction format for a stack-based virtual machine. WASM is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.”

On the other hand, ext/async is an async framework for PHP, written by Martin Schröder : it “provides concurrent Zend VM executions using native C fibers in PHP.” In particular, “A task is a fiber-based object that executes a PHP function or method on a separate call stack. ”

 

ext/async makes it easy to start a task, including PHP code, and keep running the rest of PHP. This is particularly efficient with a task that requires waiting, like database queries, sockets or even files. Here is an example from the extension :

    

<?php 

namespace Concurrent;
$domain = (\DIRECTORY_SEPARATOR == '\\') ? \STREAM_PF_INET : \STREAM_PF_UNIX;
list ($a, $b) = stream_socket_pair($domain, \STREAM_SOCK_STREAM, \STREAM_IPPROTO_IP);
foreach ([$a, $b] as $r) {     
  stream_set_blocking($r, false);
  stream_set_read_buffer($r, 0);
  stream_set_write_buffer($r, 0);
}

$watcher = new StreamWatcher($b);
task::async(function () use ($a, $watcher) {     
    (new Timer(500))->awaitTimeout();

   fwrite($a, 'Hello Socket ');
   fclose($a);
   var_dump('EOF!');
});

var_dump('WAIT FOR IO...');
while (\is_resource($b) && !\feof($b)) {     
   $watcher>awaitReadable();

   var_dump(fread($b, 4));
}
fclose($b);
var_dump('DONE!');

?>

This displays :

string(14) "WAIT FOR IO..."
string(4) "EOF!"
string(4) "Hell" 
string(4) "o So" 
string(4) "cket" 
string(3) " " 
string(5) "DONE!"

Visit those two extensions, as they are under heavy work.

Methods that could be static

What do you call a method that makes no usage of $this ? A static method.

We already have an analysis called This is not for static methods, which reports the usage of $this in static methods : this is a bug, as PHP will report its usage a execution time : Using $this when not in object context

Like visibility (private, public, protected), abstract or final, those keywords are dropped during development or refactoring, so as to avoid recurring PHP error messages. And, when the situation settles, it is difficult to review them, as it implies also checking the code that calls them.

Exakat now scours the code to find all legit usage, and report any method that can be made static. This clarifies the code, and help understand its structure.

And while you’re at it, you may also consider moving the static method to a function : as long as the method doesn’t have any link with the current class, including static properties.

The Weekly Audits : 2018, Week #50

Exakat includes a ‘weekly’ report : this report is built with a selection of five analyses. This means a short audit report, with few issues to review. This is not a lot to read them, and review them in your code. Everyone in the PHP community can focus on one of the classic coding problems and fix it. Talk about the weekly audit around you : you’ll find programmers facing the same challenges.

To obtain the ‘weekly’ audit, run an audit, and request the ‘Weekly’ report.

# Init the project (skip when it is already done)    
php exakat.phar init -p <yourproject> -R https://github.com/Seldaek/monolog.git -git 

# Run the project (skip when it is already done)    
php exakat.phar project -p <yourproject> 

# Export the weekly project (every monday)    
php exakat.phar report -p <yourproject> -format Weekly 

# Open projects/<yourproject>/weekly/index.html in your browser    

Every week, you can find here 5 new analysis to review in your code. In fact, when your code is clean, you can also take a quick look at the upcoming

Weekly recommendations for PHP code review : 2018, week 2018-50

Happy PHP Code Reviews

All the 352 analyzers are presented in the docs, including the neat Unthrown Exception : Exceptions are defined in the code but never thrown.

It is a common bug : 31% applications have too many exceptions.

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.