我想将这个类实现为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字段? 我的扩展成功编译,我可以定义属性,读取它们,但我无法设置它们 - 因为设置值变为null,例如:
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 body更改为:
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 ??
答案 0 :(得分:3)
这应该有效:
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);
}
}