Ala*_*orm 5 php c macros php-internals
PHP InternalsTSRMLS_FETCH
宏是如何工作的?
根据PHP 手册
在开发扩展时,包含“tsrm_ls 未定义”的构建错误或导致该结果的错误源于 TSRMLS 在当前范围内未定义的事实,要解决此问题,请使用适当的宏声明函数以接受 TSRMLS,如果有问题的函数不能更改,您必须在函数体内调用 TSRMLS_FETCH。
我了解声明函数以使用适当的宏接受 TSRMLS意味着使用TSRMLS_C、TSRMLS_D、TSRMLS_CC 和 TSRMLS_DC来定义或调用具有额外参数/参数的函数。
但是,如果相关函数的原型无法更改,则必须在函数体内调用 TSRMLS_FETCH使我有点困惑。如果我在PHP-SRC看起来既这里和这里的TSRMLS_FETCH
似乎是一个空的宏。
所以这给我留下了一个问题——它TSRMLS_FETCH
是如何工作的?在编译时是否有其他东西填充这个宏?
首先,我不会太关注手册中关于 PHP 内部结构的内容。它已经过时了,并且很可能在不久的将来从手册中删除。目前有两个网站专门介绍 PHP 的内部结构:PHPInternalsBook.com和PHPInternals.net(我为后者编写内容)。还有一些不错的博客可供关注,包括Nikita和Julien 的。
PHP 5.x 系列中的 TSRM 相当具有侵入性。当想要从函数内访问任何Zend 全局变量时,可以选择从函数调用中获取 TLS 内存指针(例如pthread_getspecific
,相对昂贵)或通过函数参数传播 TLS 内存指针(一种混乱且错误的方式)。容易发生外遇,但更快的方法)。您提到的宏TSRMLS_FETCH
用于前一种方法。
在 PHP 7.x 中,传播 TLS 内存指针(通过TSRMLS_[D|C]C?
宏)已被完全删除(尽管它们的宏仍然是为了向后兼容而定义的 - 它们只是不会执行任何操作)。现在访问 TSRM 的 TLS 的首选方式是通过其静态缓存。这基本上只是一个线程局部全局变量,用于保存当前 TLS 内存指针。
以下是相关宏:
#define TSRMLS_CACHE _tsrm_ls_cache // the TLS global variable
#define TSRMLS_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE = NULL; // define it
#define TSRMLS_CACHE_UPDATE() TSRMLS_CACHE = tsrm_get_ls_cache() // update it - i.e. calls pthread_getspecific()
#define TSRMLS_CACHE_RESET() TSRMLS_CACHE = NULL // reset it
Run Code Online (Sandbox Code Playgroud)
使用上述宏确实需要特别小心,以适当地更新静态缓存(通常在扩展的 阶段,GINIT
有时是阶段)。RINIT
然而,这是一种更干净的方式来提供对 TLS 内存指针的访问,而不会通过函数参数传播它,也不会因为总是获取它(通过pthread_getspecific
和类似)而造成性能损失。
额外阅读: