Poor man's macro programming in php (revisited)

How exactly can you do macros in php now?

Macros have (let's say) two main responsibilities - adding syntactic sugar and abstraction of common patterns. The syntactic sugar bit is something which probably should happen at compile time, at least in a weakly typed language like php. So I'll skip them. The abstraction of computation, well this is wat codified design patterns are. This is what function, classes and the rest of the things we read about and use usually do. To abstract a function in php there are at least two different strategies, probably more, but these two are effective in diametrically different situations. The first one is a combination of the ideas of generic functions (higher order functions) and partial evaluation. In code it can look something like:

class rep { var $parameters=array(); function __construct( $select, $update, $eval) { $this->parameters['select'] = $select; $this->parameters['update'] = $update; $this->parameters['eval'] = $eval; } function run() { $args = func_get_args(); $selections = call_user_func_array( $this->parameters['select'], args); $updates = call_user_func_array( $this->parameters['update'], $selections); return call_user_func_array( $this->parameters['eval'], $updates); } }

It is a copy of the generic functions (higher order functions). What is so good about this, that I bother to write about it outside of the apttern collection? Well, it encapsulates a pattern. It is abstract, as in it doesn't care what are the select, update, eval functions, it will execute them nevertheless. It defines (abstracts) the shape of an algorithm, but a lot of these can actually be specific 'design patterns', like C++ templates, for example. Since it is compiled once, and can be used in quite a few instatiations, it may improve the execution of the script using it.

What are it's downfalls? You carry the penalties for the indirect function calls, which may slow down the execution of a script. All depeends on the balance between how often a function encoded this way is actually used. I'm not sure how this will palay with bytecode caches.

Another way to do the same or similar job, at least in some circumstances is using the scary create_function() call. Something along the lines of:

function make_rep( $select, $update, $eval) { $sfun = unique_symbol(); // this assigns a unique global symbol $ufun = unique_symbol(); $efun = unique_symbol(); global $$sfun, $$ufun, $$efun; $$sfun = $select; $$ufun = $update; $$efun = $eval; return create_function() { "global \$$sfun, \$$ufun, \$$efun; \$args = func_get_args(); \$selections = call_user_func_array( \$$sfun, args); \$updates = call_user_func_array( \$$ufun, $selections); return call_user_func_array( \$$efun, $updates); }

Yep, it's a bit ugly. The call to make_rep will be slower than to new rep(), but if the result is used a lot the overall excution time might improve. I'm not sure it's worth the effort, but the advantages and disadvantages, when writing libraries must be evaluated anyway.

So what do these example prove? Well, php has decent abstraction mechanisms. The fact that we can do indirect function calls and indirect variable (symbol) resolution can give us useful means to code in different design patterns. This is slower and in some cases memory efficiency is worse than in the directly coded case, but pays off in overall code consistency and in development time. It doesn't substitue proper macros (as in scheme-like macros, not C-style ones), since we can't eliminate the wrapper calls, we can't introduce convenient syntax sugar, etc...

How can we make proper macros?

Is it too complicated to have something like dylan macros (a nice paper from 1999)

Powered by Drupal, an open source content management system