声明:本文为斯人原创,全部为作者一一分析得之,有不对的地方望赐教。
博客地址:
PHP技术博客在CSDN也会同步更新的哦.
欢迎转载,转载请注明出处
上一节讲到 函数的参数
下面继续分析函数的返回值..
从根本来说,PHP的每个函数或方法都存在返回值,可能有的时候不写return,
这个时候 会返回NULL.
[php]
function test(){
return 1;
}
[/php]
经过分析找到token
[c]
T_RETURN ';' { zend_do_return(NULL, 0 TSRM LS_CC); }
| T_RETURN expr_without_variable ';' { zend_do_return(&$2, 0 TSRMLS_CC); }
| T_RETURN variable ';' { zend_do_return(&$2, 1 TSRMLS_CC); }
[/c]
上面三个token代表函数返回的三种形式,
return ;
return 立即数(字符串);
return 变量; //返回变量/引用返回
执行的函数为 zend_do_return
PHP对三种不同的返回值做了不同的处理.我们详细来看一下
zend_do_return(NULL, 0 TSRM LS_CC);是返回NULL
zend_do_return(&$2, 0 TSRMLS_CC); //直接返回 立即数或字符串
zend_do_return(&$2, 1 TSRMLS_CC); //返回变量/引用返回
定义如下Zend/zend_compile.c
[c]
void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */{ zend_op *opline;
int start_op_number, end_op_number;
if (do_end_vparse) {//引用返回
if (CG(active_op_array)->return_reference && !zend_is_function_or_method_call(expr)) {
zend_do_end_variable_parse(expr, BP_VAR_W, 0 TSRMLS_CC);//引用返回
} else {
zend_do_end_variable_parse(expr, BP_VAR_R, 0 TSRMLS_CC);//普通变量返回
}
}
//当前op位置
start_op_number = get_next_op_number(CG(active_op_array));
#ifdef ZTS
zend_stack_apply(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_foreach_copy);
#endif
end_op_number = get_next_op_number(CG(active_op_array));
while (start_op_number < end_op_number) {
CG(active_op_array)->opcodes[start_op_number].op1.u.EA.type = EXT_TYPE_FREE_ON_RETURN;
start_op_number++;
}
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
//生成中间代码
opline->opcode = ZEND_RETURN;
if (expr) {
opline->op1 = *expr;
if (do_end_vparse && zend_is_function_or_method_call(expr)) {
opline->extended_value = ZEND_RETURNS_FUNCTION;
}
} else {
opline->op1.op_type = IS_CONST;
INIT_ZVAL(opline->op1.u.constant);
}
SET_UNUSED(opline->op2);
}
[/c]
根据操作数的不同,ZEND_RETURN中间代码会执行 ZEND_RETURN_SPEC_CONST_HANDLER, ZEND_RETURN_SPEC_TMP_HANDLER或ZEND_RETURN_SPEC_TMP_HANDLER.这几个代码流程基本相同
以 ZEND_RETURN_SPEC_CONST_HANDLER为例.
[c]
static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op *opline = EX(opline);
zval *retval_ptr;
zval **retval_ptr_ptr;
if (EG(active_op_array)->return_reference == ZEND_RETURN_REF) {//引用返回
if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) {//变量和临时变量是不能引用传递的
/* Not supposed to happen, but we'll allow it */
zend_error(E_NOTICE, "Only variable references should be returned by reference");
goto return_by_value; }
retval_ptr_ptr = NULL;//返回值初始化NULL
if (IS_CONST == IS_VAR && !retval_ptr_ptr) {
zend_error_noreturn(E_ERROR, "Cannot return string offsets by reference");
}
if (IS_CONST == IS_VAR && !Z_ISREF_PP(retval_ptr_ptr)) {
if (opline->extended_value == ZEND_RETURNS_FUNCTION &&
EX_T(opline->op1.u.var).var.fcall_returned_reference) {
if (IS_CONST == IS_VAR && !0) {
}
goto return_by_value;
}
}
if (EG(return_value_ptr_ptr)) {
SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr);//设置is_ref__gc 为1
Z_ADDREF_PP(retval_ptr_ptr);//refcount__gc+1
(*EG(return_value_ptr_ptr)) = (*retval_ptr_ptr);
}
} else {
return_by_value:
retval_ptr = &opline->op1.u.constant;
if (!EG(return_value_ptr_ptr)) {
if (IS_CONST == IS_TMP_VAR) {
}
} else if (!0) { /* Not a temp var */
if (IS_CONST == IS_CONST ||
EG(active_op_array)->return_reference == ZEND_RETURN_REF ||
(PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) {
zval *ret;
ALLOC_ZVAL(ret);
INIT_PZVAL_COPY(ret, retval_ptr);
zval_copy_ctor(ret);
*EG(return_value_ptr_ptr) = ret;
} else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) &&
retval_ptr == &EG(uninitialized_zval)) {
zval *ret;
ALLOC_INIT_ZVAL(ret);
*EG(return_value_ptr_ptr) = ret;
} else {
*EG(return_value_ptr_ptr) = retval_ptr;
Z_ADDREF_P(retval_ptr);
}
} else {
zval *ret;
ALLOC_ZVAL(ret);
INIT_PZVAL_COPY(ret, retval_ptr);
*EG(return_value_ptr_ptr) = ret;
}
}
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
[/c]
函数返回值 存储在EG(return_value_ptr_ptr);
当然 PHP还有很多 用于函数返回的内置宏如
RETURN_BOOL
RETURN_NULL
RETURN_RESOURCE
RETURN_LONG
RETURN_DOUBLE
等等...
原文出处:原:PHP内核研究
函数的返回值
分享到:
相关推荐
6. 函数的返回值和参数:主要学习函数的返回值的处理,以及如何解析函数的参数。 7. Array与HashTable:介绍数组在PHP内核中的表现形式,如何操作HashTable以及在内核中操作PHP语言中的数组。 8. PHP中的资源类型...
- **返回值处理**:函数返回值的处理同样非常重要,这涉及到如何正确释放不再使用的资源,以及如何高效地返回结果。 ##### 3. 类与面向对象 - **类定义与实例化**:类的定义与实例化过程涉及到类表、对象属性和方法...
《深入理解PHP内核》是一本专为PHP开发者和爱好者量身打造的开源书籍,它深入探讨了PHP的内部机制,旨在帮助读者更好地理解和优化PHP应用程序。这本书涵盖了从基础到高级的各种主题,包括PHP的环境配置、源码解读、...
PHP7还引入了 scalar type hints,允许函数参数和返回值指定为 int, float, string 或 bool 类型,这有助于避免类型转换带来的潜在问题。同时,void 关键字用于表示函数没有返回值,增强了代码的可读性和规范性。 ...
《PHP扩展开发及内核应用》是一本深入探讨PHP扩展编程和PHP内核机制的书籍,基于Sara Golemon的《Extending and Embedding PHP》进行翻译和修订,主要面向那些希望深入了解PHP并可能想要为其开发自定义扩展的开发者...
PHP内核和扩展开发是一个复杂但有趣的领域,它涉及到内存管理、数据结构、函数调用等多个层面。掌握这些知识不仅可以帮助开发者更有效地编写PHP扩展,还能深化对PHP内核的理解,提升编程技能。通过本文的详细介绍,...
扩展编写通常包括声明导出函数、填写模块信息、实现导出函数、处理参数传递、编译检查、返回值处理等步骤。 ##### HelloWorld扩展示例 1. **声明导出函数** - 编写C语言函数,定义为PHP的函数。 2. **声明导出函数...
06.函数的返回值.md 07.函数的参数.md 08.Array与HashTable.md 09.PHP中的资源类型.md 10.PHP中的面向对象上篇.md 11.PHP中的面向对象下篇.md 12.启动与终止的那点事.md 13.ini配置文件.md 14.流式访问.md 门 15...
《PHP7内核剖析》是深入理解PHP编程技术的一个重要课题,主要涵盖了PHP7的核心架构、内部机制以及优化策略。这个主题旨在帮助开发者们更好地掌握PHP7的内部工作原理,从而提升开发效率和代码质量。在PHP7中,Zend...
开发PHP扩展涉及C语言编程,需要理解ZEND_API和PHP内核的工作原理。PHP SDK提供的工具简化了这一过程,使得创建、测试和调试扩展变得更加容易。开发者可以使用这些工具来编译PHP源代码,生成适用于PHP 7.0的二进制...
3. **类型提示增强**:在函数参数和返回值上可以使用`union types(联合类型)`,如`function foo(string|int $x): string|bool`,允许参数或返回值为多种类型。 4. **预加载(Preloading)**:PHP 7.4引入了预加载...
- **返回类型声明**:PHP 7.2允许函数声明返回值的类型,例如可以指定函数必须返回整数或字符串等特定类型的值。 - **可空类型声明**:支持对参数和返回类型使用可空类型(`?Type`),这意味着函数可以接受特定类型...
5. **PHP扩展开发**:如果对PHP内核有一定了解,可以尝试开发自己的PHP扩展。 **实际应用** 1. **Web框架**:介绍如Laravel、Symfony、Yii等流行的PHP框架,以及它们的核心概念和使用方法。 2. **CMS系统**:如...
第9章 扩充PHP 4.0:探究PHP内核 221 9.1 概述 221 9.2 什么是Zend?什么是PHP? 221 9.3 扩充可能性 222 9.3.1 外部模块 222 9.3.2 内嵌模块 223 9.3.3 Zend引擎 223 9.4 源代码格式 223 9.4.1 宏 224 9.4.2 内存...
第9章 扩充PHP 4.0:探究PHP内核 221 9.1 概述 221 9.2 什么是Zend?什么是PHP? 221 9.3 扩充可能性 222 9.3.1 外部模块 222 9.3.2 内嵌模块 223 9.3.3 Zend引擎 223 9.4 源代码格式 223 9.4.1 宏 224 9.4.2 内存...
1. 类型声明:使用类型声明可以确保函数参数和返回值的类型安全,避免类型不匹配导致的错误,提高代码稳定性。 2. 异常处理:正确使用try-catch语句捕获并处理异常,提高程序健壮性。 3. PHP魔术方法:如__get()、...