Pythonesque PHP: Self-Documenting Code
One amazing feature about Python is that it is self-documenting. All classes and functions can have documentation strings and they all have access to them using the __doc__ property. Most Python doc strings follow the conventions in PEP 257 and so when printed out they are usually quite nice.
I decided that I wanted a feature like Python's help() function in PINQ and so I made one using PHP's Reflection API. If you remember (and read my articles) I wrote an earlier blog post about manually rebuilding classes using the Reflector classes.
First, here's an example of the output from my help() function on the Dictionary class in PINQ:
class Dictionary | An array-like class for mapping keys to values. | | Author: Peter Goodman | | Constructor: | | Dictionary([array $default_values]) <==> dict($default_values) | | Public Methods: | | offsetExists(...) | $d->offsetExists($key) <==> isset($d[$key]) | | Check if an entry in this dictionary exists for a given key. | | offsetGet(...) | $d->offsetGet($key) <==> $d[$key] | | Get the value (entry) for a specific key in the dictionary. If the key | does not exist in the dictionary then this function will return NULL. | | offsetSet(...) | $d->offsetSet($key, $val) <==> $d[$key] = $val | $d->offsetSet(NULL, array $val) <==> $d[] = $val | | Map a key in the dictionary to a specific value. | | Note: When specifying the key as NULL, val must be an array. | | offsetUnset(...) | $d->offsetUnset($key) <==> unset($d[$key]) | | Remove a (key,value) entry in the dictionary. | | toArray(...) | $d->toArray(void) -> array | | Return the (key,value) pairs in the dictionary as an array mapping keys | to values. | | Class Descendants: | | InnerRecord | Loader | ConfigLoader | PackageLoader | ModelDictionary | PinqRouteParser | ReadOnlyDictionary | StackOfDictionaries | View | PinqView
As you can see, it gets the PHP Doc Block comments for classes and methods and displays them nicely. It also shows the class constants. I decided not to show class properties because I usually don't do doc-block style commenting on them and so I didn't need them. Another thing this class does is function the extending/implementing classes for an interface/class and shows it as a tree of class descendants. This follows nicely from the idea of self-documenting code as it allows the programmer to discover new and important classes.
I'm currently in the process of re-documenting PINQ's source code to be more Pythonesque as I rather like the format and it suits the help() function well. This, of course, does not mean that my help() function (and its associated functions) do not work for non-PINQ classes because they do.
You can check out/download the code from PINQ's Google Code project repository at http://code.google.com/p/pinq-php/source/browse/trunk/system/functions/reflection.php. The help function works for classes, objects, functions, and class/object methods (using two arguments instead of one).
Comments
-
That's really very cool idea :) . I have used PHP's Reflection API for automatic generation of test, the test contents is in doc comment and have @test: before it. And this kind of technique works really great. But your idea will help me to improve the comments usage even more. 10xposted by Radoslav Stankov on Jul 2, 2008 at 10:12am
-
Oh neat, I was thinking of doing something similar (because python has it too) but I was more thinking of evaluating the tests within a function itself. I realized it might not be the best idea (because my approach would lead to an infinite loop), and I had already written some of the code to move the *'s and such from the doc block so I just went from there.posted by Peter Goodman on Jul 2, 2008 at 5:23pm
Comment
