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.