Chinaunix首页 | 论坛 | 博客
  • 博客访问: 920876
  • 博文数量: 194
  • 博客积分: 7991
  • 博客等级: 少将
  • 技术积分: 2067
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-09 22:03
文章分类

全部博文(194)

文章存档

2010年(8)

2009年(71)

2008年(109)

2007年(6)

我的朋友

分类:

2008-01-22 09:33:16

 
(本文由 song.xian-guang 原创,如果您觉得对您有帮助,请评论之,如需转载,请指明链接;作者保留所有权利, 禁止商业用途)
 
在C语言编程中,可以用一个数据结构作为参数,该参数可以为IN/OUT目的,在函数内部外部之间进行数据传递:
 

typedef struct _ips_command{
    long cmd;
    long target;
    char protocol[32];
}ips_command_t;

void do_something(ips_command_t *cmd)
{
    if (cmd->cmd == IPS_GET_PROTOCOL)
    {
        strcpy(cmd->protocol, PROTOCOL_TCP);
    }
}

这适合有很多数据需要传递的场合,把这些数据封装进入一个结构中,使用这样的函数接口可以减少使用以及维护成本;曾有同事不是很同意我的这个说法,说将来要是改动的话,不是一样需要改变数据结构,改变接口的实现方式吗,没有什么简化啊?错!因为如果采用类似如下的函数接口:void do_something(long cmd, long target, char *protocol);

当数据结构发生变化的时候,除了上边说的两种改变之外,如果该接口被多处调用的话,需要去一个一个的改,这就增加了维护难度,如果有一个地方被遗忘没改动的话,就会出现问题。

也就是说,只要数据结构有变动的话,两种改变是必然要有的,我们能做的只有让接口方式不变来降低维护难度了。

废话少说,下面就来说说在PHP页面与PHP可扩展模块之间传结构的方法。我目前做的项目中,需要制作扩展PHP模块来实现一些功能,但是如何在PHP模块与页面之间传递结构参数,网上没有文章讲述,我只好自己研究PHP和Zend的源代码,总结出了如下的方法,大家参考吧。

原理:
1) 在C++中,class和struct除了成员的访问属性(public, private……)不一样,其他都是一样的
2) 在PHP脚本中没有struct的概念
3) 在PHP脚本中有class的概念
于是,我考虑采用class实现结构参数的传递,摸索的重点就是如何在PHP页面与PHP可扩展模块之间双向传递对象(instance of a class)。

实践:
1) 编写PHP脚本(以下为片段)

 

class ips_command_t
{
         var $cmd; /* 1 : pass parm to ext, 2 : get sth from ext */
         var $target;
         var $protocol;
}

function ips_command_dump($cmd)
{
         echo "php page : cmd = " . $cmd->cmd ."$br\n";
         echo "php page : target = " . $cmd->target ."$br\n";
         echo "php page : protocol = " . $cmd->protocol ."$br\n";
}

$obj = new ips_command_t();

//pass parm to php-ext-module
$obj->cmd = 1; //set
$obj->target = 2;
$obj->protocol = "udp";
php_struct_set($obj);

//get sth from php-ext-module
echo "$br\n";
$obj->cmd = 2; //get
php_struct_set($obj);
ips_command_dump($obj);

以上定义了一个类ips_command_t,以及其一个实例$obj
然后先由上向下传递参数(set),再由下向上传递数据(get)

2) 编写模块

static int get_values_from_php_page(zval **struc, int num_args, va_list args, zend_hash_key *hash_key)
{
    char *prop_name, *class_name;

    zend_unmangle_property_name(hash_key->arKey, hash_key->nKeyLength-1, &class_name, &prop_name);

    if (!strncmp(prop_name, "cmd", 3))
    {
        ipscmd.cmd = Z_LVAL_PP(struc);
    }
    else if (!strncmp(prop_name, "target", 6))
    {
        ipscmd.target = Z_LVAL_PP(struc);
    }
    else if (!strncmp(prop_name, "protocol", 8))
    {
        strcpy(ipscmd.protocol, Z_STRVAL_PP(struc));
    }
    
    return 0;
}

static int set_values_to_php_page(zval **struc, int num_args, va_list args, zend_hash_key *hash_key)
{
    char *prop_name, *class_name;

    zend_unmangle_property_name(hash_key->arKey, hash_key->nKeyLength-1, &class_name, &prop_name);

    if (!strncmp(prop_name, "cmd", 3))
    {
        Z_LVAL_PP(struc) = 999;
    }
    else if (!strncmp(prop_name, "target", 6))
    {
        Z_LVAL_PP(struc) = 888;
    }
    else if (!strncmp(prop_name, "protocol", 8))
    {
        strcpy(Z_STRVAL_PP(struc), "sxgsxg");
    }
    
    return 0;
}

static void ips_command_dump(ips_command_t* cmd)
{
    php_printf("php ext module : cmd = %d\n", cmd->cmd);
    php_printf("php ext module : target = %d\n", cmd->target);
    php_printf("php ext module : protocol = %s\n", cmd->protocol);
}

PHP_FUNCTION(php_struct_set)
{
    zval **mythis;
    HashTable *myht = NULL;
    char *class_name;
    zend_uint class_name_len;
    zend_class_entry *ce;
    int (*zval_element_dump_func)(zval**, int, va_list, zend_hash_key*);
    
    zend_get_parameters_ex(1, &mythis);    
    if (Z_TYPE_PP(mythis) != IS_OBJECT)
        RETURN_FALSE;
    zend_printf("php ext module : php_struct_set is called ,get an object\n");

    //php_debug_zval_dump(mythis, 1 TSRMLS_CC);

    myht = Z_OBJPROP_PP(mythis);
    Z_OBJ_HANDLER(**mythis, get_class_name)(*mythis, &class_name, &class_name_len, 0 TSRMLS_CC);
    php_printf("php ext module : class name is %s, %d properties\n", class_name, myht ? zend_hash_num_elements(myht) : 0);
    efree(class_name);

    //get struct members' values from php pages

    zval_element_dump_func = get_values_from_php_page;
    zend_hash_apply_with_arguments(myht, (apply_func_args_t) zval_element_dump_func, 1, 1, (Z_TYPE_PP(mythis) == IS_ARRAY ? 0 : 1));
    ips_command_dump(&ipscmd);

    //change some member's values

    if (ipscmd.cmd == 2)
    {
        php_printf("now i am changing sth in ext module...\n");
        zval_element_dump_func = set_values_to_php_page;
        zend_hash_apply_with_arguments(myht, (apply_func_args_t) zval_element_dump_func, 1, 1, (Z_TYPE_PP(mythis) == IS_ARRAY ? 0 : 1));
    }
}

效果:
执行php脚本后,会有如下输出:
[root@10-190-50-74 php_struct]# php -f sxgsystem.php
loading php extention module : sxgsystem.so... done
php ext module : php_struct_set is called ,get an object
php ext module : class name is ips_command_t, 3 properties
php ext module : cmd      = 1
php ext module : target   = 2
php ext module : protocol = udp

php ext module : php_struct_set is called ,get an object
php ext module : class name is ips_command_t, 3 properties
php ext module : cmd      = 2
php ext module : target   = 2
php ext module : protocol = udp
now i am changing sth in ext module...
php page : cmd      = 999
php page : target   = 888
php page : protocol = sxg
[root@10-190-50-74 php_struct]#

可以看到,底层模块获取到了页面传下来的结构;另外底层模块也改变了结构的值并将其传到了页面。


另外,如果结构中成员比较多的话,可以加入一个构造函数,由该函数自动赋默认值:
class ips_command_t
{
         var $cmd;          /* 1 : pass parm to ext, 2 : get sth from ext */
         var $target;
         var $protocol;
        
         function ips_command_t()
         {
                   $this->cmd = 11;
                   $this->target = 1;
                   $this->protocol = "tcp";
         }
}
这样,当定义一个变量的时候,只需要改变必要的成员就行了。

总结:
采用这样的在PHP页面和PHP可扩展模块之间传递参数,可以降低接口的使用与维护难度。

希望本文对您有所帮助。

sxg


 

 

阅读(2277) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~