58-定義函數的過程

來源:互聯網
上載者:User
58-定義函數的過程

在PHP中,使用者函數的定義從function關鍵字開始。如下所示簡單樣本:

function foo($var) {    echo $var;}

這是一個非常簡單的函數,它所實現的功能是定義一個函數,函數有一個參數,函數的內容是在標準輸出端輸出傳遞給它的參數變數的值。

函數的一切從function開始。我們從function開始函數定義的探索之旅。

詞法分析

在 Zend/zend_language_scanner.l中我們找到如下所示的代碼:

"function" {    return T_FUNCTION;}

它所表示的含義是function將會產生T_FUNCTION標記。在擷取這個標記後,我們開始文法分析。

文法分析

在 Zend/zend_language_parser.y檔案中找到函數的聲明過程標記如下:

function:    T_FUNCTION { $$.u.opline_num = CG(zend_lineno); };is_reference:        /* empty */ { $$.op_type = ZEND_RETURN_VAL; }        |   '&'         { $$.op_type = ZEND_RETURN_REF; };unticked_function_declaration_statement:        function is_reference T_STRING {zend_do_begin_function_declaration(&$1, &$3, 0, $2.op_type, NULL TSRMLS_CC); }            '(' parameter_list ')' '{' inner_statement_list '}' {                zend_do_end_function_declaration(&$1 TSRMLS_CC); };

關注點在 function is_reference T_STRING,表示function關鍵字,是否引用,函數名。

T_FUNCTION標記只是用來定位函數的聲明,表示這是一個函數,而更多的工作是與這個函數相關的東西,包括參數,傳回值等。

產生中間代碼

文法解析後,我們看到所執行編譯函數為zend_do_begin_function_declaration。在 Zend/zend_complie.c檔案中找到其實現如下:

void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC) /* {{{ */{    ...//省略    function_token->u.op_array = CG(active_op_array);    lcname = zend_str_tolower_dup(name, name_len);    orig_interactive = CG(interactive);    CG(interactive) = 0;    init_op_array(&op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);    CG(interactive) = orig_interactive;     ...//省略    if (is_method) {        ...//省略 類方法 在後面的類章節介紹    } else {        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);        opline->opcode = ZEND_DECLARE_FUNCTION;        opline->op1.op_type = IS_CONST;        build_runtime_defined_function_key(&opline->op1.u.constant, lcname,            name_len TSRMLS_CC);        opline->op2.op_type = IS_CONST;        opline->op2.u.constant.type = IS_STRING;        opline->op2.u.constant.value.str.val = lcname;        opline->op2.u.constant.value.str.len = name_len;        Z_SET_REFCOUNT(opline->op2.u.constant, 1);        opline->extended_value = ZEND_DECLARE_FUNCTION;        zend_hash_update(CG(function_table), opline->op1.u.constant.value.str.val,            opline->op1.u.constant.value.str.len, &op_array, sizeof(zend_op_array),             (void **) &CG(active_op_array));    }}/* }}} */

產生的中間代碼為 ZEND_DECLARE_FUNCTION ,根據這個中間代碼及運算元對應的op_type。 我們可以找到中間代碼的執行函數為 ZEND_DECLARE_FUNCTION_SPEC_HANDLER。

在產生中間代碼時,可以看到已經統一了函數名全部為小寫,表示函數的名稱不是區分大小寫。

為驗證這個實現,我們看一段代碼:

function T() {    echo 1;}function t() {    echo 2;}

執行代碼,可以看到螢幕上輸出如下報錯資訊:

Fatal error: Cannot redeclare t() (previously declared in ...)

表示對於PHP來說T和t是同一個函數名。檢驗函數名是否重複,這個過程是在哪進行的呢? 下面將要介紹的函式宣告中間代碼的執行過程包含了這個檢查過程。

執行中間代碼

在 Zend/zend_vm_execute.h 檔案中找到 ZEND_DECLARE_FUNCTION中間代碼對應的執行函數:ZEND_DECLARE_FUNCTION_SPEC_HANDLER。 此函數只調用了函數do_bind_function。其調用代碼為:

do_bind_function(EX(opline), EG(function_table), 0);

在這個函數中將EX(opline)所指向的函數添加到EG(function_table)中,並判斷是否已經存在相同名字的函數,如果存在則報錯。 EG(function_table)用來存放執行過程中全部的函數資訊,相當於函數的註冊表。 它的結構是一個HashTable,所以在do_bind_function函數中添加新的函數使用的是HashTable的操作函數zend_hash_add。

').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('
  • ').text(i)); }; $numbering.fadeIn(1700); }); });

    以上就介紹了58-定義函數的過程,包括了定義,過程方面的內容,希望對PHP教程有興趣的朋友有所協助。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.