PHP 内部结构:TSRMLS_FETCH 是如何工作的?
PHP Internals: How does TSRMLS_FETCH Work?
PHP Internals TSRMLS_FETCH
宏是如何工作的?
根据 PHP Manual
While developing extensions, build errors that contain "tsrm_ls is undefined" or errors to that effect stem from the fact that TSRMLS is undefined in the current scope, to fix this, declare the function to accept TSRMLS with the appropriate macro, if the prototype of the function in question cannot be changed, you must call TSRMLS_FETCH within the function body.
我明白 声明函数以使用适当的宏接受 TSRMLS 意味着使用 TSRMLS_C, TSRMLS_D, TSRMLS_CC, and TSRMLS_DC 来定义或调用具有额外 parameters/arguments 的函数。
但是,如果无法更改相关函数的原型,则必须在函数体内调用TSRMLS_FETCH,这让我有点困惑。如果我查看 php-src here and here TSRMLS_FETCH
似乎是 一个空宏。
所以这给我留下了一个问题——TSRMLS_FETCH
是如何工作的?编译时是否有其他东西填充此宏?
这段代码
#if ZEND_DEBUG
...
#else
#define TSRMLS_FETCH()
...
#endif
正在做以下事情:
如果您未处于调试模式,请将对宏 TSRMLS_FETCH()
的每次调用更改为空。
在这个例子中:
#if 0
#define TSRMLS_FETCH() printf("Bla");
#else
#define TSRMLS_FETCH()
#endif
int main(void)
{
TSRMLS_FETCH()
return 0;
}
cpp demo.c
(预处理器输出)returns:
int main(void)
{
return 0;
}
看看older versions of that file:
#define TSRMLS_FETCH() void ***tsrm_ls = (void ***) ts_resource_ex(0, NULL)
#define TSRMG(id, type, element) (((type) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])->element)
#define TSRMLS_D void ***tsrm_ls
#define TSRMLS_DC , TSRMLS_D
#define TSRMLS_C tsrm_ls
#define TSRMLS_CC , TSRMLS_C
似乎在某些时候 PHP 删除了对这些宏的支持,但将它们保留为空,以避免将外部代码拆分为两个版本,一个用于新的 PHP,一个用于新的 PHP旧 PHP.
首先,我不会过多关注手册中关于 PHP 内部结构的内容。它已经过时了,很可能在不久的将来会从手册中删除。目前有两个网站致力于 PHP 的内部:PHPInternalsBook.com and PHPInternals.net (I author content for the latter). There's also a couple of good blogs to follow, including Nikita's and Julien's.
PHP 的 5.x 系列中的 TSRM 非常具有侵入性。当想要从函数中访问任何 Zend globals 时,选择是从函数调用中获取 TLS 内存指针(例如 pthread_getspecific
,这是相对昂贵的)或通过传播 TLS 内存指针函数参数(混乱且 error-prone 的事情,但速度更快)。您提到的 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
使用上述宏确实需要特别注意以适当地更新静态缓存(通常在扩展的 GINIT
,有时 RINIT
阶段)。但是,这是一种提供对 TLS 内存指针的访问的更简洁的方法,而无需通过函数参数传播它的混乱或始终获取它(通过 pthread_getspecific
和类似方式)对性能的影响。
补充阅读:
- Native TLS(在 PHP 7.0 中引入此更改的 RFC)
- Threads and PHP(Julien 在 TSRM 上的博客 post)
在 PHP 8 中(我写这篇文章的时候处于 Alpha 阶段)很多这样的宏已经被删除。参见 https://github.com/php/php-src/blob/master/UPGRADING.INTERNALS
c. The following things have been removed from TSRM:
- TSRMLS_DC
- TSRMLS_D
- TSRMLS_CC
- TSRMLS_C
- TSRMLS_FETCH
- TSRMLS_FETCH_FROM_CTX
- TSRMLS_SET_CTX
- tsrm_new_interpreter_context
- tsrm_set_interpreter_context
- tsrm_free_interpreter_context
- support for GNUPTH, SGI ST, and BETHREADS
PHP Internals TSRMLS_FETCH
宏是如何工作的?
根据 PHP Manual
While developing extensions, build errors that contain "tsrm_ls is undefined" or errors to that effect stem from the fact that TSRMLS is undefined in the current scope, to fix this, declare the function to accept TSRMLS with the appropriate macro, if the prototype of the function in question cannot be changed, you must call TSRMLS_FETCH within the function body.
我明白 声明函数以使用适当的宏接受 TSRMLS 意味着使用 TSRMLS_C, TSRMLS_D, TSRMLS_CC, and TSRMLS_DC 来定义或调用具有额外 parameters/arguments 的函数。
但是,如果无法更改相关函数的原型,则必须在函数体内调用TSRMLS_FETCH,这让我有点困惑。如果我查看 php-src here and here TSRMLS_FETCH
似乎是 一个空宏。
所以这给我留下了一个问题——TSRMLS_FETCH
是如何工作的?编译时是否有其他东西填充此宏?
这段代码
#if ZEND_DEBUG
...
#else
#define TSRMLS_FETCH()
...
#endif
正在做以下事情:
如果您未处于调试模式,请将对宏 TSRMLS_FETCH()
的每次调用更改为空。
在这个例子中:
#if 0
#define TSRMLS_FETCH() printf("Bla");
#else
#define TSRMLS_FETCH()
#endif
int main(void)
{
TSRMLS_FETCH()
return 0;
}
cpp demo.c
(预处理器输出)returns:
int main(void)
{
return 0;
}
看看older versions of that file:
#define TSRMLS_FETCH() void ***tsrm_ls = (void ***) ts_resource_ex(0, NULL) #define TSRMG(id, type, element) (((type) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])->element) #define TSRMLS_D void ***tsrm_ls #define TSRMLS_DC , TSRMLS_D #define TSRMLS_C tsrm_ls #define TSRMLS_CC , TSRMLS_C
似乎在某些时候 PHP 删除了对这些宏的支持,但将它们保留为空,以避免将外部代码拆分为两个版本,一个用于新的 PHP,一个用于新的 PHP旧 PHP.
首先,我不会过多关注手册中关于 PHP 内部结构的内容。它已经过时了,很可能在不久的将来会从手册中删除。目前有两个网站致力于 PHP 的内部:PHPInternalsBook.com and PHPInternals.net (I author content for the latter). There's also a couple of good blogs to follow, including Nikita's and Julien's.
PHP 的 5.x 系列中的 TSRM 非常具有侵入性。当想要从函数中访问任何 Zend globals 时,选择是从函数调用中获取 TLS 内存指针(例如 pthread_getspecific
,这是相对昂贵的)或通过传播 TLS 内存指针函数参数(混乱且 error-prone 的事情,但速度更快)。您提到的 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
使用上述宏确实需要特别注意以适当地更新静态缓存(通常在扩展的 GINIT
,有时 RINIT
阶段)。但是,这是一种提供对 TLS 内存指针的访问的更简洁的方法,而无需通过函数参数传播它的混乱或始终获取它(通过 pthread_getspecific
和类似方式)对性能的影响。
补充阅读:
- Native TLS(在 PHP 7.0 中引入此更改的 RFC)
- Threads and PHP(Julien 在 TSRM 上的博客 post)
在 PHP 8 中(我写这篇文章的时候处于 Alpha 阶段)很多这样的宏已经被删除。参见 https://github.com/php/php-src/blob/master/UPGRADING.INTERNALS
c. The following things have been removed from TSRM:
- TSRMLS_DC
- TSRMLS_D
- TSRMLS_CC
- TSRMLS_C
- TSRMLS_FETCH
- TSRMLS_FETCH_FROM_CTX
- TSRMLS_SET_CTX
- tsrm_new_interpreter_context
- tsrm_set_interpreter_context
- tsrm_free_interpreter_context
- support for GNUPTH, SGI ST, and BETHREADS