一起源码网

  • QingYuanMa.com
  • 全球最大的互联网技术和资源下载平台
搜索
猜你喜欢
查看: 9488|回复: 1
打印 上一主题 下一主题

深入了解php自定义函数的参数传递

[复制链接]

0

主题

0

帖子

1万

积分

钻石会员

Rank: 8Rank: 8

积分
17424
QQ
跳转到指定楼层
楼主
发表于 2020-3-7 03:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
函数的参数

函数的定义只是一个将函数名注册到函数列表的过程。

1、用户的参数

我们知道对于函数的参数检查是通过zend_do_receive_arg函数来实现的,在此函数中对于参数的关键代码如下:

CG(active_op_array)->arg_info = erealloc(CG(active_op_array)->arg_info,
        sizeof(zend_arg_info)*(CG(active_op_array)->num_args));
cur_arg_info = &CG(active_op_array)->arg_info[CG(active_op_array)->num_args-1];
cur_arg_info->name = estrndup(varname->u.constant.value.str.val,
        varname->u.constant.value.str.len);
cur_arg_info->name_len = varname->u.constant.value.str.len;
cur_arg_info->array_type_hint = 0;
cur_arg_info->allow_null = 1;
cur_arg_info->pass_by_reference = pass_by_reference;
cur_arg_info->class_name = NULL;
cur_arg_info->class_name_len = 0;

 整个参数的传递是通过给中间代码的arg_info字段执行赋值操作完成。关键点是在arg_info字段,arg_info字段的结构如下:

typedef struct _zend_arg_info {
    const char *name;   /*参数的名称*/
    zend_uint name_len;     /*参数名称的长度*/
    const char *class_name; /* 类名*/
     zend_uint class_name_len;   /*类名长度*/
    zend_bool array_type_hint;  /*数组类型提示*/
    zend_bool allow_null;   /*是否允许为NULLͺ*/
    zend_bool pass_by_reference;    /*是否引用传递*/
    zend_bool return_reference; 
    int required_num_args;  
} zend_arg_info;

参数的值传递和参数传递的区别是通过pass_by_reference参数在生成中间代码时实现的。

  对于参数的个数,中间代码中包含的arg_nums字段在每次执行**zend_do_receive_argxx时都会加1.如下代码:

CG(active_op_array)->num_args++;

  并且当前参数的索引为ŒCG(active_op_array)->num_args-1.如下代码:

cur_arg_info = &CG(active_op_array)->arg_info[CG(active_op_array)->num_args-1];

  以上的分析是针对函数定义时的参数设置,这些参数是固定的。而在实际编写程序时可能我们会用到。此时我们会用到函数func_num_args和func_get_args。它们是以存在。于是在Zendzend_builtin_functions.c文件中找到这两个函数的实现。我们首先来看func_num_args函数的实现,其代码如下:

/* {{{ proto int func_num_args(void)
   Get the number of arguments that were passed to the function */
ZEND_FUNCTION(func_num_args)
{
    zend_execute_data *ex = EG(current_execute_data)->prev_execute_data;
 
    if (ex && ex->function_state.arguments) {
        RETURN_LONG((long)(zend_uintptr_t)*(ex->function_state.arguments));
    } else {
        zend_error(E_WARNING,
"func_num_args():  Called from the global scope - no function context");
        RETURN_LONG(-1);
    }
}
/* }}} */

 在存在ex->function_state.arguments的情况下,及函数调用时,返回ex->function_state.arguments转化后的值,否则显示错误并返回-1。这里最关键的一点是EG(current_execute_data)。这个变量存放的是当前执行程序或函数的数据,此时我们需要取前一个执行程序的数据,为什么呢?因为这个函数的调用是在进入函数后执行的。函数的相关数据等都在之前执行过程中,于是调用的是:

zend_execute_data *ex = EG(current_execute_data)->prev_execute_data;

2、内部函数的参数

以常见的count函数为例,其参数处理部分的代码如下:

/* {{{ proto int count(mixed var [, int mode])
   Count the number of elements in a variable (usually an array) */
PHP_FUNCTION(count)
{
    zval *array;
    long mode = COUNT_NORMAL;
 
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l",
         &array, &mode) == FAILURE) {
        return;
    }
    ... //省略
}

 这里包括了两个操作:一个是取参数的个数,一个是解析参数列表。

(1)取参数的个数

取参数的个数是通过ZEND_NUM_ARGS()宏来实现的,其定义如下:

#define ZEND_NUM_ARGS()     (ht)

ht是在Zend/zend.h文件中定义的宏INTERNAL_FUNCTION_PARAMETERS中的ht,如下

#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value,
zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC

(2)解析参数列表

PHP内部函数在解析参数时使用的是zend_parse_parameters。它可以大大简化参数的接收处理工作,虽然它在处理可变参数时还有点弱。

其声明如下:

ZEND_API int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, 
...)

第一个参数num_args表明表示想要接收的参数个数,我们经常使用ZEND_NUM_ARGS()来表示对传入的参数“有多少要多少”

第二个参数应该是宏TSRMLS_CC。

第三个参数type_spec是一个字符串,用来指定我们所期待接收的各个参数的类型,有点类似于printf中指定输出格式的那个。

剩下的参数就是我们用来接收PHP参数值的变量的指针。

zend_parse_parameters()在解析参数的同时户尽可能的转换参数类型,这样就可以确保我们总是能得到所期望的类型的变量

以上就是深入了解php自定义函数的参数传递的详细内容,更多请关注php中文网其它相关文章!

分享到:  QQ好友和群QQ好友和群
收藏收藏
回复

使用道具 举报

0

主题

18

帖子

60

积分

注册会员

Rank: 2

积分
60
沙发
发表于 2022-9-3 16:52 来自手机 | 只看该作者
游戏源码免费下载
回复

使用道具 举报

轻源码让程序更轻更快

QingYuanMa.com

工作时间 周一至周六 8:00-17:30

侵权处理

客服QQ点击咨询

关注抖音号

定期抽VIP

Copyright © 2016-2021 https://www.171739.xyz/ 滇ICP备13200218号

快速回复 返回顶部 返回列表