PHP之MODULE学习笔记(二)

原文地址:http://blog.sina.com.cn/s/blog_48835ef9010003ho.html

PHP之MODULE学习笔记(二)


在PHP得MODULE当中有三种扩展方式:
(1)External Modules;
(2)Built-in Modules;
(3)The Zend Engine;
而在上一章之中我们谈到了第一种方式(即External Modules),那么接下来我们来介绍如何讲我们的MODULE编译进PHP中(即Built-in Modules).

我们在对我们写的MODULE测试没有问题之后即可以把我们的MODULE编译进PHP之中:
步骤如下:
如果我们要想把我们的MODULE以with方式编译进来则:
(1).修改config.m4中的
dnl [ --with-sandy_php_module Include sandy_php_module support])
修改为:
--with-sandy_php_modulet Include sandy_php_module support
编译PHP时: ./configure --with-sandy_php_module 
如果我们想把我们的MODULE以enable方式编译进拉则:
(2).修改config.m4中的
dnl [ --enable-sandy_php_module Enable sandy_php_module support])
修改为:
--enable-sandy_php_module Enable sandy_php_module support

编译PHP时: ./configure --enable-sandy_php_module 

/【编写带返回值的MODULE】/
编写带返回值的MODULE:
下面我们一起来研究带函数返回值的MODULE: 

#include "string.h"

PHP_FUNCTION(mytest)
{
char *return_s;
int len = 5;
return_s = emalloc();
strcat(return_s,"abcd");

RETURN_STRINGL (return_s, len, 1);
}
我们编译后就可以调用此函数:
<?php
dl("mytest.so");
$str = mytest();
echo "\$str={$str}"; // 这时将输出 $str = abcd 
?>
/【编写带参数及返回值的MODULE】/
因为 Zend 没有正式的函数调用语法检查支持,所以我们在编写扩展函数的时候必须得小心, 也就是我们必须得严格地进行调用合法性检查,

首先,我们写一个函数:
PHP_FUNCTION(sandy_var)
{
int args_count = ZEND_NUM_ARGS();
char *return_s;
char *s;
int s_len;

if(args_count != 1) zend_error(E_ERROR, "This function must be one arguments!"); //检查参数个数是否对

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"s", &s, &s_len) == FAILURE) {
RETURN_FALSE;
} // 接收参数

return_s = malloc(s_len + 5); // 升请空间
return_s = strdup(s);
strcat(return_s,"abcd"); // 连接字符串 

zend_printf(return_s); // 输出这个字符串

RETURN_STRING(s,1); // 返回
}
在这个函数中我们只接收一个字符串参数,我们也返回一个字符串.
在ZEND中ZEND_NUM_ARGS()时取
我们来分析这个函数:
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"s", &s, &s_len) == FAILURE) {
RETURN_FALSE;
}
这句就是进行参数检查与取得参数的语句,zend_parse_parameters() 是 Zend 提供的 API 函数, 第一个参数是参数的数量,可以通过 Zend 

提供的 ZEND_NUM_ARGS() 来取得,TSRMLS_CC 是必须的, 第三个参数 "s" 指明参数的类型(s - 字符串),这个函数有1个字符串参数,所

以为 "s", 之后的参数就是你要取得的参数值了,注意 如果 参数类型为 "s" 的话, 参数值后面还要传一个 long 来取得字符串的长度. 

zend_parse_parameters 函数成功的话会返回SUCCESS, 失败则返回 FAILURE ,并且输出错误信息.

变量类型列表:
l - long

d - double

s - string (with possible null bytes) and its length

b - boolean

r - resource, stored in zval*

a - array, stored in zval*

o - object (of any class), stored in zval*

O - object (of class specified by class entry), stored in zval*

z - the actual zval*

下面这些是特殊含义的字符:

| - indicates that the remaining parameters are optional. The storage variables corresponding to these parameters should be 

initialized to default values by the extension, since they will not be touched by the parsing function if the parameters are 

not passed. 

/ - the parsing function will call SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows, to provide a copy of the 

parameter, unless it's a reference. 

! - the parameter it follows can be of specified type or NULL (only applies to a, o, O, r, and z). If NULL value is passed by 

the user, the storage pointer will be set to NULL. 

使用范例:
/* Gets a long, a string and its length, and a zval. */
long l;
char *s;
int s_len;
zval *param;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"lsz", &l, &s, &s_len, ¶m) == FAILURE) {
return;
}

/* Gets an object of class specified by my_ce, and an optional double. */
zval *obj;
double d = 0.5;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"O|d", &obj, my_ce, &d) == FAILURE) {
return;
}

/* Gets an object or null, and an array.
If null is passed for object, obj will be set to NULL. */
zval *obj;
zval *arr;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O!a", &obj, &arr) == FAILURE) {
return;
}

/* Gets a separated array. */
zval *arr;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &arr) == FAILURE) {
return;
}

/* Get only the first three parameters (useful for varargs functions). */
zval *z;
zend_bool b;
zval *r;
if (zend_parse_parameters(3, "zbr!", &z, &b, &r) == FAILURE) {
return;
}

ZEND的返回值方法:
Macro Description 
RETURN_RESOURCE(resource) Returns a resource. 
RETURN_BOOL(bool) Returns a Boolean. 
RETURN_NULL() Returns nothing (a NULL value). 
RETURN_LONG(long) Returns a long. 
RETURN_DOUBLE(double) Returns a double. 
RETURN_STRING(string, duplicate) Returns a string. The duplicate flag indicates whether the string should be 

duplicated using estrdup(). 
RETURN_STRINGL(string, length, duplicate) Returns a string of the specified length; otherwise, behaves like RETURN_STRING. 

This macro is faster and binary-safe, however. 
RETURN_EMPTY_STRING() Returns an empty string. 
RETURN_FALSE Returns Boolean false. 
RETURN_TRUE Returns Boolean true. 

Predefined Macros for Setting the Return Value of a Function

Macro Description 
RETVAL_RESOURCE(resource) Sets the return value to the specified resource. 
RETVAL_BOOL(bool) Sets the return value to the specified Boolean value. 
RETVAL_NULL Sets the return value to NULL. 
RETVAL_LONG(long) Sets the return value to the specified long. 
RETVAL_DOUBLE(double) Sets the return value to the specified double. 
RETVAL_STRING(string, duplicate) Sets the return value to the specified string and duplicates it to Zend internal memory if 

desired (see also RETURN_STRING). 
RETVAL_STRINGL(string, length, duplicate) Sets the return value to the specified string and forces the length to become 

length (see also RETVAL_STRING). This macro is faster and binary-safe, and should be used whenever the string length is 

known. 
RETVAL_EMPTY_STRING Sets the return value to an empty string. 
RETVAL_FALSE Sets the return value to Boolean false. 
RETVAL_TRUE Sets the return value to Boolean true. 
在这里大家不难发现为什么没有数组和对象的返回方法呢?ZEND的内核是C写的,而我们会发现C是没有对象的,且其数组的下标只允许是整型数字

的,然而在我们的PHP中的数组是支持字符等多种下标类型的,因此决定了在返回此类类型的数据时,我们必须得采用其他的方法,ZEND在这方面已

经为我们做好了,我们在返回数组及对象等数据类型时,只要将其赋值给return_value即可完成数据的返回.
下面我们将编写一个参数为数组,返回值为数组的MODULE:
PHP_FUNCTION(sandy_array)
{
int args_count = ZEND_NUM_ARGS();
int id = 0;
zval **array;
HashTable *target_hash; 

if(zend_get_parameters_ex(1, &array) == FAILURE) zend_error(E_ERROR, "This function must be a array!");

target_hash = HASH_OF(*array);
if (!target_hash)
{
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
RETURN_FALSE;
}

*return_value = **array;

char *key = "2";
zval *new_element;

MAKE_STD_ZVAL(new_element); // 初始化zval类型的变量,为其申请变量空间
ZVAL_LONG(new_element, 10); // 赋初值

if(zend_hash_update(return_value->value.ht, key, strlen(key) + 1, (void *)&new_element, sizeof(zval *), NULL) == FAILURE)
{
zend_error(E_ERROR,"This is error array!");
}

zend_printf("\nargc = %d\n",args_count);

add_assoc_string(return_value, "a", "aaaaaaaa", 1); // 增加数组元素
add_assoc_string(return_value, "b", "bbbbbbbb", 1);
add_assoc_string(return_value, "c", "cccccccc", 1);
add_assoc_string(return_value, "d", "dddddddd", 1);
add_assoc_string(return_value, "1", "dddddddd", 1);

zval **entry;

HashPosition pos;

zend_hash_internal_pointer_reset_ex(HASH_OF(return_value), &pos);

if (zend_hash_get_current_data_ex(HASH_OF(return_value), (void **) &entry, &pos) == FAILURE)
{
RETURN_FALSE;
}else{
if((*entry)->type == IS_STRING) zend_printf("<br/>\r\n is string<br/>\r\n");

zend_printf("<Br/>\r\n value =%s",(*entry)->value.lval); 
}


if(zend_hash_exists(HASH_OF(return_value), "f", 2)) zend_printf("<br/>\r\n is exists! <br/>\r\n");
else zend_printf("<br/>\r\n is not exists! <br/>\r\n");

zval_copy_ctor(return_value);
}

PHP的数组在zend中是一个结构体,其结构如下:
typedef pval zval;

typedef struct _zval_struct zval;

typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
struct {
zend_class_entry *ce;
HashTable *properties;
} obj;
} zvalue_value;

struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
unsigned char type; /* active type */
unsigned char is_ref;
short refcount;
};
更多的API见PHP源项目文件.

参考资料:
(1).PHP4.4.1源代码
(2).PHP手册
注:转载请说明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值