当前位置: 首页 > 后端技术 > PHP

php内核探索之PHP_FUNCTION宏

时间:2023-03-29 13:44:15 PHP

一开始我只是个菜鸟,因为对技术有一种向往,所以在“枯燥”的工作之后尽自己最大的努力提升自己。由于本人C语言功底也有限,本文的深度也有限。如果你有幸读到,希望你能给我一些指导。我很感激。PHP函数作为PHPer,我们几乎天天都在写函数,想必好奇那些PHP中内置的函数长什么样子。如果你写过PHP扩展,你一定知道这个宏:PHP_FUNCTION。定义函数时,像这样使用这个宏。例如array_change_key_case,它的定义是这样的:PHP_FUNCTION(array_change_key_case)。是的,就这么简单。然而,这简单的背后,却没有那么简单。PHP_FUNCTION宏的溯源相信对这篇文章感兴趣的同学一定对C语言及其宏定义有一定的了解。如果没有也没关系,我简单解释一下什么是宏。C中的宏,我觉得可以理解为简单的封装。通过宏定义,可以对开发者隐藏一些细节,让开发者用简单的语法完成重复复杂的编码。当然,宏定义还有其他用途,但这就是我们在PHP_FUNCTION中处理的内容。有下面的代码。#defineTEST(test)voidtest(inta)TEST(haha)宏是一个完整的替换,即将前面的语句替换为后面的语句。那么对于后面的TEST(哈哈)就等同于下面的。voidhaha??(inta)PHP_FUNCTION的定义首先我们要定义函数,所以用这个宏。PHP_FUNCTION(array_change_key_case){//TODO}我们在php-src/main/php.h中找到了如下定义。#definePHP_FUNCTIONZEND_FUNCTION也就是把这里的PHP_FUNCTION宏替换成ZEND_FUNCTION。所以,我们的定义就相当于变成了这样。ZEND_FUNCTION(array_change_key_case){//TODO}我们继续往下看,因为这里还是一个宏,没有看到我们想看的代码。我们可以在php-src/Zend/zend_API.h中找到如下定义。#defineZEND_FN(name)zif_##name#defineZEND_FUNCTION(name)ZEND_NAMED_FUNCTION(ZEND_FN(name))#defineZEND_NAMED_FUNCTION(name)voidname(INTERNAL_FUNCTION_PARAMETERS)我们看到在宏定义中,使用了另一个宏。别怕,还是一个字,替换。我们遵循这些步骤。(##是一个连接器,它的作用是根据字符串连接前后。替换ZEND_FUNCTIONZEND_NAMED_FUNCTION(ZEND_FN(name)){//TODO}替换ZEND_FNZEND_NAMED_FUNCTION(zif_array_change_key_case){//TODO}替换ZEND_NAMED_FUNCTIONvoidzif_array_change_key_case(INTERNAL_FUNCTION_PARAMETERS){//TODO}到这里,我们可以看到和我们熟悉的函数定义差不多。。我们找到php-src/Zend/zend.h,可以找到INTERNAL_FUNCTION_PARAMETERS的宏定义。#defineINTERNAL_FUNCTION_PARAMETERSzend_execute_data*execute_data,zval*return_value嗯,还是按照替换原则,我们可以把函数定义改成这样voidzif_array_change_key_case(zend_execute_data*execute_data,zval*return_value){//TODO}整个函数完全没有宏,这就是我们熟悉的一个C语言函数的定义,这就是PHP_FUN的整个定义CTION的过程。execute_data和return_valuereturn_value,顾名思义,就是定义的PHP函数的返回值。而execute_data,按照我的理解,是Zend内部的一个调用栈,在执行这个函数的时候,指向这个函数的栈帧。具体细节这里暂时不考虑,有兴趣的同学可以来这里看看。深入理解PHP内核后记我一直认为对于一个PHPer来说,C语言是必备的技能。了解PHP的核心对于编写高质量代码起着关键作用。所以,我现在开始研究PHP的源码实现。我希望通过这些文章,记录下我理解源码的那一刻,也希望我的文章能让更多的PHPer进入PHP内核的世界。