· 作者: Laruence( )
· 本文地址: http://www.laruence.com/2008/08/12/164.html
· 转载请注明出处
在PHP中,函数分为俩种,
· 一种是zend_internal_function, 这种函数是由扩展或者Zend/PHP内核提供的,用’C/C++’编写的,可以直接执行的函数。
· 另外一种是zend_user_function, 这种函数呢,就是我们经常在见的,用户在PHP脚本中定义的函数,这种函数最终会被ZE翻译成opcode array来执行
查看zend_compile.h,我们可以找到如下的3个结构:
1. typedefstruct _zend_internal_function {
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. unsignedchar return_reference;
13. /* END of common elements */
14.
15. void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
16. struct _zend_module_entry *module;
17. } zend_internal_function;
18.
19. struct _zend_op_array {
20. /* Common elements */
21. zend_uchar type;
22. char *function_name;
23. zend_class_entry *scope;
24. zend_uint fn_flags;
25. union _zend_function *prototype;
26. zend_uint num_args;
27. zend_uint required_num_args;
28. zend_arg_info *arg_info;
29. zend_bool pass_rest_by_reference;
30. unsignedchar return_reference;
31. /* END of common elements */
32.
33. zend_uint *refcount;
34.
35. zend_op *opcodes;
36. zend_uint last, size;
37.
38. zend_compiled_variable *vars;
39. int last_var, size_var;
40.
41. zend_uint T;
42.
43. zend_brk_cont_element *brk_cont_array;
44. zend_uint last_brk_cont;
45. zend_uint current_brk_cont;
46.
47. zend_try_catch_element *try_catch_array;
48. int last_try_catch;
49.
50. /* static variables support */
51. HashTable *static_variables;
52.
53. zend_op *start_op;
54. int backpatch_count;
55.
56. zend_bool done_pass_two;
57. zend_bool uses_this;
58.
59. char *filename;
60.
61. zend_uint line_start;
62. zend_uint line_end;
63. char *doc_comment;
64. zend_uint doc_comment_len;
65.
66. void *reserved[ZEND_MAX_RESERVED_RESOURCES];
67. };
68.
69. typedefunion _zend_function {
70. zend_uchar type; /* MUST be the first element of this struct!*/
71.
72. struct {
73. zend_uchar type; /* never used */
74. char *function_name;
75. zend_class_entry *scope;
76. zend_uint fn_flags;
77. union _zend_function *prototype;
78. zend_uint num_args;
79. zend_uint required_num_args;
80. zend_arg_info *arg_info;
81. zend_bool pass_rest_by_reference;
82. unsignedchar return_reference;
83. } common;
84.
85. zend_op_array op_array;
86. zend_internal_function internal_function;
87. } zend_function;
88.
第一个结构,定义了zend_internal_function, 当PHP启动的时候,它会遍历每个载入的扩展模块,然后将模块中function_entry中指明的每一个函数,创建一个zend_internal_function结构,并将type置为ZEND_INTERNAL_FUNCTION(见下表), 将这个结构填入全局的函数表(一个HashTable);
1. #define ZEND_INTERNAL_FUNCTION 1
2. #define ZEND_USER_FUNCTION 2
3. #define ZEND_OVERLOADED_FUNCTION 3
4. #define ZEND_EVAL_CODE 4
5. #define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5
6.
第二个结构,op_array, 这个结构很重要,因为:
1. extern ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
2.
也就是说,我们编写的PHP脚本,都会被ZE翻译成op_array, 最后交由zend_execute执行。
另外,在ZE中,用户定义的函数(userland function), 也会被翻译成一个op_array, 并填入全局函数表中。这个时候scope,function_name都不为空。而对于在全局作用域的直接代码来说,最后的op_array的scope为全局,function_name为空。
第三个结构,很有趣,要理解这个结构,首先你要理解他的设计目标: zend_internal_function,zend_function,zend_op_array可以安全的互相转换(The are not identical structs, but all the elements thatare in “common” they hold in common, thus the can safely be casted to eachother);
具体来说,当在op code中通过ZEND_DO_FCALL调用一个函数的时候,ZE会在函数表中,根据名字(其实是lowercase的函数名字,这也就是为什么PHP的函数名是大小写不敏感的)查找函数,如果找到,返回一个zend_function结构的指针(仔细看这个上面的zend_function结构), 然后判断type,如果是ZEND_INTERNAL_FUNCTION,那么ZE就调用zend_execute_internal,通过zend_internal_function.handler来执行这个函数,如果不是,就调用zend_execute来执行这个函数包含的zend_op_array.