在php类方法中使最后一个数组参数可选(C)

Posted

技术标签:

【中文标题】在php类方法中使最后一个数组参数可选(C)【英文标题】:Make last array parameter optional in php class method (C) 【发布时间】:2012-08-20 23:51:06 【问题描述】:

我正在用 C 语言创建一个 php 扩展来访问 SPI 接口。到目前为止,我已经完成了几乎所有工作:php_spi on Github

但是,我似乎无法将构造函数中的 $options 参数设为可选。我的工作代码是这样的:

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lla", &bus, &chipselect, &options) == FAILURE) 
    return;


_this_zval = getThis();
_this_ce = Z_OBJCE_P(_this_zval);

options_hash = HASH_OF(options);

char device[32];
sprintf(device, "/dev/spidev%d.%d", bus, chipselect);

// If the device doesn't exists, error!
if(access(device, F_OK) == -1) 
    char error[128];
    sprintf(error, "The device %s does not exist", device);
    php_error(E_ERROR, error);


// If we can't open it, error!
long fd = open(device, O_RDWR);
if (fd < 0) 
    char error[128];
    sprintf(error, "Could not open %s for read/write operations, are you running as root?", device);
    php_error(E_ERROR, error);


// Set the file descriptor as a class property
zend_update_property_long(_this_ce, _this_zval, "device", 6, fd TSRMLS_DC);

// Default property values
uint8_t mode = SPI_MODE_0;
uint8_t bits = 8;
uint32_t speed = 500000;
uint16_t delay = 0;

// Loop through the options array
zval **data;
for(zend_hash_internal_pointer_reset(options_hash);
    zend_hash_get_current_data(options_hash, (void **)&data) == SUCCESS;
    zend_hash_move_forward(options_hash)) 

    char *key;
    int len;
    long index;
    long value = Z_LVAL_PP(data);

    if(zend_hash_get_current_key_ex(options_hash, &key, &len, &index, 1, NULL) == HASH_KEY_IS_STRING) 
        // Assign the value accordingly
        if(strncmp("mode", key, len) == 0) 
            switch(value) 
                case SPI_MODE_1:
                    mode = SPI_MODE_1;
                    break;
                case SPI_MODE_2:
                    mode = SPI_MODE_2;
                    break;
                case SPI_MODE_3:
                    mode = SPI_MODE_3;
                    break;
                default:
                    mode = SPI_MODE_0;
                    break;
            
        
        else if(strncmp("bits", key, len) == 0) 
            bits = value;
        
        else if(strncmp("speed", key, len) == 0) 
            speed = value;
        
        else if(strncmp("delay", key, len) == 0) 
            delay = value;
        
    

但是,如果我遵循所有文档的建议,我可以找到并在 l 和 a 之间添加一个管道,如下所示:

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|a", &bus, &chipselect, &options) == FAILURE) 

然后我的扩展默默地失败了 - 任何人都可以给我任何建议吗?

【问题讨论】:

【参考方案1】:

假设optionszval*,如果你这样做:

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|a", &bus, &chipselect, &options) == FAILURE) 
    return;

...如果options 没有被传递(也就是说,你省略了第三个可选参数),options 将不会被初始化或修改。稍后,你这样做:

options_hash = HASH_OF(options);

因此,您使用的是未初始化的指针或 NULL 指针,这是未定义的行为。这很可能会导致分段错误,从而导致您的 PHP 脚本失败。

你应该做的是:

zval* options = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|a", &bus, &chipselect, &options) == FAILURE) 
    return;


// ...

if (options != NULL) 
    options_hash = HASH_OF(options);

...并处理options(和options_hash)的每个实例,条件是检查它是否为NULL

【讨论】:

很明显的事情我应该自己检查一下 - 谢谢

以上是关于在php类方法中使最后一个数组参数可选(C)的主要内容,如果未能解决你的问题,请参考以下文章

[PHP] 抽象类abstract的回顾

C#4.0中的方法重载与可选参数[重复]

Java基础学习191221(可变参数,数组,Array类,稀疏数组,继承重写多态,抽象类,接口)

Java实训笔记——-抽象类-接口-泛型-集合

PHP 抽象类的使用

使用可选关键字参数定义类的 __init__ 方法的更好方法是啥?