@@ -46,7 +46,7 @@ statement:
4646;
4747```
4848修改完这两个文件后需要分别调用re2c、yacc生成对应的C文件,具体的生成命令可以在Makefile.frag中看到:
49- ```c
49+ ```sh
5050$ re2c --no-generation-date --case-inverted -cbdFt Zend/zend_language_scanner_defs.h -oZend/zend_language_scanner.c Zend/zend_language_scanner.l
5151$ yacc -p zend -v -d Zend/zend_language_parser.y -oZend/zend_language_parser.c
5252```
@@ -294,4 +294,62 @@ ZEND_API int pass_two(zend_op_array *op_array)
294294
295295__(5)定义ZEND_DEFER_CALL、ZEND_DEFER_CALL_END指令的handler__
296296
297+ ZEND_DEFER_CALL指令执行时需要将return的位置保存下来,我们把这个值保存到zend_execute_data结构中:
298+ ```c
299+ //zend_compile.h
300+ struct _zend_execute_data {
301+ ...
302+ const zend_op *return_opline;
303+ ...
304+ }
305+ ```
306+ opcode的handler定义在zend_vm_def.h文件中,定义完成后需要执行` php zend_vm_gen.php ` 脚本生成具体的handler函数。
307+ ``` c
308+ ZEND_VM_HANDLER (173, ZEND_DEFER_CALL, ANY, ANY)
309+ {
310+ USE_OPLINE
311+
312+ //1) 将return指令的位置保存到EX(return_opline)
313+ EX(return_opline) = opline + 1;
314+
315+ //2) 跳转
316+ ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline, opline->op1));
317+ ZEND_VM_CONTINUE();
318+ }
319+
320+ ZEND_VM_HANDLER(174, ZEND_DEFER_CALL_END, ANY, ANY)
321+ {
322+ USE_OPLINE
323+
324+ ZEND_VM_SET_OPCODE(EX(return_opline));
325+ ZEND_VM_CONTINUE();
326+ }
327+ ```
328+ 到目前为止我们已经完成了全部的修改,重新编译PHP后就可以使用defer语法了:
329+ ```php
330+ function shutdown($a){
331+ echo $a."\n";
332+ }
333+ function test(){
334+ $a = 1234;
335+ defer shutdown($a);
336+
337+ $a = 8888;
338+
339+ if(1){
340+ return "mid end\n";
341+ }
342+ defer shutdown("9999");
343+ return "last end\n";
344+ }
345+
346+ echo test();
347+ ```
348+ 执行后将显示:
349+ ``` sh
350+ 8888
351+ mid end
352+ ```
353+ 这里我们只实现了普通函数调用的方式,关于成员方法、静态方法、匿名函数等调用方式并未实现,留给有兴趣的读者自己去实现。
297354
355+ 完整代码:[ https://github.com/pangudashu/php-7.0.12 ] ( https://github.com/pangudashu/php-7.0.12 )
0 commit comments