diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-14 12:42:35 +0100 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-14 12:42:35 +0100 |
commit | 1f1a0fa9349d37e623ae763b48c7ea21681cd45b (patch) | |
tree | d5bc49690b2bb1f85f3560c28845dcc02566d330 /src/classbase.cpp | |
parent | 91e1175a467cb9e2f90e7421a1398430d075f776 (diff) |
implementation of properties using callback methods
Diffstat (limited to 'src/classbase.cpp')
-rw-r--r-- | src/classbase.cpp | 130 |
1 files changed, 92 insertions, 38 deletions
diff --git a/src/classbase.cpp b/src/classbase.cpp index 2fae658..1773890 100644 --- a/src/classbase.cpp +++ b/src/classbase.cpp @@ -646,22 +646,7 @@ zval *ClassBase::readDimension(zval *object, zval *offset, int type) try { // ArrayAccess is implemented, call function - Value value = arrayaccess->offsetGet(offset); - - // because we do not want the value object to destruct the zval when - // it falls out of scope, we detach the zval from it, if this is a regular - // read operation we can do this right away - if (type == 0) return value.detach(); - - // this is a more complicated read operation, the scripts wants to get - // deeper access to the returned value. This, however, is only possible - // if the value has more than once reference (if it has a refcount of one, - // the value object that we have here is the only instance of the zval, - // and it is simply impossible to return a reference or so - if (value.refcount() <= 1) return value.detach(); - - // we're dealing with an editable zval, return a reference variable - return Value(value.detach(), true).detach(); + return toZval(arrayaccess->offsetGet(offset), type); } catch (Exception &exception) { @@ -814,6 +799,30 @@ void ClassBase::unsetDimension(zval *object, zval *member) } /** + * Helper method to turn a property into a zval + * @param value + * @param type + * @return Value + */ +zval *ClassBase::toZval(Value &&value, int type) +{ + // because we do not want the value object to destruct the zval when + // it falls out of scope, we detach the zval from it, if this is a regular + // read operation we can do this right away + if (type == 0) return value.detach(); + + // this is a more complicated read operation, the scripts wants to get + // deeper access to the returned value. This, however, is only possible + // if the value has more than once reference (if it has a refcount of one, + // the value object that we have here is the only instance of the zval, + // and it is simply impossible to return a reference or so + if (value.refcount() <= 1) return value.detach(); + + // we're dealing with an editable zval, return a reference variable + return Value(value.detach(), true).detach(); +} + +/** * Function that is called when a property is read * @param object * @param name @@ -857,23 +866,23 @@ zval *ClassBase::readProperty(zval *object, zval *name, int type, const struct _ // the exception we know if the object was implemented by the user or not try { - // retrieve value - Value value = meta->callGet(base, name); - - // because we do not want the value object to destruct the zval when - // it falls out of scope, we detach the zval from it, if this is a regular - // read operation we can do this right away - if (type == 0) return value.detach(); + // convert name to a Value object + Value key(name); - // this is a more complicated read operation, the scripts wants to get - // deeper access to the returned value. This, however, is only possible - // if the value has more than once reference (if it has a refcount of one, - // the value object that we have here is the only instance of the zval, - // and it is simply impossible to return a reference or so - if (value.refcount() <= 1) return value.detach(); + // is it a property with a callback? + auto iter = meta->_properties.find(key); - // we're dealing with an editable zval, return a reference variable - return Value(value.detach(), true).detach(); + // was it found? + if (iter == meta->_properties.end()) + { + // retrieve value from the __get method + return toZval(meta->callGet(base, key), type); + } + else + { + // get the value + return toZval(iter->second->get(base), type); + } } catch (const NotImplemented &exception) { @@ -929,8 +938,26 @@ void ClassBase::writeProperty(zval *object, zval *name, zval *value, const struc // we know for sure that the user has not overridden the __set method try { - // call the default - meta->callSet(base, name, value); + // wrap the name + Value key(name); + + // check if the property has a callback + auto iter = meta->_properties.find(key); + + // is it set? + if (iter == meta->_properties.end()) + { + // use the __set method + meta->callSet(base, key, value); + } + else + { + // check if it could be set + if (iter->second->set(base, value)) return; + + // read-only property + zend_error(E_ERROR, "Unable to write to read-only property %s", (const char *)key); + } } catch (const NotImplemented &exception) { @@ -989,15 +1016,21 @@ int ClassBase::hasProperty(zval *object, zval *name, int has_set_exists, const s // we need the C++ class meta-information object ClassBase *meta = cpp_class(entry); + + // convert the name to a Value object + Value key(name); + + // check if this is a callback property + if (meta->_properties.find(key) != meta->_properties.end()) return true; // call the C++ object - if (!meta->callIsset(base, name)) return false; + if (!meta->callIsset(base, key)) return false; // property exists, but what does the user want to know if (has_set_exists == 2) return true; // we have to retrieve the property - Value value = meta->callGet(base, name); + Value value = meta->callGet(base, key); // should we check on NULL? switch (has_set_exists) { @@ -1052,9 +1085,18 @@ void ClassBase::unsetProperty(zval *object, zval *member, const struct _zend_lit // we need the C++ class meta-information object ClassBase *meta = cpp_class(entry); - - // call the __unset method - meta->callUnset(cpp_object(object), member); + + // property name + Value name(member); + + // is this a callback property? + auto iter = meta->_properties.find(name); + + // if the property does not exist, we forward to the __unset + if (iter == meta->_properties.end()) meta->callUnset(cpp_object(object), member); + + // callback properties cannot be unset + zend_error(E_ERROR, "Property %s can not be unset", (const char *)name); } catch (const NotImplemented &exception) { @@ -1641,6 +1683,18 @@ void ClassBase::property(const char *name, double value, int flags) } /** + * Set property with callbacks + * @param name Name of the property + * @param getter Getter method + * @param setter Setter method + */ +void ClassBase::property(const char *name, const getter_callback &getter, const setter_callback &setter) +{ + // add property + _properties[name] = std::make_shared<Property>(getter,setter); +} + +/** * End namespace */ } |