Introducing php-tracer-weaver

Share this article

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.

Troels Knak-NielsenTroels Knak-Nielsen
View Author

Troels has been crafting web applications, as a freelancer and while employed by companies of various sizes, since around the time of the IT-bubble burst. Nowadays, he's working on backend systems for a Danish ISP. In his spare time, he develops and maintains Konstrukt, a web application framework for PHP, and is the organizer of a monthly PHP-meetup in Copenhagen.

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week