Roadsend PHP-开源的PHP代码编译器
Roadsend PHP 是一个开源的php compiler, 可以将你的PHP代码编译成原生的二进制代码, 无需分发php源码.
Roadsend 可以将你的PHP web项目编译成FastCGI的可执行文件,这样apache,nginx可以通过fastcgi方式和编译后的
程序进行通讯. 看起来,PHP 编写的程序可以和C编写的程序有同样的待遇了? 因为都可以生成原生代码么,再也不需要在服务器上安装PHP了?
等等, 没有那么美好. 的确,经Roadsend编译后, 可以不需要PHP解释器,甚至它自带了一个micro-server, 在开发环境下,连web server都不用装. 但是, Roadsend仍然有很多限制:
1. 它的编译器依赖bigloo工作,甚至可以将其看作bigloo的前端. 它是通过bigloo中间代码,然后进一步用gcc联编后生成的二进制文件. 因此, 速度上和纯C的代码仍然有差别,在某些情况,如非静态编译,需要运行时动态include php文件的时候,速度和普通php文件相差无几
2. 支持的extension有限,目前只支持 curl - gtk - mysql - pcre - posix - standard - xml 这几个. 其他如常用的memcached,gd等都不支持.
尽管原生代码编译器的名号有些缺憾,但是, 如果有兴趣的朋友还是可以试试,体验一下. 对了,最大的好处就是编译后的PHP代码是无法还原了,当你不希望别人看到你的源码的时候,倒是个不错的办法.
Roadsend PHP 目前支持Windows, Linux ,Mac OSX . 最新版也支持Linux AMD64位.
你可以从其官方站点下载:
http://www.roadsend.com/home/index.php
基于PHP Tokenizer的模板引擎设计思路
PHP5以后内置了Tokenizer库, 从而可以直接使用内置的词法分析器了. 很简单,只有2个函数:
- token_get_all 分析给定的PHP源码,并返回分析后的token数组
- token_name 返回字符形式的token类型
token_get_all 分析的源码必须是完整的PHP语法形式,包括”“.
返回的token数组中每个元素分为2种形式, 元素为数组,则第一个元素为token的名字或者叫类型,
第二个元素是实际的值.
第二种形式就是一个字符串标量,一般是通用的操作符,分隔符等.
使用tokenizer可以实现一些高级的功能,比如,通过分析PHP源码,进行代码重写或者实现
类似java中的XDoclet. 比较实用的例子,如自动生成测试单元的代码框架.
这些都是比较正统的应用,我则考虑利用Tokenizer实现一个更为简单的模板引擎.
我们目前使用的是Smarty,Smarty的优点就是可以作为一个独立的模板语言来使用,
在我们实践中,可以使用smarty封装很多的api从而实现二次开发.
不过,Smarty的缺点也是很明显,
首先,它依赖于复杂的正则表达式来实现模板的解析.占用内存和速度都不太快,当然,这不是主要问题.
其次,由于正则表达式的先天不足,因此对于一些表达式的支持并不高.
此外,过于复杂, 相关的概念太多. 比如block,section,foreach等,其实都可以相互替代.
设计基于Tokenizer的模板引擎可以克服以上缺点,
首先,不依赖复杂的正则表达式,只需要对词法分析器分析出的词(token)进行语法分析即可.
其次,语法分析可以通过2次编译,递归降解的形式来实现,设计可以很简单.
具体实现上,我的计划:
1. 对模板源文件替换相应的标签,使PHP能够进行分析
1. PHP Tokenizer分析tokens
2. 对tokens进行简单的处理形成内部的token数组
3. 第一次编译,将token数组翻译成Runtime库可以识别的bytecode数组
4. Runtime库对bytecode进行运行执行
5. 也可以进一步优化,可以将bytecode编译成普通的PHP文件,直接运行.
其中2,3都可以通过实现PECL扩展来加速. 由于2,3的实现逻辑比较简单,因此并不难,
重点在于4, 实现一个通用的Runtime库, 设计一些标准的bytecode,
大致可以有以下几种:
[E] 执行echo命令
[M] 对象方法调用
[F 普通函数调用
[Do] Do循环
[While] While循环
[For] For 循环
[If] If 指令
[+-/*] 操作符
…
Runtime可以识别这些指令,然后根据指令的参数数组进行执行相应的操作.
这样,读取bytecode数组,循环,即可实现模板的运行执行.
对于指令(bytecode),开始可以实现一些最核心的,也可为编译器留有一些接口,支持bytecode的扩展接口.
不过,我怀疑是否有用,因为其实再复杂的指令其实都可以转换为几个基本bytecode的.