深入理解PHP原理之函數(Introspecting PHP Function)

來源:互聯網
上載者:User

在PHP中,函數分為倆種,

  • 一種是zend_internal_function, 這種函數是由擴充或者Zend/PHP核心提供的,用’C/C++’編寫的,可以直接執行的函數。
  • 另外一種是zend_user_function, 這種函數呢,就是我們經常在見的,使用者在PHP指令碼中定義的函數,這種函數最終會被ZE翻譯成opcode array來執行

    查看zend_compile.h,我們可以找到如下的3個結構:

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

    第一個結構,定義了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 that are in “common” they hold in common, thus the can safely be casted to each other);

  • 具體來說,當在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.

  • 原文地址: http://www.laruence.com/2008/08/12/164.html
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.