<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 6.2 引用與函數的執行結果 一個函數的執行結果要返回給調用者,除了使用return功能,還有一種辦法,那就是以引用的形式傳遞參數,然后在內部修改這個參數的值。前一種方法往往只能返回一個值,如果我們的函數執行結果具有多種數據,便需要把這些數據打包到一個數組、類等復合類型的變量中才能得以實現;但后一種方法相比而言就簡單一些了。 ### 運行時傳遞引用:Call-time Pass-by-ref 標題有點繞口,其實很簡單,功能如以下php代碼所示: ````php <?php function byref_calltime($a) { $a = '(modified by ref!)'; } $foo = 'I am a string'; //使用&傳遞引用 byref_calltime(&$foo); echo $foo; //輸出'(modified by ref!)' ```` 我們在傳遞參數的時候使用&操作符,便可以傳遞$foo變量的引用過去,而不是copy一份。當我們在函數內核修改這個參數時,函數外部的$foo也跟著被一起修改了。同樣的功能我們如何在擴展里實現呢,其實很簡單,請看下面的源碼: ````c ZEND_FUNCTION(byref_calltime) { zval *a; //將我們接收的參數傳給zval *a; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a) == FAILURE) { RETURN_NULL(); } //如果a不是以引用的方式傳遞的。 if (!a->is_ref__gc) { return; } //將a轉成字符串 convert_to_string(a); //更改數據 ZVAL_STRING(a," (modified by ref!)",1); return; } ```` ### 編譯時的傳遞引用Compile-time Pass-by-ref 如果每一次都在調用函數時候都對參數加一個&符號真是太羅嗦了,有沒有一個簡單的辦法呢,比如在定義函數的時候便聲明這個參數是引用形式的,而不用用戶自己加&符號表示引用,而由內核來完成這步操作?這個功能是有的,我們在PHP語言中可以這樣實現。 ````php <?php 在定義函數參數的時候加了引用符 function byref_compiletime(&$a) { $a = ' (modified by ref!)'; } $foo = 'I am a string'; //這個地方我們沒有加&引用符 byref_compiletime($foo); echo $foo; //輸出 (modified by ref!) ```` 上面的代碼中,我們只是把引用符號從函數調用里轉移到函數定義里。此功能在擴展里面實現的話就頗費周折了,我們需要提前為它定義一個arginfo結構體來向內核通知此函數的這個特定行為。添加此函數到module_entry里需要這樣: ````c ZEND_FE(byref_compiletime, byref_compiletime_arginfo) ```` byref_compiletime_arginfo是一個arginfo結構體,我們在前面的章節中已經用過一次了。 <div class="tip-common">原書中此處有arginfo在PHP4里的實現,被我略去了。</div> 在Zend Engine 2 (PHP5+)中,arginfo的數據是由多個zend_arg_info結構體構成的數組,數組的每一個成員即每一個zend_arg_info結構體處理函數的一個參數。zend_arg_info結構體的定義如下: ````c typedef struct _zend_arg_info { const char *name; /* 參數的名稱*/ zend_uint name_len; /* 參數名稱的長度*/ const char *class_name; /* 類名 */ zend_uint class_name_len; /* 類名長度*/ zend_bool array_type_hint; /* 數組類型提示 */ zend_bool allow_null; /* 是否允許為NULL */ zend_bool pass_by_reference; /* 是否引用傳遞 */ zend_bool return_reference; /* 返回值是否為引用形式 */ int required_num_args; /* 必要參數的數量 */ } zend_arg_info; ```` 生成zend_arg_info結構的數組比較繁瑣,為了方便PHP擴展開發者,內核已經準備好了相應的宏來專門處理此問題,首先先用一個宏函數來生成頭部,然后用第二個宏生成具體的數據,最后用一個宏生成尾部代碼。 ````c #define ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference) ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, ZEND_RETURN_VALUE, -1) #define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \ static const zend_arg_info name[] = { \ { NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args }, #define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref, 0, 0 }, #define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, NULL, 0, 0, 0, pass_by_ref, 0, 0 }, #define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, 0, allow_null, pass_by_ref, 0, 0 }, #define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, 1, allow_null, pass_by_ref, 0, 0 }, #define ZEND_END_ARG_INFO() }; //這里我們先看 ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference) ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference,required_num_args) ```` 這兩個宏函數的前兩個參數的含義是一樣的,name便是這個zend_arg_info數組變量的名字,這里我們定義它為:byref_compiletime_arginfo。pass_rest_by_reference如果被賦值為1,則代表著所有的參數默認都是需要以引用的方式傳遞的(在arginfo中單獨聲明的除外)。而對于ZEND_BEGIN_ARG_INFO_EX的后兩個參數: <ul> <li>name和pass_rest_by_reference的含義同上。</li> <li>return_reference:聲明這個函數的返回值需要以引用的形式返回,這個參數已經在前面章節用過了。</li> <li>required_num_args:函數被調用時,傳遞參數至少為前N個函數(也就是后面參數都有默認值),當設置為-1時,必須傳遞所有參數</li> </ul> 接下來讓我們看生成具體數據的宏: ````c ZEND_ARG_PASS_INFO(by_ref) //強制所有參數使用引用的方式傳遞 ZEND_ARG_INFO(by_ref, name) //如果by_ref為1,則名稱為name的參數必須以引用的方式傳遞, ZEND_ARG_ARRAY_INFO(by_ref, name, allow_null) ZEND_ARG_OBJ_INFO(by_ref, name, classname, allow_null) 這兩個宏實現了類型綁定,也就是說我們在傳遞某個參數時,必須是數組類型或者某個類的實例。如果最后的參數為真,則除了綁定的數據類型,還可以傳遞一個NULL數據。 //我們組合起來使用: ZEND_BEGIN_ARG_INFO(byref_compiletime_arginfo, 0) ZEND_ARG_PASS_INFO(1) ZEND_END_ARG_INFO() ```` 為了使我們的擴展能夠兼容PHP4,還需要使用#ifdef進行特殊處理。 ````c #ifdef ZEND_ENGINE_2 ZEND_BEGIN_ARG_INFO(byref_compiletime_arginfo, 0) ZEND_ARG_PASS_INFO(1) ZEND_END_ARG_INFO() #else /* ZE 1 */ static unsigned char byref_compiletime_arginfo[] = { 1, BYREF_FORCE }; #endif ```` 我們copy一份ZEND_FUNCTION(byref_calltime)的實現,并重名成ZEND_FUNCTION(byref_compiletime)就行了。或者直接弄個ZEND_FALIAS就行了: ````c ZEND_FALIAS(byref_compiletime,byref_calltime,byref_compiletime_arginfo) ```` ## links * 6.1 [一個特殊的參數:return_value](<6.1.md>) * 6.3 [第六章小結](<6.3.md>)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看