Phrep allows both standard/basic macros and more complex code substitutions.

Basic macros work pretty much like in CPP. They just take a list of argument names, and a substitution code as value.

The macro definition doesn't use sigil $ prefixes for the arguments nor the substitution corpus. But when referencing a macro, either argument can be a literal PHP expression, including variable names of course. Which is why parameters often/usually should be parenthesized in substitution blocks (a)*(b).

Obviously macros don't make sense for functionality that can be readily expressed with plain PHP functions. Instead their purpose is templating more lengthy constructs.

Code templating

Consider a more realistic example, like templating an object property getter:

Which expands to a stub getter function for the named property.

See examples/ for more practical variants, with implicit docblocks and type assertions etc.

Again, this is a somewhat trivial example. And code templating that can be done by IDEs and doesn't need project-specific customizations or rule-based updating should probably not use macro preprocessing.

Code expansion features

The ## is a macro concatenation operator.

There's also support for the # stringification prefix.

Variadic params are supported by declaring a parameter with #define M(x1,args...).


Macro-in-macro expansion is also supported.

#define RATE(x)  MAX(x, CONST*x)

It needs to be enabled however:


And it's only intended for basic macros. (But will implictly also expand preprocessor-defined constants in macros.)

Unsupported features

There are also a few C specifica that don't make sense for PHP source and may remain unsupported:

Differences token and regex mode

Constants and macros are replaced with values or code in the substitution phase. There can be differences in how arguments are passed/interpolated into macros.

Currently neither mode handles comma separators in not-quite-PHP expressions like MACRO(foo{3,4,5}, $ao[0,1,2]). (Would only be relevant for complex macros, or wrapping whole function/class declarations perhaps.)

And empty-parens macros like #define WRONG() aren't recognized as macro, and really should just be a plain constant. (Well, actually it's recognized, but expansion currently disabled.)