当前位置:Gxlcms > PHP教程 > PHPexecute

PHPexecute

时间:2021-07-01 10:21:17 帮助过:11人阅读

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

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

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

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

  1. struct _zend_op_array {
  2. /* Common elements */
  3. zend_uchar type;
  4. char *function_name;
  5. zend_class_entry *scope;
  6. zend_uint fn_flags;
  7. union _zend_function *prototype;
  8. zend_uint num_args;
  9. zend_uint required_num_args;
  10. zend_arg_info *arg_info;
  11. zend_bool pass_rest_by_reference;
  12. unsigned char return_reference;
  13. /* END of common elements */
  14. zend_bool done_pass_two;
  15. zend_uint *refcount;
  16. zend_op *opcodes;
  17. zend_uint last, size;
  18. zend_compiled_variable *vars;
  19. int last_var, size_var;
  20. zend_uint T;
  21. zend_brk_cont_element *brk_cont_array;
  22. int last_brk_cont;
  23. int current_brk_cont;
  24. zend_try_catch_element *try_catch_array;
  25. int last_try_catch;
  26. /* static variables support */
  27. HashTable *static_variables;
  28. zend_op *start_op;
  29. int backpatch_count;
  30. zend_uint this_var;
  31. char *filename;
  32. zend_uint line_start;
  33. zend_uint line_end;
  34. char *doc_comment;
  35. zend_uint doc_comment_len;
  36. zend_uint early_binding; /* the linked list of delayed declarations */
  37. void *reserved[ZEND_MAX_RESERVED_RESOURCES];};typedef struct _zend_internal_function {
  38. /* Common elements */
  39. zend_uchar type;
  40. char * function_name;
  41. zend_class_entry *scope;
  42. zend_uint fn_flags;
  43. union _zend_function *prototype;
  44. zend_uint num_args;
  45. zend_uint required_num_args;
  46. zend_arg_info *arg_info;
  47. zend_bool pass_rest_by_reference;
  48. unsigned char return_reference;
  49. /* END of common elements */
  50. void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
  51. struct _zend_module_entry *module;} zend_internal_function;typedef union _zend_function {
  52. zend_uchar type;
  53. /* MUST be the first element of this struct! */
  54. struct {
  55. zend_uchar type; /* never used */
  56. char *function_name;
  57. zend_class_entry *scope;
  58. zend_uint fn_flags;
  59. union _zend_function *prototype;
  60. zend_uint num_args;
  61. zend_uint required_num_args;
  62. zend_arg_info *arg_info;
  63. zend_bool pass_rest_by_reference;
  64. unsigned char return_reference;
  65. } common;
  66. zend_op_array op_array;
  67. zend_internal_function internal_function;} zend_function;typedef struct _zend_function_state {
  68. zend_function *function;
  69. 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;可以说明一切。

一个重要的数据结构:

  1. struct _zend_execute_data {
  2. struct _zend_op *opline;
  3. zend_function_state function_state;
  4. zend_function *fbc; /* Function Being Called */
  5. zend_class_entry *called_scope;
  6. zend_op_array *op_array;
  7. zval *object;
  8. union _temp_variable *Ts;
  9. zval ***CVs;
  10. HashTable *symbol_table;
  11. struct _zend_execute_data *prev_execute_data;
  12. zval *old_error_reporting;
  13. zend_bool nested;
  14. zval **original_return_value;
  15. zend_class_entry *current_scope;
  16. zend_class_entry *current_called_scope;
  17. zval *current_this;
  18. zval *current_object;
  19. struct _zend_op *call_opline;}

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

  1. ZEND_API void execute(zend_op_array *op_array TSRMLS_DC){
  2. zend_execute_data *execute_data;
  3. zend_bool nested = 0;
  4. zend_bool original_in_execution = EG(in_execution);
  5. if (EG(exception)) {
  6. return;
  7. }
  8. EG(in_execution) = 1;zend_vm_enter:
  9. /* Initialize execute_data */
  10. execute_data = (zend_execute_data *)zend_vm_stack_alloc(
  11. ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) +
  12. ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)) +
  13. ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T TSRMLS_CC);
  14. EX(CVs) = (zval***)((char*)execute_data + ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)));
  15. memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var);
  16. EX(Ts) = (temp_variable *)(((char*)EX(CVs)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)));
  17. EX(fbc) = NULL;
  18. EX(called_scope) = NULL;
  19. EX(object) = NULL;
  20. EX(old_error_reporting) = NULL;
  21. EX(op_array) = op_array;
  22. EX(symbol_table) = EG(active_symbol_table);
  23. EX(prev_execute_data) = EG(current_execute_data);
  24. EG(current_execute_data) = execute_data;
  25. EX(nested) = nested;
  26. nested = 1;
  27. if (op_array->start_op) {
  28. ZEND_VM_SET_OPCODE(op_array->start_op);
  29. } else {
  30. ZEND_VM_SET_OPCODE(op_array->opcodes);
  31. }
  32. if (op_array->this_var != -1 && EG(This)) {
  33. Z_ADDREF_P(EG(This)); /* For $this pointer */
  34. if (!EG(active_symbol_table)) {
  35. EX(CVs)[op_array->this_var] = (zval**)EX(CVs) + (op_array->last_var + op_array->this_var);
  36. *EX(CVs)[op_array->this_var] = EG(This);
  37. } else {
  38. if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void**)&EX(CVs)[op_array->this_var])==FAILURE) {
  39. Z_DELREF_P(EG(This));
  40. }
  41. }
  42. }
  43. EG(opline_ptr) = &EX(opline);
  44. EX(function_state).function = (zend_function *) op_array;
  45. EX(function_state).arguments = NULL;
  46. while (1) {
  47. int ret;#ifdef ZEND_WIN32
  48. if (EG(timed_out)) {
  49. zend_timeout(0);
  50. }#endif
  51. if ((ret = EX(opline)->handler(execute_data TSRMLS_CC)) > 0) {
  52. switch (ret) {
  53. case 1:
  54. EG(in_execution) = original_in_execution;
  55. return;
  56. case 2:
  57. op_array = EG(active_op_array);
  58. goto zend_vm_enter;
  59. case 3:
  60. execute_data = EG(current_execute_data);
  61. default:
  62. break;
  63. }
  64. }
  65. }
  66. 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);会将返回以前的场景,保证回到执行函数以前的作用域。

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

人气教程排行