PhpRiot
News Archive
PhpRiot Newsletter
Your Email Address:

More information

The state of meta programming in PHP

Note: This article was originally published at Planet PHP on 18 April 5680.
Planet 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 aofooa
  • I need the dependency aoBara here
  • This method should be access protected to the rules of the DSL I put here
  • This method returns a value of type aoABCDa

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 OndAej NeApor. 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)