- URL: https://www.laruence.com/en/2012/08/16/2701.html
- Please include attribution when republishing.
The question of "separating PHP's compilation and execution" has been brought up again and again, and again and again tried. Those who propose it believe that once compilation and execution are separated, you can get a performance boost, do code protection, and so on.
I myself am not really enthusiastic about this feature, because there's a cost-benefit ratio here. Let me explain, though in any case, at the end I'll provide a scheme for achieving this functionality.
1. PHP's compilation is not very time-consuming
I've introduced this in a previous article: PHP's compilation is a linear compilation process, without optimization, so it's extremely fast. The proponents of separating compilation and execution believe that once separated, you can skip the compilation process entirely and get a big performance boost.
Postscript: someone pointed out that once compilation and execution are separated, you can do various optimizations at compile time, which in turn affects execution speed. That is indeed a direction worth researching.
2. Development speed
One of PHP's strengths is that development/deployment/debugging is very convenient and fast — changes take effect immediately. You feel this even more deeply when you're scrambling to fix a live production bug, 🙂 But if we adopted compile/execute separation, then any change would first need to be compiled, then deployed, before it could take effect. That's not a good thing for development.
3. We already have third-party code-cache tools like APC / Zend O+
Third-party code-cache tools like APC (Opcode Cache) are already relatively mature and transparent to developers. All you need to do is install APC on the server, and you get the performance benefit of compile/execute separation.
4. A simple compile/execute separation does not achieve code protection well
The reason is simple: PHP's compilation does no optimization, so it's easy to decompile. Of course, I also don't deny that using binary content does have some effect.
In addition, there are other factors, for instance: the compile/execute separation approach is something people are working on, but it's still not mature, and so on.
Finally, actually, we can do it today as well. Here I'll provide a similar solution.
First, let me plug something: from now on, APC will be maintained by me. If you run into problems using APC in the future, feel free to contact me directly. 🙂
Back to the point: to achieve separation of compilation and execution, we can actually do it with APC. APC provides a family of functions apc_bin_dump and apc_bin_load, which can export the cached Opcodes to an external file.
However, unfortunately, this functionality hasn't worked well before, which is related to the fact that the previous developers, for lack of time, stopped investing energy in it.
After I reorganized and fixed the apc_bin family of functions, this functionality can now finally work properly (starting from APC-3.1.12). Based on these functions, we can implement compile/execute separation.
The idea is simple: locally, use apc_bin_dumpfile to export our PHP files into .bin files, and then on the server, use apc_bin_loadfile to read those .bin files. That achieves compile/execute separation. A simple illustrative code:
$ find ./ -name "*.php" -exec php -r "apc_bin_dumpfile(array('{}'), array(), '{}' . '.bin');" \;
Then, on the server side, in the auto-loading part:
<?php
function __autoload($name) {
/*first compute the file name*/
$file = get PHP file path from class name();
if (!file_exists($file)) {
//file doesn't exist, meaning we haven't loaded it yet, so create an empty file.
file_put_contents($file, '');
apc_bin_loadfile($file . '.bin');
} else {
//we've already loaded it; in theory it should already be cached by the server's APC.
}
include ($file);
}
Of course, this is only a simple illustration. If you want to actually use it, you also have to account for the possibility of the cache being evicted. One solution is to set up two autoload functions: the first as above, and the second, if it's called, means the cache was evicted and an empty file was included, so just load the .bin file once more.
Of course, you could also pack all the files into a single .bin file, load it once, and then leave the rest to the server's APC Cache. But there's one thing to be careful about here,
So for those who want a "code protection" capability, they can now use APC to do these things for free. Of course, because it's a memory-image dump, it's affected by the PHP version and the system's endianness, but for a general application, this can be matched quite easily.
Finally, thanks to @cfc4n for pushing this along, hehe.
Be First to Comment