【php7扩展开发二】全局变量
使用C語言開發程序時經常會使用全局變量進行數據存儲,這就涉及前面已經介紹過的一個問題:線程安全,PHP設計了TSRM(即:線程安全資源管理器)用于解決這個問題,內核中頻繁使用到的EG、CG等都是根據是否開啟ZTS封裝的宏,同樣的,在擴展中也需要必須按照TSRM的規范定義全局變量,除非你的擴展不支持多線程的環境。
PHP為擴展的全局變量提供了一種存儲方式:每個擴展將自己所有的全局變量統一定義在一個結構體中,然后將這個結構體注冊到TSRM中,這樣擴展就可以像使用EG、CG那樣訪問這個結構體。
這個結構體的定義通過ZEND_BEGIN_MODULE_GLOBALS(extension_name),ZEND_END_MODULE_GLOBALS(extension_name)兩個宏完成,這兩個宏必須成對出現,中間定義擴展需要的全局變量即可。
ZEND_BEGIN_MODULE_GLOBALS(hello)zend_long greeting; ZEND_END_MODULE_GLOBALS(hello)展開后實際就是個普通的struct:
typedef struct _zend_hello_globals {zend_long greeting; } zend_hello_globals;接著創建一個此結構體的全局變量,這時候就會涉及ZTS了,如果未開啟線程安全直接創建普通的全局變量即可,如果開啟線程安全了則需要向TSRM注冊,得到一個唯一的資源id,這個操作也由專門的宏來完成:ZEND_DECLARE_MODULE_GLOBALS(extension_name),展開后:
//ZTS: 此時只是定義資源id,并沒有向TSRM注冊 ts_rsrc_id hello_globals_id;//非ZTS zend_hello_globals hello_global;最后需要定義一個像EG、CG那樣的宏用于訪問擴展的全局資源結構體,這一步使用ZEND_MODULE_GLOBALS_ACCESSOR()宏完成:
#define HELLO_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(hello, v)
看起來是不是跟EG、CG的定義非常像?這個宏展開后:
//ZTS #define hello_G(v) ZEND_TSRMG(hello_globals_id, zend_hello_globals *, v) //非ZTS #define hello_G(v) (hello_globals.v)接下來就可以在擴展中通過:MYTEST_G(greeting)、對結構體成員進行讀寫了。下面來看一個demo:
//php_hello.h #define HELLO_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(hello, v)ZEND_BEGIN_MODULE_GLOBALS(hello)zend_long greeting; ZEND_END_MODULE_GLOBALS(hello)//hello.c ZEND_DECLARE_MODULE_GLOBALS(hello)PHP_FUNCTION(hello_change_ini) {HELLO_G(greeting) ++; }PHP_FUNCTION(hello_ini) {RETURN_LONG(HELLO_G(greeting)); }//index.php <?phpecho hello_ini(); //0hello_change_ini();echo "<br>";echo hello_ini(); //1 >?
總結
以上是生活随笔為你收集整理的【php7扩展开发二】全局变量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【php内核与扩展开发系列】PHP生命周
- 下一篇: 【php7扩展开发一】注册一个内部函数h