深入PHP内核之函数和返回值
1、关于返回值,PHP内核中使用了大量的宏来实现,我们先看一个函数
PHP_FUNCTION 宏的定义(Zend/zend_API.h)
#define PHP_FUNCTION ZEND_FUNCTION
#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))
#define ZEND_FN(name) zif_##name
#define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)
#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr,\
zval *this_ptr, int return_value_used TSRMLS_DC //最终
void zif_hello_world(int ht, zval *return_value, zval **return_value_ptr,
zval *this_ptr, int return_value_used TSRMLS_DC)
{
}
参数解释
名称和类型 | 描述 | 访问宏 |
---|---|---|
int ht |
用户实际传递参数的数量 | ZEND_NUM_ARGS() |
zval *return_value |
PHP 变量的指针,可填充返回值传递给用户。默认值是 IS_NULL 。 |
RETVAL_* , RETURN_* |
zval **return_value_ptr |
当返回引用时,PHP 将其设为变量的指针。不建议返回引用。 | |
zval *this_ptr |
假如这是一个方法调用,其指向存放 $this 对象的 PHP 变量。 |
getThis() |
int return_value_used |
指示返回值是否会被调用者使用的标志。 caller. |
函数入口可含有一个对参数信息结构的指针。 不是必须要提供此信息,除非打算接受参数引用或返回一个引用,及提供由 PHP 的反射 API 访问的信息。参数可以直接作为函数参数传递,也可以是通过一个堆栈(stack)
2、用于返回值的宏
a)RETURN_BOOL(0); //返回bool值
#define RETVAL_BOOL(b) ZVAL_BOOL(return_value, b)
#define RETURN_BOOL(b) { RETVAL_BOOL(b); return; }
#define ZVAL_BOOL(z, b) do { \
zval *__z = (z); \
Z_LVAL_P(__z) = ((b) != 0); \
Z_TYPE_P(__z) = IS_BOOL; \
} while (0)
所以展开这个RETURN_BOOL(0),最终在函数里返回值的操作即是
do {
zval *__z = (return_value);
Z_LVAL_P(__z) = ((0) != 0); //定义return_value值
Z_TYPE_P(__z) = IS_BOOL; //定义return_value的类型
}while(0)
b) RETURN_STRING("hello world", 1);
展开之后
do {
const char *__s = ("hello world");
zval *__z = return_value;
Z_STRLEN_P(__z) = strlen(__s);//定义长度
Z_STRVAL_P(__z) = (1?estrndup(__s, Z_STRLEN_P(__z)):(char*)__s);//定义值,estrndup函数实现字符串的复制
Z_TYPE_P(__z) = IS_STRING;
}while(0)
c) RETURN_LONG(100);
展开之后
zval *__z = return_value;
Z_LVAL_P(__z) = 100;
Z_TYPE_P(__z) = IS_LONG;
d)返回数组
array_init(return_value);//初始化return_value成数组,此操作完后就可以返回一个空的数组
e)返回object
object_init(return_value);//初始化return_value成Object,此操作完成后返回一个空的对像
其他的
#define ZVAL_FALSE(z) ZVAL_BOOL(z, 0)
#define ZVAL_TRUE(z) ZVAL_BOOL(z, 1) #define RETVAL_RESOURCE(l) ZVAL_RESOURCE(return_value, l)
#define RETVAL_BOOL(b) ZVAL_BOOL(return_value, b)
#define RETVAL_NULL() ZVAL_NULL(return_value)
#define RETVAL_LONG(l) ZVAL_LONG(return_value, l)
#define RETVAL_DOUBLE(d) ZVAL_DOUBLE(return_value, d)
#define RETVAL_STRING(s, duplicate) ZVAL_STRING(return_value, s, duplicate)
#define RETVAL_STRINGL(s, l, duplicate) ZVAL_STRINGL(return_value, s, l, duplicate)
#define RETVAL_EMPTY_STRING() ZVAL_EMPTY_STRING(return_value)
#define RETVAL_ZVAL(zv, copy, dtor) ZVAL_ZVAL(return_value, zv, copy, dtor)
#define RETVAL_FALSE ZVAL_BOOL(return_value, 0)
#define RETVAL_TRUE ZVAL_BOOL(return_value, 1) #define RETURN_RESOURCE(l) { RETVAL_RESOURCE(l); return; }
#define RETURN_BOOL(b) { RETVAL_BOOL(b); return; }
#define RETURN_NULL() { RETVAL_NULL(); return;}
#define RETURN_LONG(l) { RETVAL_LONG(l); return; }
#define RETURN_DOUBLE(d) { RETVAL_DOUBLE(d); return; }
#define RETURN_STRING(s, duplicate) { RETVAL_STRING(s, duplicate); return; }
#define RETURN_STRINGL(s, l, duplicate) { RETVAL_STRINGL(s, l, duplicate); return; }
#define RETURN_EMPTY_STRING() { RETVAL_EMPTY_STRING(); return; }
#define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; }
#define RETURN_FALSE { RETVAL_FALSE; return; }
#define RETURN_TRUE { RETVAL_TRUE; return; }
3、数组以及对象的操作
zval *arr;
MAKE_STD_ZVAL(arr);
array_init(arr); //$arr = array();
add_assoc_long(arr, "a", 10); //$arr["a"] = 10;
add_asoc_unset(arr, "a"); //unset(arr["a"]);
add_assoc_bool(arr, "b", 1); //$arr["b"] = true;
add_assoc_resource(arr, "c", 10); //$arr["c"] = $resource;
add_assoc_double(arr, "d", 2.15); //$arr["d"] = 2.15;
add_assoc_string(arr, "e", "hello", 1); //$arr["e"] = "hello";最后一个参数表示字符串值是否复制
add_assoc_stringl(); zval *sub;
MAKE_STD_ZVAL(sub);
array_init(sub);
add_assoc_zval(arr, "f", sub); //$arr["f"] = $sub; zval *arr;
MAKE_STD_ZVAL(arr);
array_init(arr); //$arr = array();
add_index_long(arr, 1, 10); //$arr[1] = 10;
add_index_unset(arr, 1); //unset($arr[1]);
add_index_bool(arr, 2, 1); //$arr[2] = true;
add_index_resource(arr, 3, 10); //$arr[3] = $resource;
add_index_double(arr, 4, 2.15); //$arr[4] = 2.15;
add_index_string(arr, 5, "hello", 1); //$arr[5] = "hello";最后一个参数表示字符串值是否复制
add_index_stringl(); zval *sub;
MAKE_STD_ZVAL(sub);
array_init(sub);
add_index_zval(arr, 6, sub); //$arr[6] = $sub; zval *arr;
MAKE_STD_ZVAL(arr);
array_init(arr); //$arr = array();
add_next_index_long(arr, 10); //$arr[] = 10;
add_next_index_unset(arr); //unset($arr[]);
add_next_index_bool(arr, 1); //$arr[] = true;
add_next_index_resource(arr, 10); //$arr[] = $resource;
add_next_index_double(arr, 2.15); //$arr[] = 2.15;
add_next_index_string(arr, "hello", 1); //$arr[] = "hello";最后一个参数表示字符串值是否复制
add_next_index_stringl(); zval *sub;
MAKE_STD_ZVAL(sub);
array_init(sub);
add_next_index_zval(arr, sub); //$arr[] = $sub; zval *obj;
MAKE_STD_ZVAL(obj);
object_init(obj);//$obj = new stdClass;
add_property_long(obj, "a", 10); //$obj->a = 10;
add_property_unset(obj, "a"); //unset($obj->a);
add_property_bool(obj, "b", 1); //$obj->b = true;
add_property_resource(obj, "c", 10); //$obj->c = $resource;
add_property_double(obj, "d", 2.15); //$obj->d = 2.15;
add_property_string(obj, "e", "hello", 1);//$obj->e = "hello"; 最后一个参数表示字符串值是否复制
add_property_stringl(); zval *sub;
MAKE_STD_ZVAL(sub);
object_init(sub); //$sub = new stdClass;
add_property_zval(obj, "f", sub); //$obj->f = $sub;
一些操作的宏
#define Z_LVAL(zval) (zval).value.lval
#define Z_BVAL(zval) ((zend_bool)(zval).value.lval)
#define Z_DVAL(zval) (zval).value.dval
#define Z_STRVAL(zval) (zval).value.str.val
#define Z_STRLEN(zval) (zval).value.str.len
#define Z_ARRVAL(zval) (zval).value.ht
#define Z_OBJVAL(zval) (zval).value.obj
#define Z_OBJ_HANDLE(zval) Z_OBJVAL(zval).handle
#define Z_OBJ_HT(zval) Z_OBJVAL(zval).handlers
#define Z_OBJCE(zval) zend_get_class_entry(&(zval) TSRMLS_CC)
#define Z_OBJPROP(zval) Z_OBJ_HT((zval))->get_properties(&(zval) TSRMLS_CC)
#define Z_OBJ_HANDLER(zval, hf) Z_OBJ_HT((zval))->hf
#define Z_RESVAL(zval) (zval).value.lval
#define Z_OBJDEBUG(zval,is_tmp) (Z_OBJ_HANDLER((zval),\
get_debug_info)?Z_OBJ_HANDLER((zval),get_debug_info)(&(zval),\
&is_tmp TSRMLS_CC):(is_tmp=0,Z_OBJ_HANDLER((zval),get_properties)?Z_OBJPROP(zval):NULL)) #define Z_LVAL_P(zval_p) Z_LVAL(*zval_p)
#define Z_BVAL_P(zval_p) Z_BVAL(*zval_p)
#define Z_DVAL_P(zval_p) Z_DVAL(*zval_p)
#define Z_STRVAL_P(zval_p) Z_STRVAL(*zval_p)
#define Z_STRLEN_P(zval_p) Z_STRLEN(*zval_p)
#define Z_ARRVAL_P(zval_p) Z_ARRVAL(*zval_p)
#define Z_OBJPROP_P(zval_p) Z_OBJPROP(*zval_p)
#define Z_OBJCE_P(zval_p) Z_OBJCE(*zval_p)
#define Z_RESVAL_P(zval_p) Z_RESVAL(*zval_p)
#define Z_OBJVAL_P(zval_p) Z_OBJVAL(*zval_p)
#define Z_OBJ_HANDLE_P(zval_p) Z_OBJ_HANDLE(*zval_p)
#define Z_OBJ_HT_P(zval_p) Z_OBJ_HT(*zval_p)
#define Z_OBJ_HANDLER_P(zval_p, h) Z_OBJ_HANDLER(*zval_p, h) #define Z_OBJDEBUG_P(zval_p,is_tmp) Z_OBJDEBUG(*zval_p,is_tmp) #define Z_LVAL_PP(zval_pp) Z_LVAL(**zval_pp)
#define Z_BVAL_PP(zval_pp) Z_BVAL(**zval_pp)
#define Z_DVAL_PP(zval_pp) Z_DVAL(**zval_pp)
#define Z_STRVAL_PP(zval_pp) Z_STRVAL(**zval_pp)
#define Z_STRLEN_PP(zval_pp) Z_STRLEN(**zval_pp)
#define Z_ARRVAL_PP(zval_pp) Z_ARRVAL(**zval_pp)
#define Z_OBJPROP_PP(zval_pp) Z_OBJPROP(**zval_pp)
#define Z_OBJCE_PP(zval_pp) Z_OBJCE(**zval_pp)
#define Z_RESVAL_PP(zval_pp) Z_RESVAL(**zval_pp)
#define Z_OBJVAL_PP(zval_pp) Z_OBJVAL(**zval_pp)
#define Z_OBJ_HANDLE_PP(zval_p) Z_OBJ_HANDLE(**zval_p)
#define Z_OBJ_HT_PP(zval_p) Z_OBJ_HT(**zval_p)
#define Z_OBJ_HANDLER_PP(zval_p, h) Z_OBJ_HANDLER(**zval_p, h)
#define Z_OBJDEBUG_PP(zval_pp,is_tmp) Z_OBJDEBUG(**zval_pp,is_tmp) #define Z_TYPE(zval) (zval).type
#define Z_TYPE_P(zval_p) Z_TYPE(*zval_p)
#define Z_TYPE_PP(zval_pp) Z_TYPE(**zval_pp)
深入PHP内核之函数和返回值的更多相关文章
- 测试函数用Return 返回值和用函数名返回值的区别
'*************************************************************************'**模 块 名:工程1 - Form1'**说 ...
- Shell入门教程:Shell函数的返回值
shell函数返回值一般有3种方式: 1.return语句(默认的返回值) shell函数的返回值可以和其他语言的返回值一样,通过return语句返回. 比如: #!/bin/bash functio ...
- GDB 修改当前判断函数的返回值(即修改寄存器的值)的方法
工作中遇到的问题: 在GDB调试时要进入下边该判断后边的函数,而m_EtherDecode.Chk_MakeSure_IP_Pkt(pPacket,dwPacketLen)的返回值是false,所以需 ...
- JavaScript 在函数中使用Ajax获取的值作为函数的返回值
解决:JavaScript 在函数中使用Ajax获取的值作为函数的返回值,结果无法获取到返回值 原因:ajax默认使用异步方式,要将异步改为同步方式 案例:通过区域ID,获取该区域下所有的学校 var ...
- c++特性:指向类成员的指针和非类型类模板参数和函数指针返回值 参数推导机制和关联型别
一.c++允许定义指向类成员的指针,包括类函数成员指针和类数据成员指针 格式如下: class A { public: void func(){printf("This is a funct ...
- getchar()函数的返回值赋给char型,用if(ch=getchar() != EOF)测试,输入ctrl+z同样可以结束循环的分析
2013-07-18 21:35:58 getchar()函数的返回值赋给char型,用if(ch=getchar() != EOF)测试,输入ctrl+z同样可以结束循环的分析. char是字符型数 ...
- Python的函数式编程-传入函数、排序算法、函数作为返回值、匿名函数、偏函数、装饰器
函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基本单元. ...
- (转)函数中使用 ajax 异步 同步 返回值错误 主函数显示返回值总是undefined -- ajax使用总结
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAloAAAE0CAIAAAB7LwoKAAAgAElEQVR4nO2dy6sc152A6+/R2mXwSn ...
- SendMessage的返回值,就是由相应的响应消息函数的返回值(解释的简洁明了)
SendMessage Return Values The return value specifies the result of the message processing and depend ...
随机推荐
- iframe在ie和firefox中的高度兼容性问题解决
1.问题描述: <iframe src="p_photo_cont_iframe.html" name="iframe" width="700& ...
- 使用开源库 TWMessageBarManager 展示系统级别的通知
TWMessageBarManager 简单翻译 https://github.com/terryworona/TWMessageBarManager An iOS manager for prese ...
- eclipse无法启动
-startupplugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar-showsplashorg.eclipse.platfo ...
- 在Ubuntu 12.04 桌面上设置启动器(快捷方式)
在Ubuntu 12.04 桌面上设置启动器(快捷方式)过程讲解: 如下图所示,Eclipse 和 SQLDeveloper 都可以直接双击打开,这些应用程序的启动器都在 /usr/share/app ...
- 一个常见下拉菜单的样式:一体化小三角(纯css手写解决)
类似下拉菜单2个一体化小三角,习惯上用字体图标加jQuery处理,比较方便,但是下面纯css手写解决方式,效果也还不错,对CSS知识也是一个比较好的孔固. 小三角用了2种不同处理方式:1.利用bord ...
- Back Track 5 之 网络踩点(二)
操作系统探测 Xprobe2 通过ICMP协议来获得指纹,通过模糊矩阵统计分析主动探测数据包对应的ICMP数据特征,进而探测得到远端操作系统的类型. 格式: ./xprobe2 域名 ./xprobe ...
- Cognos开发图表乱码问题
在此之前提到过在利用TR建模导入IQD数据源的时候遇到乱码的一种解决方案: http://www.cnblogs.com/wxjnew/p/3374029.html 今天说的是在RS中开发新报表的时候 ...
- 如何解决SPD的缓存问题
SPD有时候文件被缓存住了,表现为文件的最后更改时间不对,或者本来文件已经被check in了,但是显示check out状态,而此时如果选择check in, 就会提示文件没有被check ou ...
- Java 抽象类和接口有什么差别
抽象类和接口有什么差别? 1. 抽象类在java语言中所表示的是一种继承关系,一个子类仅仅能继承一个父类.可是能够实现多个接口. 2. 在抽象类中能够拥有自己的成员变量和非抽象类方法,可是接口中仅仅能 ...
- C++学习笔记12-模板1
1. 函数模板 函数模板是一个独立于类型的函数,可作为一种方式.产生函数的特定类型版本号. // implement strcmp-like generic compare function // ...