Skip to content

Latest commit

 

History

History
146 lines (115 loc) · 6.74 KB

4.写函数 [ Writing Functions ].md

File metadata and controls

146 lines (115 loc) · 6.74 KB
/*
|----------------------------------------
| Writing Functions
| @weiChen translate, <[email protected]>
| @MIT License
*/

http://php.net/manual/en/internals2.funcs.php

PHP中的函数和方法采用同样的方式,一个方法就是一个有指定作用范围的函数;它们类区域的范围。
Hacker 可以在指南的其它章节中读到关于类的入口。本节的目的是给Hacker剖析函数或方法;
Hacker将学到如何定义方法,如何接收变量和如何返回变量给phper。

一个不能再简单的函数结构:

PHP_FUNCTION(Hackers_function) {
    /* your accepted arguments here */
    long numer;
    
    /* accepting arguments */
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "1", &number) != SUCCESS) {
      return;
    }
    
    /* do some work on the input */
    number *= 2;
    
    /* set return value */
    RETURN_LONG(number);
}

PHP_FUNCTION(hackers_function) 预处理器指令将生成下面的声明:

void zif_hackers_function(INTERNAL_FUNCTION_PARAMETERS)

INTERNAL_FUNCTION_PARAMETERS 作为宏被定义,并被解释成下表中的:

名字和类型 描述 访问宏
int ht 用户传递的实际参数数量 ZEND_NUM_ARGS()
zval* return_value 由返回值填充的传递给用户的PHP变量指针,默认类型是 IS_NULL RETVAL_, RETURN_
zval** return_value_ptr 当返回的PHP引用设置为一个变量的指针。不建议返回引用。
zval* this_ptr 如果这是一个方法调用,指向PHP变量的是 $this 对象 getThis()
int return_value_used 标记指示返回值是否被调用者使用

清楚起见,PHP_FUNCTION(hackers_function) 完整的扩展声明,看起来像这样:

void zif_hackers_function(int ht, zval* return_value, zval** return_value_ptr,
                          zval* this_ptr, int return_value_used)

this_ptr 的存在可能令人混淆,后面的章节详细介绍了类,
足以说明白PHP_METHOD(MyClass, hackersFunction)会生成下面的定义:

void zim_MyClass_hackersFunction(INTERNAL_FUNCTION_PARAMETERS)

hackers_function 不做任何有用的事,它使用 zend_parse_parameters API接收一个数字,并让它加倍,
然后返回给引擎。显然,一个普通的函数得做比让输入翻倍更复杂的事,为了教学目的我们让它保持简单。
在函数入口上,return_value 被分配和初始化为 null,让 null 成为任何PHP函数的默认返回值。

如果 zend_parse_parameters 没有接收Hacker指定的正确参数,
且接收的参数不能被转换为符合 type_spec 将产生一个error,并且按惯例,Hacker应该立刻 return

Note:  
  数组,对象和资源不能被转换。  

解析参数原型

int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...)
int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, char *type_spec, ...)
int zend_parse_parameter(int flags, int num_arg TSRMLS_DC, zval **arg, const char *spec, ...)
Note:  
  `zend_parse_parameter` 从5.5版本开始可用,它的行为如 `zend_parse_parameters_ex` 期望代替从栈中读取参数,  
它接收一个单独的zval来转换,并且这个zval可能会改变。
Note:  
  `flags` 是一个掩饰,目前只有 `ZEND_PARSE_PARAMS_QUIET` 会有作用(抑制警告)。

这些API函数接收的变量参数被期望是C变量的地址,并且应该被认为是 zend_parse_parameters API函数的输出。

类型说明符

说明符(Spec) 类型(Type) 本地变量(Locals)
a array zval*
A array or object zval*
b boolean zend_bool
C class zend_class_entry*
d double double
f function zend_fcall_info*, zend_fcall_info_cache*
h array HashTable*
H array or object HashTable*
l long long
L long(limits out-of-range
LONG_MAX/LONG_MIN)
long
o object zval*
O object(of specified zend_class_entry) zval*, zend_class_entry*
p string(a valid path) char*, int
r resource zval*
s string char*, int
z mixed zval*
Z mixed zval**
Note:  
  类型说明符是o的,本地 `zend_class_entry*` 被认为是到 `zend_parse_parameter`的输入(类型说明符的一部分)

高级类型说明符

说明符(Spec) 描述
* 上面类型的可变数量的参数,0 或者更多
+ 上面类型的可变数量的参数,1 或者更多
| 表示剩下的参数是可选的
/ SEPARATE_ZVAL_IF_NOT_REF 在它遵循的参数上
! 上面的参数可以是针对'b', 'l', 和 'd' 的null
一个额外的参数类型zend_bool* 必须在相符的bool*,long* 之后传递,否则接收的 double* 地址如果为 null 将被设为 true
Note:  
  查阅包含在源码内的 README.PARAMETER_PARSING_API 获取更多关于解析参数的信息。

一旦Hacker的函数已经执行,无论什么时候被实现执行,是时候返回 return_value 给引擎了。
RETURN_ 和 RETVAL_ 宏仅仅是和 return_value 一起工作的 Z_*_P 宏的包装。

Note:  
  RETURN_ 宏引起执行来离开函数(如:return;), 当 RETVAL_ 宏允许在 return_value 设置后继续执行时。

Hacker现在应该已经有一个合理的的理解函数的结构,和一些角度,方法的结构。