/*
|----------------------------------------
| 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现在应该已经有一个合理的的理解函数的结构,和一些角度,方法的结构。