Drupal and Pressflow have too much magic in them, and not the good kind. On the recent Facebook webcast introducing HipHop PHP, their PHP-to-C++ converter, they broke down PHP language features into two categories: magic and mundane. The distinction is how well each capability of PHP, a dynamic language, translates to a static language like C++. “Mundane” features translate well to C++ and get a big performance boost in HipHop PHP. “Magic” features are either unsupported, like eval(), or run about as fast as today’s PHP+APC, like call_user_func_array().
- If/else control blocks
- Normal function calls
- Array operations
- …and most other common operations
- Code causing side-effects that depends on conditions like function existence
- Includes within function bodies
- Other PHP-isms that make Java and C++ developers cringe
How Drupal and Pressflow can run better (or at all) on HipHopPHP
Currently, we invoke hooks using “magic” (though still HipHop-supported) calls to call_user_func_array(). We don’t have to do that; we could be “prelinking” hook invocations by generating the right PHP for the set of enabled modules. If we generate the right PHP here, HipHop can link the function calls during compilation.
This sort of “prelinking” also cleans up profiling results, making it easier to trace function calls through hooks in tools like KCacheGrind.
Compatibility break? Nope, it should be possible to replace the guts of module_invoke_all() with appropriate branching and calls to the generated PHP.
Including files staticly
Drupal 6 introduced an optimization to dynamically load files based on which menu path a user is visiting. This won’t fly in HipHop; it’s simply not supported. Fortunately, this is easy to work around: we can either drop the feature (shared hosters without APC are already booing me) or we could, like in the prelinking example, generate a big, static includes file (which is itself included on HipHop-based systems) that includes all possible page callback handlers based on the hook_menu() entries. Sites that include the static includes file would skip the dynamic includes at runtime.
Compatibility break? None, assuming we take the approach I describe above.
Death to eval()
Like dynamic includes, eval() is unsupported on HipHop. Drupal has already relegated core use of eval() to an isolated module, which is great for security. eval() is pretty bad in general: PHP+APC doesn’t support opcode caching for it, so serious code can’t run in eval() sanely. Unfortunately, using the PHP module to allow controlling block display remains quite popular.
We have a few options here:
- Drop the feature (ouch!)
- Provide a richer interface for controlling block display, including support for modules to hook in and provide their own extended options
- Pump out the PHP to functions in a real file, include that, and call those functions to control block display
Compatibility break? Yes, on all but the third option (writing out a PHP file).
Migrate performance-intensive code to C++
I’m looking at you, drupal_render().
This opportunity is exciting. Without the cruft of Zend’s extension framework, we can migrate performance-critical code paths in core to C++ and make use of STL and Boost, two of the most respected libraries in terms of predictable memory usage and algorithm running time.
Compatibility break? There’s no reason to have one, but keeping C++ and PHP behaviors consistent will be a serious challenge.
- Use real, file-based PHP, avoiding dynamic language features.
- Profile the system to find the biggest wins versus development cost for migrating core functionality to C++.
I’ll be presenting the “Ultimate PHP Stack” for large-scale applications at PHP TEK-X. Zend PHP, Quercus, and HipHop PHP (source code release pending) will all be contenders.