php-5.6.26源代码 - include_once、require_once、include、require、eval 的opcode处理器
# ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER 实现在文件 php-5.6.\Zend\zend_vm_execute.h
static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_op_array *new_op_array=NULL; zval *inc_filename;
zval *tmp_inc_filename = NULL;
zend_bool failure_retval=; SAVE_OPLINE();
inc_filename = opline->op1.zv; // 要include的文件 if (inc_filename->type!=IS_STRING) {
MAKE_STD_ZVAL(tmp_inc_filename);
ZVAL_COPY_VALUE(tmp_inc_filename, inc_filename);
zval_copy_ctor(tmp_inc_filename);
convert_to_string(tmp_inc_filename);
inc_filename = tmp_inc_filename;
} if (opline->extended_value != ZEND_EVAL && strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)) {
if (opline->extended_value == ZEND_INCLUDE_ONCE || opline->extended_value == ZEND_INCLUDE) {
zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename) TSRMLS_CC);
} else {
zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename) TSRMLS_CC);
}
} else {
switch (opline->extended_value) {
// include_once 和 require_once
case ZEND_INCLUDE_ONCE: // 只 included 一次
case ZEND_REQUIRE_ONCE: {
zend_file_handle file_handle;
char *resolved_path; resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename) TSRMLS_CC); // 解析文件路径
if (resolved_path) {
failure_retval = zend_hash_exists(&EG(included_files), resolved_path, strlen(resolved_path)+); // 是否已经 included
} else {
resolved_path = Z_STRVAL_P(inc_filename);
} if (failure_retval) { // 如已经 included
/* do nothing, file already included */
} else if (SUCCESS == zend_stream_open(resolved_path, &file_handle TSRMLS_CC)) { // 尝试打开文件流 if (!file_handle.opened_path) {
file_handle.opened_path = estrdup(resolved_path);
} if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+)==SUCCESS) { // 添加到已经 included
// zend_compile_file == compile_file
new_op_array = zend_compile_file(&file_handle, (opline->extended_value==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE) TSRMLS_CC); // 编译文件,获取新的opcode列表
{
# compile_file 实现在文件 php-5.6.\Zend\zend_language_scanner.c
ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
{
zend_lex_state original_lex_state;
zend_op_array *op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
zend_op_array *original_active_op_array = CG(active_op_array); // 保存 op_code 现场(保存现场)
zend_op_array *retval=NULL;
int compiler_result;
zend_bool compilation_successful=;
znode retval_znode;
zend_bool original_in_compilation = CG(in_compilation); retval_znode.op_type = IS_CONST;
INIT_PZVAL(&retval_znode.u.constant);
ZVAL_LONG(&retval_znode.u.constant, ); zend_save_lexical_state(&original_lex_state TSRMLS_CC); // 保存词法分析器的状态(保存现场) retval = op_array; /* success oriented */ if (open_file_for_scanning(file_handle TSRMLS_CC)==FAILURE) { // 打开文件、设置扫描器的指针
if (type==ZEND_REQUIRE) {
zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC); // 发送失败信息
zend_bailout(); // !!! require、require_once 会抛出异常
} else {
zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
// 没有抛出异常
}
compilation_successful=;
} else {
// 扫描后、初始化 op_array
init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); // 1、初始化一些数据、申请空间 2、迭代调用所有 zend_extensions 扩展的 op_array_ctor 函数
CG(in_compilation) = ; // 是否处于汇编状态
CG(active_op_array) = op_array; // 操作码数组
zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context))); // 把当前上下文入栈
zend_init_compiler_context(TSRMLS_C); // 初始化编译器上下文
compiler_result = zendparse(TSRMLS_C); // 开始解析 zendparse == phpparse == yyparse
zend_do_return(&retval_znode, TSRMLS_CC); // 返回
CG(in_compilation) = original_in_compilation; // 还原现场
if (compiler_result != ) { /* parser error */
zend_bailout(); // !!! 抛出异常
}
compilation_successful=; // 汇编成功
} if (retval) {
CG(active_op_array) = original_active_op_array; // 还原原来 op_code 现场(还原现场)
if (compilation_successful) { // 汇编成功
pass_two(op_array TSRMLS_CC); // !!!! 给每个op_code注册“op_code处理器”
zend_release_labels( TSRMLS_CC);
} else {
efree(op_array);
retval = NULL;
}
}
zend_restore_lexical_state(&original_lex_state TSRMLS_CC); // 还原原来词法解析器的状态(还原现场)
return retval;
} }
zend_destroy_file_handle(&file_handle TSRMLS_CC);
} else {
zend_file_handle_dtor(&file_handle TSRMLS_CC);
failure_retval=;
}
} else {
if (opline->extended_value == ZEND_INCLUDE_ONCE) { // include_once 执行失败,消息通知
zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename) TSRMLS_CC);
} else { // require_once 执行失败,消息通知
zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename) TSRMLS_CC);
}
}
if (resolved_path != Z_STRVAL_P(inc_filename)) {
efree(resolved_path);
}
}
break;
// include 和 require
case ZEND_INCLUDE: // 可以 included 多次
case ZEND_REQUIRE:
new_op_array = compile_filename(opline->extended_value, inc_filename TSRMLS_CC); // 编译文件,获取新的opcode列表
break;
// eval
case ZEND_EVAL: { // 使用的是 eval 指令
char *eval_desc = zend_make_compiled_string_description("eval()'d code" TSRMLS_CC); new_op_array = zend_compile_string(inc_filename, eval_desc TSRMLS_CC); // 编译后,获取新的opcode列表
efree(eval_desc);
}
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
}
if (tmp_inc_filename) {
zval_ptr_dtor(&tmp_inc_filename);
} if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
} else if (EXPECTED(new_op_array != NULL)) {
EX(original_return_value) = EG(return_value_ptr_ptr);
EG(active_op_array) = new_op_array;
if (RETURN_VALUE_USED(opline)) {
EX_T(opline->result.var).var.ptr_ptr = &EX_T(opline->result.var).var.ptr;
EG(return_value_ptr_ptr) = EX_T(opline->result.var).var.ptr_ptr;
} else {
EG(return_value_ptr_ptr) = NULL;
} EX(function_state).function = (zend_function *) new_op_array;
EX(object) = NULL; if (!EG(active_symbol_table)) {
zend_rebuild_symbol_table(TSRMLS_C);
} if (EXPECTED(zend_execute_ex == execute_ex)) {
ZEND_VM_ENTER();
} else {
zend_execute(new_op_array TSRMLS_CC); // 执行opcode列表
{
# zend_execute 实现在文件 php-5.6.\Zend\zend_vm_execute.h
ZEND_API void zend_execute(zend_op_array *op_array TSRMLS_DC)
{
if (EG(exception)) {
return;
}
zend_execute_ex(i_create_execute_data_from_op_array(op_array, TSRMLS_CC) TSRMLS_CC); // zend_execute_ex = execute_ex
}
}
} EX(function_state).function = (zend_function *) EX(op_array); EG(opline_ptr) = &EX(opline);
EG(active_op_array) = EX(op_array);
EG(return_value_ptr_ptr) = EX(original_return_value);
destroy_op_array(new_op_array TSRMLS_CC);
efree(new_op_array);
if (UNEXPECTED(EG(exception) != NULL)) {
zend_throw_exception_internal(NULL TSRMLS_CC);
HANDLE_EXCEPTION();
} } else if (RETURN_VALUE_USED(opline)) {
zval *retval; ALLOC_ZVAL(retval);
ZVAL_BOOL(retval, failure_retval);
INIT_PZVAL(retval);
EX_T(opline->result.var).var.ptr = retval;
}
ZEND_VM_NEXT_OPCODE();
}
php-5.6.26源代码 - include_once、require_once、include、require、eval 的opcode处理器的更多相关文章
- php学习笔记6--php中的文件包含 include,require,include_once,require_once
php中的文件包含 include,require,include_once,require_once 文件包含:是指将一个文件的内容包含进另外一个文件,有利于代码的复用等.php中文件包含指令有4个 ...
- 关于require,require_once,include和include_once的区别
一.定义 require,require_once,include,include_once都属于PHP的关键字,也就是说它们实际都是PHP的语句,而不是函数,类似于print,echo一样,也是PH ...
- include require include_once require_once
include 使用方法: include "test.php"; 一般是放在流程控制的处理部分中使用,将文件内容引入.PHP程序在遇到include语句时,才将它读进来,这种方式 ...
- php include,require,include_once,require_once 的区别
include(),require(),include_once(),require_once()作用都是包含并运行指定文件,但是使用场景又有很大区别. 1.include()和require()的区 ...
- php-5.6.26源代码 - PHP文件汇编成opcode(require、include的差异)
文件 php-5.6.26/Zend/zend_language_scanner.c ZEND_API zend_op_array *compile_file(zend_file_handle *fi ...
- php-7.2.3源代码和php-5.6.26源代码摘录,对比 “汇编php文件”和“执行opcode代码”
php-7.2.3 在“汇编php文件”和“执行opcode代码”上做了大量改变php-5.6.26 没见到支持抽象语法树的相关代码,php-7.2.3 见到支持抽象语法树的相关代码php-5.6.2 ...
- php-5.6.26源代码 - opcode处理器,“函数调用opcode”处理器,如何调用扩展模块的函数
// opcode处理器 --- ZEND_DO_FCALL_SPEC_CONST_HANDLER实现在 php-5.6.26\Zend\zend_vm_execute.h static int ZE ...
- php-5.6.26源代码 - 扩展模块的种类,扩展模块的执行埋点
模块种类(两种) 类型一:zend的模块:(类似zend_extension=test.so) 识别方法: php.ini中以zend_extension开头的配置,如zend_extension=t ...
- php-5.6.26源代码 - opcode处理器的注入
.初始化 opcode处理器列表 // main实现在文件“php-5.6.26\sapi\cgi\cgi_main.c” int main(int argc, char *argv[]) { if ...
随机推荐
- Java 重写hashCode() 时为什么要用 31 来计算
在OSChina 中看到了一篇文章<Java 中正确使用 hashCode 和 equals 方法>,看到 hashCode 的方法体内的31比较有意思. 在Stackoverflow上找 ...
- 03_Jsoup
[1.获取一个页面所有的链接] public static void main(String[] args) throws IOException { String url="http:// ...
- 讲座: conversation
一, Zhouming MSRA NLP group NLP 2.0 attention model 二,Yan Rui 一, retrived based-conversation system t ...
- python 多线程效果演示
多线程演示 不使用多线程的情况 import threading import time def run(n): print("task ",n) time.sleep(2) ru ...
- pcharm激活
服务器搭建命令:(一直默认即可) wget http://home.ustc.edu.cn/~mmmwhy/jetbrain.sh && sh ./jetbrain.sh 我搭建的服务 ...
- 定时备份SQL Server数据库
一.手动备份: 1.整个数据库备份:选择数据库 => 右键任务 => 备份: 2.导出一张表的框架:选择表 => 编写表脚本为 => CREATE到: 3.导出一张表的数据: ...
- 一键生成http服务器
如果你想用最简单的方法在内网共享目录,可以考虑为要共享的目录生成一个http服务器,这样就可以在内网任一台设备打开浏览器就可以浏览了.简单举几个例,有了这个http服务器就可以: 在手机浏览器里观看电 ...
- 12C RAC 常用检查命令,持续总结中
grid: olsnodes -s列出集群中节点crsctl check cluster -all检查几圈状态crsctl check clustercrsctl check crs 检查当前节点sr ...
- March 8 2017 Week 10 Wednesday
Rules are meant to be broken. 规则就是用来被打破的. What is innovation? Some may tell you innovation is to bre ...
- 另一种方式实现事务码SE16里的结果集修改
注: 这种方法不同于网上流传的在调试器里修改fcode的那种解决方案. 使用场景:我们需要直接在开发系统的事务码SE16里修改某些结果集的值,但是在SE16的工具栏里看不见修改按钮: 解决方案 使用/ ...