Skip to content

Commit 4fbe1c3

Browse files
committed
完善第一节中对 PHP_FUNCTION 的说明
1 parent 4c6d23b commit 4fbe1c3

File tree

3 files changed

+95
-1
lines changed

3 files changed

+95
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# 在扩展中使用函数
2+
3+
我们在 hello-world 扩展的例子中,通过原型框架生成了一个简单的函数,修改之后如下
4+
5+
[c]
6+
/* {{{ proto string tipi_hello_world(string name)
7+
*/
8+
PHP_FUNCTION(tipi_hello_world)
9+
{
10+
char *name = NULL;
11+
int argc = ZEND_NUM_ARGS();
12+
size_t name_len;
13+
14+
char *result = NULL;
15+
char *prefix = "hello world, ";
16+
17+
#ifndef FAST_ZPP
18+
if (zend_parse_parameters(argc TSRMLS_CC, "s", &name, &name_len) == FAILURE)
19+
return;
20+
#else
21+
ZEND_PARSE_PARAMETERS_START(1, 1)
22+
Z_PARAM_STRING(name, name_len)
23+
ZEND_PARSE_PARAMETERS_END();
24+
#endif
25+
26+
result = (char *) ecalloc(strlen(prefix) + name_len + 1, sizeof(char));
27+
strncat(result, prefix, strlen(prefix));
28+
strncat(result, name, name_len);
29+
30+
RETURN_STRING(result);
31+
}
32+
/* }}} */
33+
34+
## PHP_FUNCTION 宏
35+
36+
在 PHP 扩展中,所有的函数均以 `PHP_FUNCTION(extension_name){...}`的结构来表示,
37+
38+
[c]
39+
/* main/php.h */
40+
#define PHP_FUNCTION ZEND_FUNCTION
41+
/* Zend/zend_API.h */
42+
#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))
43+
44+
#define ZEND_FN(name) zif_##name
45+
#define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)
46+
47+
#define INTERNAL_FUNCTION_PARAMETERS zend_execute_data *execute_data, zval *return_value
48+
49+
相对 PHP5 中 `INTERNAL_FUNCTION_PARAMETERS` 宏表示的参数简单了很多。
50+
在上例中 `return_value` 虽然没有显性地使用,实际通过 `RETURN_STRING` 隐形地使用了。
51+
52+
## 从函数中返回
53+
54+
扩展API包含丰富的用于从函数中返回值的宏。这些宏有两种主要风格:第一种是 `RETVAL_type()` 形式,它设置了返回值但C代码继续执行。
55+
这通常使用在把控制交给脚本引擎前还希望做的一些清理工作的时候使用,然后再使用C的返回声明 `return` 返回到 PHP;
56+
后一个宏更加普遍,其形式是 `RETURN_type()`,他设置了返回类型,同时返回控制到 PHP。
57+
58+
[c]
59+
/* Zend/zend_API.h */
60+
#define RETURN_BOOL(b) { RETVAL_BOOL(b); return; }
61+
#define RETURN_NULL() { RETVAL_NULL(); return;}
62+
#define RETURN_LONG(l) { RETVAL_LONG(l); return; }
63+
#define RETURN_DOUBLE(d) { RETVAL_DOUBLE(d); return; }
64+
#define RETURN_STR(s) { RETVAL_STR(s); return; }
65+
#define RETURN_INTERNED_STR(s) { RETVAL_INTERNED_STR(s); return; }
66+
#define RETURN_NEW_STR(s) { RETVAL_NEW_STR(s); return; }
67+
#define RETURN_STR_COPY(s) { RETVAL_STR_COPY(s); return; }
68+
#define RETURN_STRING(s) { RETVAL_STRING(s); return; }
69+
#define RETURN_STRINGL(s, l) { RETVAL_STRINGL(s, l); return; }
70+
#define RETURN_EMPTY_STRING() { RETVAL_EMPTY_STRING(); return; }
71+
#define RETURN_RES(r) { RETVAL_RES(r); return; }
72+
#define RETURN_ARR(r) { RETVAL_ARR(r); return; }
73+
#define RETURN_OBJ(r) { RETVAL_OBJ(r); return; }
74+
#define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; }
75+
#define RETURN_FALSE { RETVAL_FALSE; return; }
76+
#define RETURN_TRUE { RETVAL_TRUE; return; }
77+
78+
`RETURN_STRING` 为例
79+
80+
[c]
81+
#define RETURN_STR(s) { RETVAL_STR(s); return; }
82+
83+
#define RETVAL_STR(s) ZVAL_STR(return_value, s)
84+
85+
实际是将 `s` 赋值给 `return_value`,详细代码读者可以自己在源码中跟下。
86+
87+
`PHP_FUNCTION` 宏类似, `PHP_METHOD` 用来封装类中的方法。

book/index.markdown

+2
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
* 第一节 扩展开发概述
109109
* [第二节 创建第一个扩展][extension-hello-world]
110110
+ [扩展中参数的解析][zend-parse-parameters]
111+
+ [扩展中使用函数][extension-php-function]
111112
* [第三节 使用全局变量][global-var]
112113
+ [原理分析][global-var-analysis]
113114
* [第四节 使用 ini 指令][ini-set]
@@ -247,6 +248,7 @@
247248

248249
[extension-hello-world]: ?p=chapt11/11-02-00-extension-hello-world
249250
[zend-parse-parameters]: ?p=chapt11/11-02-01-zend-parse-parameters
251+
[extension-php-function]: ?p=chapt11/11-02-02-php-function
250252
[global-var]: ?p=chapt11/11-03-00-global-var
251253
[global-var-analysis]: ?p=chapt11/11-03-01-global-var
252254
[ini-set]: ?p=chapt11/11-04-00-ini-set

book/sample/chapt11/11-02-00-tipi-hello-world/tipi_demo01.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,14 @@ PHP_FUNCTION(tipi_hello_world)
8383
char *result = NULL;
8484
char *prefix = "hello world, ";
8585

86-
86+
#ifndef FAST_ZPP
8787
if (zend_parse_parameters(argc TSRMLS_CC, "s", &name, &name_len) == FAILURE)
8888
return;
89+
#else
90+
ZEND_PARSE_PARAMETERS_START(1, 1)
91+
Z_PARAM_STRING(name, name_len)
92+
ZEND_PARSE_PARAMETERS_END();
93+
#endif
8994

9095
result = (char *) ecalloc(strlen(prefix) + name_len + 1, sizeof(char));
9196
strncat(result, prefix, strlen(prefix));

0 commit comments

Comments
 (0)