The state of meta programming in PHP
Quoting Wikipedia
Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data, or that do part of the work at compile time that would otherwise be done at runtime
Metaprogramming is quite an interesting sub-discipline and knowing about certain techniques and tools allows you to cut corners quite dramatically for certain tasks. As always, don't overdo but to find out when you are overdoing, first start doing, get excited, overdo, find out the right dose. Let's have a look at what kind of tools you have available in PHP to solve typical meta programming problems.
What kind of questions can meta programmatic APIs answer?
I would group metaprogramming into three sub areas: type introspection, lower level syntax inspection and metadata management. Typical type introspection questions are:
- How many arguments does this function have
- What kind of types does this function take
- Is this class abstract
- In what namespace is this class defined
On a lower level you typically interact with a certain kind of syntax tree to answer questions like:
- Where is an array declaration happening
- Where does a method start, where does it end
- Do all switch statements have a break statement
A third category is adding metadata to the declared types: Java, C# and a few others have first-class Annotation support for this kind of things but PHP only has user space solutions so far. A few things you need metadata for:
- This property is stored in the database as column a€ofooa€ť
- I need the dependency a€oBara€ť here
- This method should be access protected to the rules of the DSL I put here
- This method returns a value of type a€oABCDa€ť
The toolkit
Reflection APIs
PHP core delivers 2.5 key APIs for meta programming. The first one is ext/reflection. You can create reflection classes form a lot of things, functions, classes, extensions and use them to make programming assumptions about the APIs you are introspecting.
A simple example to find out the number of required parameters for each method in the class DirectoryIterator:
getMethods() as $method) { $numberOfRequiredParameters = $method-getNumberOfRequiredParameters(); }Refection is all nice and shiny, except when you don't want to include everything you want to inspect. This is of interest if you inspect various source trees at once that declare duplicate symbols. To do so, there is PHP-Token-Reflection by OndA™ej NeAˇpor. It's a pretty nifty replacement for ext/reflection completely built in user land and on top of ext/tokenizer that even copes with invalid declarations. Additionally it fixes some oddities of the internal reflection API but tries to keep it as close as possible. I've played around with it a bit and I quite like it.
processDirectory("path/to/src"); $class = $broker-getClass('MyClass'); foreach ($class-getMethods() as $method) { ... }Tokenizer
Another core API, this time much more low level, is ext/tokenizer. If enabled at compile time it allows you to parse PHP source code into a list of tokens. Because the API is so low level it is quite hard to use without a proper abstraction layer on top of it. Most of the successful projects built upon ext/tokenizer have built one. One of them is phpcs by Greg Sherwood that built an Token Stream abstraction on top of ext/tokenizer that allows much more convenient navigation in the token stream. Another one shipping its own token stream abstraction is pdepend by Manuel Pichler.
For an example on how the raw API can be used, I once wrote
Truncated by Planet PHP, read more at the original (another 5532 bytes)


