Introducing php-tracer-weaver

Tweet

One of xdebugs lesser known features is its function traces. In case you haven’t heard of it before, it “allows you to log all function calls, including parameters and return values to a file”, to quote the manual. After playing around with it for a while, I realised that this information could be parsed and used to determine parameter types and return types of functions.

So, as a proof on concept, I wrote a script to parse the function traces from xdebug and use this to process a php source-file, and inject docblock comments, with @param and @return tags. I had to combine the dynamic analysis (function traces) with some static analysis, to be able to collate different sub-types into their supertype, which made the whole deal a bit more complicated than first anticipated.

There are still some room for improvement, but last Thursday at the local php meetup, I demo’ed the project and it’s now available through github.

The usage is split into two steps. First you run the code, using xdebug instrumentation to generate a trace. I’ve created a wrapper script to make this simpler. Just invoke the php script with trace.sh foo.php, rather than php foo.php. This will run the script as normal, while generating a trace in the file dumpfile.xt.

The intention is to use the tool together with an existing test-case. If you don’t use unit tests, you can just put a simple integration test together; The important thing is that the script should get around in all corners of the code, to generate a good basis for the analysis.

The next step is to analyse this data and use it to generate the docblock comments. This is done with the tool weave.php. You’d likely want to call weave.php multiple times (For each file in your project, that you want to generate documentation for).

Here’s an example, to show the process:

We’ll start with a very simple file, without any docblock comments:


<?php

class Foo {
  function stuff($x) {
    return 42;
  }
}

class Bar {}

$f = new Foo();
$f->stuff(new Bar());

The first step is to run the file, using trace.sh:


$ /path/to/php-tracer/weaver/trace.sh foo.php
Running script with instrumentation: foo.php
TRACE COMPLETE

Next, we’ll weave the documentation back into the file:


$ /path/to/php-tracer/weaver/weave.php foo.php foo.php

And that’s it .. Our file now looks like this:


<?php

class Foo {
  /**
    * @param Bar
    * @return integer
    */
  function stuff($x) {
    return 42;
  }
}

class Bar {}

$f = new Foo();
$f->stuff(new Bar());

The implementation is memory-efficient, rather than cpu-efficient, which means that it’ll work with large code bases, but it will take some time to process.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • MagicalTux

    Just for info, this line shouldn’t work with unix:

    $ /path/to/php-tracer/weaver/weave.php foo.php > foo.php

    Bash will open “foo.php” for writing before weave.php being executed, emptying foo.php and making weave.php run on an empty file.

    The lesson there: write to a different file when you do something like this.

  • Troels Knak-Nielsen

    Thanks for that MagicalTux – I was indeed writing to a temp file during testing, and only edited for the post. That should teach me to test everything before deploying it. I’ll edit the article right away.

  • Peter Schade

    Programmers write an programm to document there programs ;)
    Peter Schade
    http://www.peter-schade.de

  • Lukas

    might also be a good move to detect if a method uses func_get_args() ..