PHP擴展開發與內核應用閱讀筆記---php的作用域以及如何在擴展中定義,查找php變量

首先提供書的地址:php擴展開發與內科應用,並向作者表示感謝!同時歡迎同看此書的人加入QQ羣:76761320

1:無法在函數中使用在函數外定義的變量的原因

由於php中定義的變量是存儲在一個用HashTable實現的符號表裏。當用戶在PHP中調用一個函數或者類的方法時,內核會創建一個新的符號表並激活,這也就是爲什麼我們無法在函數中使用在函數外定義的變量的原因(因爲它們分屬兩個符號表,一個當前作用域的,一個全局作用域的)。如果不是在一個函數裏,則全局作用域的符號表處於激活狀態。

然而我們是通過什麼來找到當前作用域的符號表和全局作用域的符號表的呢?

我們現在打開php源碼下的Zend/zend_globals.h文件,看一下_zend_execution_globals結構體,會在其中發現這麼兩個element:

struct _zend_executor_globals {
    ...
    HashTable symbol_table;
    HashTable *active_symbol_table;
    ...
};
其中的 symbol_table元素可以通過EG宏來訪問,它代表着PHP的全局變量,如$GLOBALS,其實從根本上來講,$GLOBALS不過是EG(symbol_table)的一層封裝而已。 與之對應,下面的active_symbol_table元素也可以通過EG(active_symbol_table)的方法來訪問,它代表的是處於當前作用域的變量符號表。

2:在擴展中創建一個php變量

我們可以先構思一下步驟:

  • 創建一個zval結構,並設置其類型。
  • 設置值爲'bar'。
  • 將其加入當前作用域的符號表,只有這樣用戶才能在PHP裏使用這個變量。
  • 具體的代碼爲
    zval *fooval;
 
    MAKE_STD_ZVAL(fooval);
    ZVAL_STRING(fooval, "bar", 1);
    ZEND_SET_SYMBOL( EG(active_symbol_table) ,  "foo" , fooval);

首先,我們聲明一個zval指針fooval,並使用MAKE_STD_ZVAL宏來申請一塊內存。然後通過ZVAL_STRING宏將值設置爲‘bar’,最後使用ZEND_SET_SYMBOL將這個zval加入到當前的符號表裏去,並將其label定義成foo,這樣用戶就可以在代碼裏通過$foo來使用它了。
3:在擴展中調用一個已經定義的php變量
內核提供了操作HashTable的API:zend_hash_find() 通過這個函數可以找到當前某個作用域下用戶已經定義好的變量。
  • 定義了一個指向指針的指針
  • 通過zend_hash_find去EG(active_symbol_table)作用域下尋找名稱爲foo($foo)的變量,如果成功找到,此函數將返回SUCCESS。並把它的地址賦給我們在調用zend_hash_find()函數傳遞的fooval參數,也就是說此時fooval就指向了我們要找的數據。如果沒有找到,那它不會對我們fooval參數做任何修改,並返回FAILURE常量。
  • if判斷輸出結果
  • 具體代碼爲:
    zval **fooval;
 
    if (zend_hash_find(
            EG(active_symbol_table), //這個參數是地址,如果我們操作全局作用域,則需要&EG(symbol_table)
            "foo",
            sizeof("foo"),
            (void**)&fooval
        ) == SUCCESS
    )
    {
        php_printf("成功發現$foo!");
    }
    else
    {
        php_printf("當前作用域下無法發現$foo.");
    }


發佈了80 篇原創文章 · 獲贊 18 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章