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. Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!

    执行Maven Install打包的时候,提示以下警告信息: [WARNING] Using platform encoding (GBK actually) to copy filtered res ...

  2. pom-4.0.0.xml中心仓库

    <!--Licensed to the Apache Software Foundation (ASF) under oneor more contributor license agreeme ...

  3. H264 RTP封包原理(转载)

    1.  引言        随着信息产业的发展,人们对信息资源的要求已经逐渐由文字和图片过渡到音频和视频,并越来越强调获取资源的实时性和互动性.但人们又面临着另外一种不可避免的尴尬,就是在网络上看到生 ...

  4. poj 1201 Intervals 解题报告

    Intervals Time Limit: 2000MS   Memory Limit: 65536KB   64bit IO Format: %lld & %llu Submit Statu ...

  5. GUI程序设计2

    8. 按钮(JButton)使用示例 例14. 按钮使用示例. package GUI; import java.awt.BorderLayout; import java.awt.Container ...

  6. Objective-C:NSMutableString类的常见操作

    NSMutableString可变字符串的主要的操作是创建.增加.删除.插入.替换 代码操作如下: // // main.m // 03-NSMutableString // // Created b ...

  7. elasticSearch nested exist与missing查询

    elasticSearch nested查询,简单意义上,你可以理解为,它不会被索引,只是被暂时隐藏起来,而查询的时候,开关就是使用nested query/filter去查询 下面我有一个例子,是查 ...

  8. Window 下安装 Redis

    Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. 一.Window 下安装 redis https://github.com/MicrosoftArchive/r ...

  9. [Node.js] Load balancing a Http server

    Let's see how to do load balancing in Node.js. Before we start with the solution, you can do a test ...

  10. 装上了Fedora19

    超期服役的Aspire黑机器在一个下午主动退役了,为了填补它留下的空白,趁JD减价入手了一台宏碁(acer) SQX4610 120N,就为了玩Linux. 这机器用光驱启动有些特殊,需要在启动时不断 ...