• PHP execute


    修改一下文章,之前没说明问题。

    主要说明一下PHP的执行过程,涉及到函数执行流程,PHP 的函数让PHP强大的特点之一,暂时不讨论类。PHP 的作用域控制只有两处,函数和类,在实际中感觉函数控制作用域的概念更多一点。

    函数分为用户自定义函数,和内部函数。内部函数是php用C 或者是C++编写,这里分析的时候,不会涉及到作用域的切换,在模块初始化的时候就会加载到全局的函数表中EG(function_table)。

    内部函数,用户自定义函数,op_array 三者的数据结构如下所示:

    struct _zend_op_array {
    	/* Common elements */
    	zend_uchar type;
    	char *function_name;		
    	zend_class_entry *scope;
    	zend_uint fn_flags;
    	union _zend_function *prototype;
    	zend_uint num_args;
    	zend_uint required_num_args;
    	zend_arg_info *arg_info;
    	zend_bool pass_rest_by_reference;
    	unsigned char return_reference;
    	/* END of common elements */
    
    	zend_bool done_pass_two;
    
    	zend_uint *refcount;
    
    	zend_op *opcodes;
    	zend_uint last, size;
    
    	zend_compiled_variable *vars;
    	int last_var, size_var;
    
    	zend_uint T;
    
    	zend_brk_cont_element *brk_cont_array;
    	int last_brk_cont;
    	int current_brk_cont;
    
    	zend_try_catch_element *try_catch_array;
    	int last_try_catch;
    
    	/* static variables support */
    	HashTable *static_variables;
    
    	zend_op *start_op;
    	int backpatch_count;
    
    	zend_uint this_var;
    
    	char *filename;
    	zend_uint line_start;
    	zend_uint line_end;
    	char *doc_comment;
    	zend_uint doc_comment_len;
    	zend_uint early_binding; /* the linked list of delayed declarations */
    
    	void *reserved[ZEND_MAX_RESERVED_RESOURCES];
    };
    
    typedef struct _zend_internal_function {
    	/* Common elements */
    	zend_uchar type;
    	char * function_name;
    	zend_class_entry *scope;
    	zend_uint fn_flags;
    	union _zend_function *prototype;
    	zend_uint num_args;
    	zend_uint required_num_args;
    	zend_arg_info *arg_info;
    	zend_bool pass_rest_by_reference;
    	unsigned char return_reference;
    	/* END of common elements */
    
    	void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
    	struct _zend_module_entry *module;
    } zend_internal_function;
    
    typedef union _zend_function {
    	zend_uchar type;	/* MUST be the first element of this struct! */
    
    	struct {
    		zend_uchar type;  /* never used */
    		char *function_name;
    		zend_class_entry *scope;
    		zend_uint fn_flags;
    		union _zend_function *prototype;
    		zend_uint num_args;
    		zend_uint required_num_args;
    		zend_arg_info *arg_info;
    		zend_bool pass_rest_by_reference;
    		unsigned char return_reference;
    	} common;
    
    	zend_op_array op_array;
    	zend_internal_function internal_function;
    } zend_function;
    
    
    typedef struct _zend_function_state {
    	zend_function *function;
    	void **arguments;
    } zend_function_state
    

    这三个数据结构之间可以相互转换,我在上面也列出了一个_zend_function_state 的数据结构,会讲op_array 中的 function 赋值给执行数据_zend_execute_data 的function_state字段的 function,从而将普通代码中切入一个函数,对于作用域的切换稍后说明。

    在excute 执行过程中,有EX(function_state).function = (zend_function *) op_array;可以说明一切。

    一个重要的数据结构:

    struct _zend_execute_data {
    	struct _zend_op *opline;
    	zend_function_state function_state;
    	zend_function *fbc; /* Function Being Called */
    	zend_class_entry *called_scope;
    	zend_op_array *op_array;
    	zval *object;
    	union _temp_variable *Ts;
    	zval ***CVs;
    	HashTable *symbol_table;
    	struct _zend_execute_data *prev_execute_data;
    	zval *old_error_reporting;
    	zend_bool nested;
    	zval **original_return_value;
    	zend_class_entry *current_scope;
    	zend_class_entry *current_called_scope;
    	zval *current_this;
    	zval *current_object;
    	struct _zend_op *call_opline;
    }
    

    用于保存执行期间的数据,在作用域切换的时候起至关重要的作用。

    ZEND_API void execute(zend_op_array *op_array TSRMLS_DC)
    {
    	zend_execute_data *execute_data;
    	zend_bool nested = 0;
    	zend_bool original_in_execution = EG(in_execution);
    
    
    	if (EG(exception)) {
    		return;
    	}
    
    	EG(in_execution) = 1;
    
    zend_vm_enter:
    	/* Initialize execute_data */
    	execute_data = (zend_execute_data *)zend_vm_stack_alloc(
    		ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) +
    		ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)) +
    		ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T TSRMLS_CC);
    
    	EX(CVs) = (zval***)((char*)execute_data + ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)));
    	memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var);
    	EX(Ts) = (temp_variable *)(((char*)EX(CVs)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)));
    	EX(fbc) = NULL;
    	EX(called_scope) = NULL;
    	EX(object) = NULL;
    	EX(old_error_reporting) = NULL;
    	EX(op_array) = op_array;
    	EX(symbol_table) = EG(active_symbol_table);
    	EX(prev_execute_data) = EG(current_execute_data);
    	EG(current_execute_data) = execute_data;
    	EX(nested) = nested;
    	nested = 1;
    
    	if (op_array->start_op) {
    		ZEND_VM_SET_OPCODE(op_array->start_op);
    	} else {
    		ZEND_VM_SET_OPCODE(op_array->opcodes);
    	}
    
    	if (op_array->this_var != -1 && EG(This)) {
     		Z_ADDREF_P(EG(This)); /* For $this pointer */
    		if (!EG(active_symbol_table)) {
    			EX(CVs)[op_array->this_var] = (zval**)EX(CVs) + (op_array->last_var + op_array->this_var);
    			*EX(CVs)[op_array->this_var] = EG(This);
    		} else {
    			if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void**)&EX(CVs)[op_array->this_var])==FAILURE) {
    				Z_DELREF_P(EG(This));
    			}
    		}
    	}
    
    	EG(opline_ptr) = &EX(opline);
    
    	EX(function_state).function = (zend_function *) op_array;
    	EX(function_state).arguments = NULL;
    	
    	while (1) {
        	int ret;
    #ifdef ZEND_WIN32
    		if (EG(timed_out)) {
    			zend_timeout(0);
    		}
    #endif
    
    		if ((ret = EX(opline)->handler(execute_data TSRMLS_CC)) > 0) {
    			switch (ret) {
    				case 1:
    					EG(in_execution) = original_in_execution;
    					return;
    				case 2:
    					op_array = EG(active_op_array);
    					goto zend_vm_enter;
    				case 3:
    					execute_data = EG(current_execute_data);
    				default:
    					break;
    			}
    		}
    
    	}
    	zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen");
    }
    

    执行期间 有EX(prev_execute_data) = EG(current_execute_data);会保存一下现场,

    然后EG(current_execute_data) = execute_data;

    当执行到函数的op_array时,EG(active_op_array) = &EX(function_state).function->op_array;

    会执行到

       case 2:
         op_array = EG(active_op_array);
         goto zend_vm_enter;

    当函数将要执行完毕或者返回的时候,可以主动调用return 或者PHP 会自动放回一个NULL,然后是zend_do_return 生成 ZEND_RETURN的opcode ,根据类型不同会调用几个不同的函数,但总之会调用一个名为zend_leave_helper_SPEC 的函数,其中:

    EG(current_execute_data) = EX(prev_execute_data);会将返回以前的场景,保证回到执行函数以前的作用域。

    个人觉得关键的是以上的一些数据结构,以及相互之间的联系。

  • 相关阅读:
    Exception in thread "main" java.io.IOException: Cannot run program "XX": CreateProcess error
    用eclipse打包mapreduce程序 运行出现解析路径错误的诡异问题
    HTMLParser学习笔记(一)
    Prim算法实现
    hadoop mapreduce 出现找不到 各种类的错误
    搜索引擎的基本原理
    ArrayList 和数组 在mapreduce编程中序列化
    读《做你自己》
    对于通过视频学习编程的建议
    长篇文档排版技巧
  • 原文地址:https://www.cnblogs.com/zoro/p/2099101.html
Copyright © 2020-2023  润新知