【问题标题】:php extension: can not update class field using zend_hash_updatephp 扩展:无法使用 zend_hash_update 更新类字段
【发布时间】:2012-02-28 05:00:03
【问题描述】:

我想把这个类实现成php扩展:

class MyClass {
  protected $attrs = array();
  public function __construct($id = null) {
    $this->attrs['id'] = $id;
    $this->attrs['name'] = '';
  }
  public function __get($key) {
    if (array_key_exists($key, $this->attr)) 
      return $this->attrs[$key];
  }
  public function __set($key, $value) {
    if (array_key_exists($key, $this->attr)) 
      $this->attrs[$key] = $value;
  }
}

我已经实现了 __constructor、$attrs 字段和 __get 方法。现在我想不通 __set。

有我的c代码:

PHP_METHOD(MyClass, __set) {    
  char *key;
  int key_len;
  zval *value;  

  if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &key, &key_len, &value)) {
    RETURN_NULL();
  }

  zval *attrs, *obj;
  obj = getThis();
  attrs = zend_read_property(Z_OBJCE_P(obj), obj, "attrs", strlen("attrs"), TRUE, TSRMLS_C);

  if (Z_TYPE_P(attrs) == IS_ARRAY && zend_hash_exists(Z_ARRVAL_P(attrs), key, strlen(key) + 1)) {
    zend_hash_update(Z_ARRVAL_P(attributes), key, strlen(key) + 1, &value, sizeof(zval*), NULL);
    }
  else {        
    zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 1, TSRMLS_C, "unknown field \"%s\"", key);
  }
}

attrs - 在 init 函数中声明受保护的属性(我已将属性声明为 null,但是当我在构造函数中向 $attrs 添加数据时 - 属性更新为数组)

zend_declare_property_null(myclass_ce, "attrs", strlen("attrs"), ZEND_ACC_PROTECTED TSRMLS_CC);

所以我的问题是:我需要如何在 c 中更新我的 attr 字段? 我的扩展成功编译,我可以定义属性,读取它们,但我无法设置它们 - 因为设置的值变为空,例如:

class MyClass2 extends MyClass {
  public function __construct($id = null) {
    parent::__construct($id);
    $this->attrs["type"] = "clz";
  }
} 

$c = new MyClass();
var_dump($c->type); // string(3) "clz"
$c->type = "myclz"; // no error, my __set method handles this call, and I'm sure I'm getting correct value 
var_dump($c->type); // NULL

我是 c 开发新手,我真的需要帮助。

UPD 1. 我尝试将 __set 正文更改为:

zval *strval;
MAKE_STD_ZVAL(strval);
ZVAL_STRING(strval, Z_STRVAL_P(value), TRUE);
if (Z_TYPE_P(attributes) == IS_ARRAY && zend_hash_exists(Z_ARRVAL_P(attributes), key, strlen(key) + 1)) {
  zend_hash_update(HASH_OF(attributes), key, strlen(key) + 1, &strval, sizeof(zval*), NULL);
}

现在我可以设置字符串值了。如果我需要打开每种类型的 zval??

【问题讨论】:

    标签: php c php-internals


    【解决方案1】:

    这应该可行:

    PHP_METHOD(MyClass, __set) {    
      char *key;
      int key_len;
      zval *value, *copied;  
    
      if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &key, &key_len, &value)) {
        RETURN_NULL();
      }
    
      zval *attrs, *obj;
      obj = getThis();
      attrs = zend_read_property(Z_OBJCE_P(obj), obj, "attrs", strlen("attrs"), TRUE, TSRMLS_C);
    
      MAKE_STD_ZVAL(copied);
      *copied = *value;
      zval_copy_ctor(copied);
    
      if (Z_TYPE_P(attrs) == IS_ARRAY && zend_hash_exists(Z_ARRVAL_P(attrs), key, strlen(key) + 1)) {
        zend_hash_update(Z_ARRVAL_P(attributes), key, strlen(key) + 1, &copied, sizeof(zval*), NULL);
      }
      else {        
        zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 1, TSRMLS_C, "unknown field \"%s\"", key);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多