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)
{
}

参数解释

INTERNAL_FUNCTION_PARAMETERS
名称和类型 描述 访问宏
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内核之函数和返回值的更多相关文章

  1. 测试函数用Return 返回值和用函数名返回值的区别

    '*************************************************************************'**模 块 名:工程1 - Form1'**说   ...

  2. Shell入门教程:Shell函数的返回值

    shell函数返回值一般有3种方式: 1.return语句(默认的返回值) shell函数的返回值可以和其他语言的返回值一样,通过return语句返回. 比如: #!/bin/bash functio ...

  3. GDB 修改当前判断函数的返回值(即修改寄存器的值)的方法

    工作中遇到的问题: 在GDB调试时要进入下边该判断后边的函数,而m_EtherDecode.Chk_MakeSure_IP_Pkt(pPacket,dwPacketLen)的返回值是false,所以需 ...

  4. JavaScript 在函数中使用Ajax获取的值作为函数的返回值

    解决:JavaScript 在函数中使用Ajax获取的值作为函数的返回值,结果无法获取到返回值 原因:ajax默认使用异步方式,要将异步改为同步方式 案例:通过区域ID,获取该区域下所有的学校 var ...

  5. c++特性:指向类成员的指针和非类型类模板参数和函数指针返回值 参数推导机制和关联型别

    一.c++允许定义指向类成员的指针,包括类函数成员指针和类数据成员指针 格式如下: class A { public: void func(){printf("This is a funct ...

  6. getchar()函数的返回值赋给char型,用if(ch=getchar() != EOF)测试,输入ctrl+z同样可以结束循环的分析

    2013-07-18 21:35:58 getchar()函数的返回值赋给char型,用if(ch=getchar() != EOF)测试,输入ctrl+z同样可以结束循环的分析. char是字符型数 ...

  7. Python的函数式编程-传入函数、排序算法、函数作为返回值、匿名函数、偏函数、装饰器

    函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基本单元. ...

  8. (转)函数中使用 ajax 异步 同步 返回值错误 主函数显示返回值总是undefined -- ajax使用总结

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAloAAAE0CAIAAAB7LwoKAAAgAElEQVR4nO2dy6sc152A6+/R2mXwSn ...

  9. SendMessage的返回值,就是由相应的响应消息函数的返回值(解释的简洁明了)

    SendMessage Return Values The return value specifies the result of the message processing and depend ...

随机推荐

  1. 初识Tomcat

    Tomcat的安装非常简单,解压即可! Tomcat要正常运行,需要配置一个环境变量JAVA_HOME,指向jdk的主目录.

  2. 第三章 mybatis-generator + mysql/ptsql

    用了mybatis-generator,我就不再想用注解了,这与我之前说的注解与XML并用是矛盾的,知识嘛,本来就是多元化的,今天喜欢这个,明天喜欢那个,哈哈,看了mybatis-generator下 ...

  3. 第七章 Xmemcached客户端介绍

    提示:有关于XMemcached在实际开发中的具体使用,查看"Java企业项目开发实践"系列博客的<第八章 企业项目开发--分布式缓存memcached> 注意:本文主 ...

  4. 第十二章 ThreadPoolExecutor使用 + 工作机理 + 生命周期

    1.最基础的线程池ThreadPoolExecutor 使用方式: /** * ThreadPoolExecutor测试类 * 注意: * 1.ThreadPoolExecutor是一个线程池 * 2 ...

  5. [置顶] Django 微信开发(一)——环境搭建

    Django 微信开发(一)——环境搭建 随着移动互联网时代的到来,微信——一个改变着我们生活的产品悄悄走近了我们的生活.我们不得不觉得自己很幸运,自己能在这个世界上遇到像QQ.微博.微信这样优秀的产 ...

  6. opencv学习_5 (IplImage的结构)

    IplImage结构体为: typedef struct _IplImage { int nSize; /* IplImage大小 */ int ID; /* 版本 (=0)*/ int nChann ...

  7. go的基结构体如何使用派生结构体的方法

    将派生类的方法声明为接口嵌入到基结构体中,派生结构体声明该接口为自身.

  8. iOS开发-CoreMotion框架(加速计和陀螺仪)

    CoreMotion是一个专门处理Motion的框架,其中包含了两个部分加速度计和陀螺仪,在iOS4之前加速度计是由UIAccelerometer类来负责采集数据,现在一般都是用CoreMotion来 ...

  9. 理解JavaScript里this关键字

    1.全局代码中的this:始终指向window 2.函数代码中的this: }; var bar = { x: , test: function () { alert(this === bar); a ...

  10. Oracle基础重点概要

    表空间                                                                 逻辑上处于数据库之下,利用表空间可以更灵活地规划数据库结构. 创 ...