- 本文地址: https://www.laruence.com/2010/07/16/1648.html
- 转载请注明出处
首先 ,插一句题外话: 从我发表第一篇PHP执行原理的文章到现在, 已经快2年了, 我很高兴的看到这俩年里PHP中文圈里 ,越来越多的人开始研究PHP源码, 也有越来越多的人开始从事PHP扩展开发.
关于PHP的执行原理, 我想我BLOG的读者都能脱口而出:
1. 词法分析, 去掉注释, 空白, 得到TOKEN 2. 语法分析, 在这个过程中生成Opcode array (op_array) 3. 解释执行, 执行op_array, 一条一条的解释执行Opline(SWITCH, CALL, GOTO)
今天有人问我, 说他看到有PHPer在说unless语句, 我很是纳闷, 后来才知道, 原来是一个国外的PHP大牛自己Hack了PHP的源码, 加入了一个unless语句.
很有意思, 今天, 我也就在这里为大家演示, 如何为我们自己的PHP加入unless语句..
如果你是不了解PHP的执行过程, 请先花点时间看看我之前的文章深入理解PHP原理之Opcodes:
我们的目标, 是要实现如下的语法(以php 5.2.11为基础):
<?php unless(TRUE) { //这不会被执行 } unless(FALSE) { //这会被执行 }
好得, 看起来unless是if的反义词了.. 那么就好办了, if怎么来, 我们相反的来就可以了..
首先, 词法分析阶段, 我们需要添加unless的TOKEN定义, 编辑Zend/zend_language_scanner.l:
//添加unless的Token定义 <st_IN_SCRIPTING>"unless" { return T_UNLESS; } <st_IN_SCRIPTING>"if" { return T_IF; } <st_IN_SCRIPTING>"elseif" { return T_ELSEIF; }
这样, 词法分析器遇到unless的时候, 就会报告发现了一个T_UNLESS Token.
接下来就需要在语法分析阶段, 定义T_UNLESS的语法动作了, 编辑Zend/zend_language_parse.y
unticked_statement: '{' inner_statement_list '}' | T_IF '(' expr ')' { zend_do_if_cond(&$3, &$4 TSRMLS_CC); } statement { zend_do_if_after_statement(&$4, 1 TSRMLS_CC); } elseif_list else_single { zend_do_if_end(TSRMLS_C); } //添加T_UNLESS的语法动作 | T_UNLESS '(' expr ')' { zend_do_unless_cond(&$3, &$4 TSRMLS_CC);} statement {zend_do_if_after_statement(&$4, 1 TSRMLS_CC);} {zend_do_if_end(TSRMLS_C)};
对的, 因为if和unless只是在条件的真假上不同, 所以我在if的基础上, 做了这个简单的hack, 接下来, 就应该定义zend_do_unless_cond了, 这个逻辑是用来生成OPCODE的. 还是从zend_do_if_cond为基础来做修改, Zend/zend_compile.c:
void zend_do_if_cond(znode *cond, znode *closing_bracket_token TSRMLS_DC) { int if_cond_op_number = get_next_op_number(CG(active_op_array)); zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMPZ; //如果为0则跳转 opline->op1 = *cond; closing_bracket_token->u.opline_num = if_cond_op_number; //跳转地址 SET_UNUSED(opline->op2); INC_BPC(CG(active_op_array)); }
OK, 那么我们的zend_do_unless_cond就可以这样定义:
void zend_do_unless_cond(znode *cond, znode *closing_bracket_token TSRMLS_DC) { int if_cond_op_number = get_next_op_number(CG(active_op_array)); zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMPNZ; //如果为不为0则跳转 opline->op1 = *cond; closing_bracket_token->u.opline_num = if_cond_op_number; SET_UNUSED(opline->op2); INC_BPC(CG(active_op_array)); }
注意上面的OPCODE, 我们把ZEND_JMPZ变成了JMPNZ...
大功告成, 现在需要重新编译PHP了:
cd Zend; rm zend_language_*.c; cd phpsrc_dir; make
编写测试脚本:
<?php unless(FALSE) { echo "Laruence"; }
运行.....
最后, 举的这个例子,相对来说是简单的, 因为有if可以参照, 有兴趣的同学, 可以自己玩玩, 用PHP实现其它语言中的各种语法~~
如果你是不了解PHP的执行过程, 请先花点时间看看我之前的文章
可以用JS的语法实现PHP的功能吗
鸟哥自己写的文章最权威 深入理解PHP原理
鸟哥自己写的文章最权威:深入理解PHP原理
[…] 这个参看鸟哥自己写的文章最权威:深入理解PHP原理之Opcodes […]
过来跟鸟哥学习
The famous temple town of Tarapith is in the Birbhum district of the Indian state of West Bengal.
If the expensive travel packages make it difficult
for you to plan your vacation, then it is time to relax.
Add in the many perks that the work at home travel agent receives, from free swag to free airplane tickets or even vacations, also it almost sounds
too good to be real. To know more, visit the website at travel
to cleveland.
//添加T_UNLESS的语法动作
| T_UNLESS ‘(‘ expr ‘)’ { zend_do_unless_cond(&$3, &$4 TSRMLS_CC);}
statement {zend_do_if_after_statement(&$4, 1 TSRMLS_CC);}
{zend_do_if_end(TSRMLS_C)};
最后的分号,应该在大括号内吧?
文章很好,顶!
刚才测试了一下,Zend/zend_language_parse.y这个文件中要加下面一行才编译成功(PHP 5.6.0-dev):
%token T_UNLESS “unless (T_UNLESS)”
挺好用的,支持
那你就自己调用flex, 先把.l翻译成.c, 别让PHP自己找flex翻译了
我已经安了flex,而且安的是2.5.4版本,在php ./configure时依然报那样的错误,说找不到flex
@jerry 错误信息说了, 你没装flex, PHP需要用flex来吧zend_language_scanner.l翻译成zend_language_sanncer.c
鸟哥,按你的文章,我测试了一下,但是当删除zend_language_*.c后,./configure就出错,没法往下编译了:
configure: error: flex not found. flex is required to generate the Zend/PHP parsers! Supported flex versions are: 2.5.4
鸟哥对php的理解让我们绝对的赞叹。还远不到你的境界
blue5tar同学尝试了在PHP中简化数组定义: 像写javascirpt数组一样写php数组(http://hi.baidu.com/blue5tar_/blog/item/36a251c3a5fa8c0f0ff47755.html)
[…] 本文地址: http://www.laruence.com/2010/07/16/1648.html […]
过来学习,离你的境界还太远啊,努力中
[…] 风雪之隅:《定制自己的PHP语法-在PHP中实现unless》 […]
超赞
过来跟鸟哥学习
基本上php源码分析里的文章我都看不懂..咋整..
[…] This post was mentioned on Twitter by 心跳失忆, Laruence. Laruence said: 定制自己的 PHP语法-在PHP中实现unless http://www.laruence.com/2010/07/16/1648.html […]
鸟哥的思路太令人称道了。好文!
鸟哥玩PHP已经炉火纯青了 这个想法超赞的。。
我们可以定制一个自己的开源PHP。。