PHP内核探索笔记-函数
2015-12-15 18:31
941 查看
函数定义:
函数的定义是一个将函数名注册到函数列表的过程1. 词法分析:
function将会生成T_FUNCTION标记
2. 语法分析:
3. 生成中间代码:
生成的中间代码为 ZEND_DECLARE_FUNCTION ,根据这个中间代码及操作数对应的op_type。 我们可以找到中间代码的执行函数为 ZEND_DECLARE_FUNCTION_SPEC_HANDLER。
在生成中间代码时,已经统一了函数名全部为小写,表示函数的名称不是区分大小写的。
4. 执行中间代码:
执行函数调用函数do_bind_function,在这个函数中将EX(opline)所指向的函数添加到EG(function_table)中,并判断是否已经存在相同名字的函数,如果存在则报错。 EG(function_table)用来存放执行过程中全部的函数信息,相当于函数的注册表。
函数参数
用户自定义函数的参数在经过词语分析,语法分析后,我们知道对于函数的参数检查是通过 zend_do_receive_arg 函数来实现的。
整个参数的传递是通过给中间代码的arg_info字段执行赋值操作完成。
EG(current_execute_data)。这个变量存放的是当前执行程序或函数的数据。此时我们需要取前一个执行程序的数据,为什么呢? 因为这个函数的调用是在进入函数后执行的
参数的传递
每个PHP脚本都有自己专属的全局符号表,而每个用户自定义的函数也有自己的符号表, 这个符号表用来存储在这个函数作用域下的属于它自己的变量。当调用每个用户自定义的函数时, 都会为这个函数创建一个符号表,当这个函数返回时都会释放这个符号表。
当执行一个拥有参数的用户自定义的函数时,其实它相当于赋值一个操作,即s=a; 只是这个赋值操作的引用计数会执行两次,除了给函数自定义的符号表,还有一个是给函数栈。
参数的传递的第一步是SEND_VAR操作,函数调用是DO_FCALL,在此中间代码之前有一个SEND_VAR操作,此操作的作用是将实参传递给函数, 并且将它添加到函数栈中。
第二步是RECV操作。 RECV操作和SEND_VAR操作不同,它是归属于当前函数的操作,仅为此函数服务。 它的作用是接收SEND过来的变量,并将它们添加到当前函数的符号表。
参数的压栈操作用户自定义的函数和内置函数都需要,而RECV操作仅用户自定义函数需要。
函数的调用和执行
**调用**foo的OPCODE是“DO_FCALL“, DO_FCALL进行函数调用操作时,ZE会在function_table中根据函数名查找函数的定义;如果存在,就返回该函数zend_function结构指针, 然后通过function.type的值来判断函数是内部函数还是用户定义的函数: 调用zend_execute_internal(zend_internal_function.handler)或者直接 调用zend_execute来执行这个函数包含的zend_op_array。
执行
那么,在函数执行的时候, 进入函数前的环境信息是必须要保存的。在函数执行完毕后,这些环境信息也会被还原,使整个程序继续的执行下去。
内部函数的执行与用户函数不同。用户函数是php语句一条条“翻译”成op_line组成的一个op_array,而内部函数则是用C来实现的,因为执行环境也是C环境。
内部函数和用户函数的处理都是由DO_FCALL来进行的。对于内部函数,zend_execute_internal函数没有定义的情况下,会进行另外一个比较长的调用。
内部函数所在的结构体中 有一个handler指针指向此函数需要调用的内部定义的C函数。 这些内部函数在模块初始化时就以扩展的函数的形式加载到EG(function_table)。
变量函数
$func = 'print_r';
$func(‘i am print_r function.’);
匿名函数
使用create_function()创建”匿名”函数:<?php $func = create_function('', 'echo "Function created dynamic";');
echo func;//lambda1my_func(); // 不存在这个函数
lambda_1(); // 不存在这个函数
create_function函数的返回值: 函数返回一个唯一的字符串函数名,出现错误的话则返回FALSE。
该函数在定义了一个函数之后,给函数起了个名字,它将函数名的第一个字符变为了’\0’也就是空字符, 然后在函数表中查找是否已经定义了这个函数,如果已经有了则生成新的函数名, 第一个字符为空字符的定义方式比较特殊, 因为在用户代码中无法定义出这样的函数, 也就不存在命名冲突的问题了.
__invoke魔幻方法
?php class Callme { public function __invoke($phone_num) { echo "Hello: $phone_num"; } } $call = new Callme(); $call(13810688888); // "Hello: 13810688888
匿名函数的实现
<?php $func = function() { echo "Hello, anonymous function"; } echo gettype($func); // object echo get_class($func); // Closure
相关文章推荐
- 一个关于if else容易迷惑的问题
- PHP5.2.*防止Hash冲突拒绝服务攻击的Patch
- 深入理解PHP之匿名函数
- Linux 自检和 SystemTap
- JSP/PHP基于Ajax的分页功能实现
- 关于PHP通过PDO用中文条件查询MySQL的问题。
- 什么是设计模式
- PHP数据库长连接mysql_pconnect的细节
- Php Installing An Expansion
- Mootools 1.2教程 函数
- autoit InputBox 函数
- 文件遍历排序函数
- Oracle 函数大全[字符串函数,数学函数,日期函数]第1/4页
- ASP下经常用的字符串等函数参考资料
- PostgreSQL教程(五):函数和操作符详解(1)
- DOS批处理 函数定义与用法
- asp Chr 函数 数字转字母的方法
- PHP+Apache在Windows 9x下的安装和配置
- IIS 6 的 PHP 最佳配置方法