summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--include/member.h251
-rw-r--r--include/type.h2
-rw-r--r--include/value.h154
-rw-r--r--phpcpp.h4
-rw-r--r--src/callable.cpp43
-rw-r--r--src/value.cpp294
7 files changed, 407 insertions, 345 deletions
diff --git a/Makefile b/Makefile
index 53aec7a..496e051 100644
--- a/Makefile
+++ b/Makefile
@@ -3,14 +3,14 @@ INCLUDE_DIR = ${PREFIX}/include
LIBRARY_DIR = ${PREFIX}/lib
all:
- cd src; $(MAKE)
+ cd src; $(MAKE) -j
tests:
cd tests; $(MAKE)
clean:
cd src; $(MAKE) clean
- cd tests; $(MAKE) clean
+# cd tests; $(MAKE) clean
install:
mkdir -p ${INCLUDE_DIR}/phpcpp
diff --git a/include/member.h b/include/member.h
index 49ac246..d56b495 100644
--- a/include/member.h
+++ b/include/member.h
@@ -1,23 +1,23 @@
/**
- * Member.h
+ * Member.h
*
- * When you're accessing members in an array or an object, you're
- * doing so via an internal member object. This is an object that
- * keeps track of the array to which it belonged, and that updates
- * the class when the object is modified
+ * When you're accessing members in an array or an object, you're
+ * doing this via an internal member object. This is an object that
+ * keeps track of the array to which it belongs, and that will update
+ * the array when the member is modified
*
- * This is an abstract class. You are not supposed to instantiate it
- * yourself. An instance of it is created when you call Value::operator[]
+ * You are not supposed to instantiate this class. An instance of it is
+ * created when you call Value::operator[]
*
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2013 Copernica BV
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2013 Copernica BV
*/
/**
- * Set up namespace
+ * Set up namespace
*/
namespace PhpCpp {
-
+
/**
* Forward definitions
*/
@@ -26,52 +26,49 @@ class Value;
/**
* Member class
*/
-template <class Type>
+template <typename Type>
class Member
{
public:
- /**
- * Destructor
- */
- virtual ~Member() {}
+ /**
+ * Destructor
+ */
+ virtual ~Member() {}
- /**
- * Assign a value object to the array
- * @param value
- * @return Member
- */
- Member &operator=(const Value &value)
- {
- // set property in parent array
- _value->set(_index, value);
-
- // leap out if this is not a nested array access
- //if (!_parent) return *this;
-
- // nested array access, we need to update the parent too
- //_parent->operator=(*_value);
-
- // done
- return *this;
- }
+ /**
+ * Assign a value object to the array
+ * @param value
+ * @return Member
+ */
+ Member &operator=(const Value &value)
+ {
+ // set property in parent array
+ _base.set(_index, value);
- /**
- * Retrieve the original value
- * @return Value
- */
- Value value() const
- {
- return _value->get(_index);
- }
+ // if there is a parent, it should sets its value too
+ if (_parent) _parent->operator=(_base);
+
+ // done
+ return *this;
+ }
- /**
- * Cast to a value object
- * @return Value
- */
- operator Value () const
- {
- return _value->get(_index);
- }
+ /**
+ * Retrieve the original value
+ * @return Value
+ */
+ Value value() const
+ {
+ return _base.get(_index);
+ }
+
+ /**
+ * Cast to a value object
+ * @return Value
+ */
+ operator Value () const
+ {
+ return _base.get(_index);
+ }
/**
* Cast to a long
@@ -79,8 +76,8 @@ public:
*/
operator long () const
{
- return _value->get(_index).longValue();
- }
+ return _base.get(_index).longValue();
+ }
/**
* Cast to a boolean
@@ -88,8 +85,8 @@ public:
*/
operator bool () const
{
- return _value->get(_index).boolValue();
- }
+ return _base.get(_index).boolValue();
+ }
/**
* Cast to a string
@@ -97,8 +94,8 @@ public:
*/
operator std::string () const
{
- return _value->get(_index).stringValue();
- }
+ return _base.get(_index).stringValue();
+ }
/**
* Cast to byte array
@@ -106,8 +103,8 @@ public:
*/
operator const char * () const
{
- return _value->get(_index).rawValue();
- }
+ return _base.get(_index).rawValue();
+ }
/**
* Cast to a floating point
@@ -115,9 +112,9 @@ public:
*/
operator double () const
{
- return _value->get(_index).decimalValue();
- }
-
+ return _base.get(_index).decimalValue();
+ }
+
/**
* Array access operator
* This can be used for accessing arrays
@@ -126,8 +123,8 @@ public:
*/
Member operator[](int index)
{
- return _value->get(_index)[index];
- }
+ return _base.get(_index)[index].add(this);
+ }
/**
* Array access operator
@@ -137,76 +134,72 @@ public:
*/
Member operator[](const std::string &key)
{
- return _value->get(_index)[key];
- }
+ return _base.get(_index)[key].add(this);
+ }
- /**
- * Array access operator
- * This can be used for accessing associative arrays
- * @param key
- * @return Member
- */
- Member operator[](const char *key)
- {
- return _value->get(_index)[key];
- }
+ /**
+ * Array access operator
+ * This can be used for accessing associative arrays
+ * @param key
+ * @return Member
+ */
+ Member operator[](const char *key)
+ {
+ return _base.get(_index)[key].add(this);
+ }
private:
- /**
- * Constructor
- * @param value Parent element
- * @param index Index in the array
- */
- Member(Value *value, Type index) : _value(value), _index(index) {}
-
- /**
- * Private copy constructor
- * @param value Other element
- */
- Member(const Member<Type> &member) : _value(member._value), _index(member._index) {}
-
- /**
- * Set the member
- * @param member
- */
- Member<Type> &add(Member *parent)
- {
- _parent = parent;
- return *this;
- }
-
- /**
- * The array of which this is a member
- * @var Value
- */
- Value *_value;
-
- /**
- * The original index
- * @var Type
- */
- Type _index;
-
- /**
- * Parent member
- *
- * When accessing nested arrays a["a"]["b"] = 'true', the member
- * object that represents the "b" entry holds a pointer to the member
- * object that represents "a", so that it can tell its parent to
- * store itself in the top array too
- *
- * @var Member
- */
- Member *_parent = nullptr;
-
- /**
- * Value objects may create members
- */
- friend class Value;
+ /**
+ * Constructor
+ * @param base Base value
+ * @param index Index in the array
+ */
+ Member(const Value *base, Type index) : _base(*base), _index(index) {}
+
+ /**
+ * Protected copy constructor
+ * @param value Other element
+ */
+ Member(const Member<Type> &member) : _base(member._base), _index(member._index), _parent(member._parent) {}
+
+ /**
+ * Add parent
+ * @param parent
+ * @return Member
+ */
+ Member &add(Member *parent)
+ {
+ _parent = parent;
+ return *this;
+ }
+
+ /**
+ * The original index
+ * @var Type
+ */
+ Type _index;
+
+ /**
+ * Base value
+ * @var Value
+ */
+ Value _base;
+
+ /**
+ * Parent member (in case of nested members)
+ * @var Member
+ */
+ Member *_parent = nullptr;
+
+ /**
+ * Only value objects may construct members
+ */
+ friend class Value;
+
};
-
+
/**
- * End of namespace
+ * End of namespace
*/
}
diff --git a/include/type.h b/include/type.h
index f3e357f..200d658 100644
--- a/include/type.h
+++ b/include/type.h
@@ -19,7 +19,7 @@ namespace PhpCpp {
*/
typedef enum _Type {
nullType = 0,
- intType = 1,
+ longType = 1,
decimalType = 2,
boolType = 3,
arrayType = 4,
diff --git a/include/value.h b/include/value.h
index 6619dcb..2cc9029 100644
--- a/include/value.h
+++ b/include/value.h
@@ -63,6 +63,12 @@ public:
Value(bool value);
/**
+ * Constructor based on single character
+ * @param value
+ */
+ Value(char value);
+
+ /**
* Constructor based on string value
* @param value
*/
@@ -95,6 +101,12 @@ public:
Value(const Value &that);
/**
+ * Move constructor
+ * @param value
+ */
+ Value(Value &&that);
+
+ /**
* Destructor
*/
virtual ~Value();
@@ -132,6 +144,13 @@ public:
* @param value
* @return Value
*/
+ Value &operator=(char value);
+
+ /**
+ * Assignment operator
+ * @param value
+ * @return Value
+ */
Value &operator=(const std::string &value);
/**
@@ -158,49 +177,83 @@ public:
* Change the internal type of the variable
* @param Type
*/
- void setType(Type type);
+ Value &setType(Type type);
+
+ /**
+ * Make a clone of the value with the same type
+ * @return Value
+ */
+ Value clone() const;
+
+ /**
+ * Make a clone of the value with a different type
+ * @param type
+ * @return Value
+ */
+ Value clone(Type type) const;
/**
* Is this a NULL value?
* @return bool
*/
- bool isNull() const;
+ bool isNull() const
+ {
+ return type() == nullType;
+ }
/**
* Is this an integer value?
* @return bool
*/
- bool isLong() const;
+ bool isLong() const
+ {
+ return type() == longType;
+ }
/**
* Is this a boolean value?
* @return bool
*/
- bool isBool() const;
+ bool isBool() const
+ {
+ return type() == boolType;
+ }
/**
* Is this a string value?
* @return bool
*/
- bool isString() const;
+ bool isString() const
+ {
+ return type() == stringType;
+ }
/**
* Is this a decimal value?
* @return bool
*/
- bool isDecimal() const;
+ bool isDecimal() const
+ {
+ return type() == decimalType;
+ }
/**
* Is this an object value?
* @return bool
*/
- bool isObject() const;
+ bool isObject() const
+ {
+ return type() == objectType;
+ }
/**
* Is this an array value?
* @return bool
*/
- bool isArray() const;
+ bool isArray() const
+ {
+ return type() == arrayType;
+ }
/**
* Retrieve the value as integer
@@ -217,7 +270,7 @@ public:
/**
* Retrieve the raw string value
* Warning: Only use this for NULL terminated strings, or use it in combination
- * with the string size to prevent that you access data outside the buffer
+ * with the string size to prevent that you access data outside the buffer
* @return const char *
*/
const char *rawValue() const;
@@ -270,12 +323,15 @@ public:
* @param key
* @return bool
*/
- bool contains(const std::string &key) const;
+ bool contains(const std::string &key) const
+ {
+ return contains(key.c_str(), key.size());
+ }
/**
* Is a certain key set in the array
* @param key
- * @param size
+ * @param size
* @return bool
*/
bool contains(const char *key, int size) const;
@@ -313,8 +369,8 @@ public:
*/
operator const char * () const
{
- return rawValue();
- }
+ return rawValue();
+ }
/**
* Cast to a floating point
@@ -327,63 +383,71 @@ public:
/**
* Get access to a certain array member
- * @param index
+ * @param index
* @return Value
*/
Value get(int index) const;
/**
* Get access to a certain assoc member
- * @param key
- * @param size
- * @return Value
+ * @param key
+ * @param size
+ * @return Value
*/
Value get(const char *key, int size=-1) const;
/**
* Get access to a certain assoc member
- * @param key
- * @return Value
+ * @param key
+ * @return Value
*/
Value get(const std::string &key) const
{
- return get(key.c_str(), key.size());
- }
+ return get(key.c_str(), key.size());
+ }
/**
* Set a certain property
- * @param index
- * @param value
+ * Calling this method will turn the value into an array
+ * @param index Index of the property to set
+ * @param value Value to set
+ * @return Value The value that was set
*/
- void set(int index, const Value &value);
+ const Value &set(int index, const Value &value);
/**
* Set a certain property
- * @param key
- * @param value
+ * Calling this method will turn the value into an array
+ * @param key Key of the property to set
+ * @param size Size of the key
+ * @param value Value to set
+ * @return Value The value that was set
*/
- void set(const char *key, int size, const Value &value);
+ const Value &set(const char *key, int size, const Value &value);
/**
* Set a certain property
- * @param key
- * @param size
- * @param value
+ * Calling this method will turn the object into an array
+ * @param key Key to set
+ * @param value Value to set
+ * @return Value The value that was set
*/
- void set(const char *key, const Value &value)
+ const Value &set(const char *key, const Value &value)
{
- set(key, strlen(key), value);
- }
+ return set(key, strlen(key), value);
+ }
/**
* Set a certain property
- * @param key
- * @param value
+ * Calling this method will turn the object into an array
+ * @param key Key to set
+ * @param value Value to set
+ * @return Value The value that was set
*/
- void set(const std::string &key, const Value &value)
+ const Value &set(const std::string &key, const Value &value)
{
- set(key.c_str(), key.size(), value);
- }
+ return set(key.c_str(), key.size(), value);
+ }
/**
* Array access operator
@@ -401,13 +465,13 @@ public:
*/
Member<std::string> operator[](const std::string &key);
- /**
- * Array access operator
- * This can be used for accessing associative arrays
- * @param key
- * @return Member
- */
- Member<std::string> operator[](const char *key);
+ /**
+ * Array access operator
+ * This can be used for accessing associative arrays
+ * @param key
+ * @return Member
+ */
+ Member<std::string> operator[](const char *key);
protected:
diff --git a/phpcpp.h b/phpcpp.h
index f9dbdba..5623c8e 100644
--- a/phpcpp.h
+++ b/phpcpp.h
@@ -31,9 +31,9 @@
* Macro to export a function
*/
#if defined(__GNUC__) && __GNUC__ >= 4
-# define PHPCPP_EXPORT __attribute__ ((visibility("default")))
+# define PHPCPP_EXPORT __attribute__ ((visibility("default")))
#else
-# define PHPCPP_EXPORT
+# define PHPCPP_EXPORT
#endif
/**
diff --git a/src/callable.cpp b/src/callable.cpp
index 7cba919..b9f67d0 100644
--- a/src/callable.cpp
+++ b/src/callable.cpp
@@ -136,43 +136,32 @@ int Callable::invoke(INTERNAL_FUNCTION_PARAMETERS)
// number of arguments on the stack
int arg_count = (int)(zend_uintptr_t) *(zend_vm_stack_top(TSRMLS_C) - 1);
- // loop through the arguments
- Arguments args(ZEND_NUM_ARGS());
-
- for (auto iter = args.begin(); iter != args.end(); iter++)
- {
- Value val = *iter;
-
- val = 1234;
-
- std::cout << "argument: " << iter->stringValue() << std::endl;
- }
-
- int result = do_test(args[1], args[2]);
-
+// // loop through the arguments
+// Arguments args(ZEND_NUM_ARGS());
+//
+// for (auto iter = args.begin(); iter != args.end(); iter++)
+// {
+// Value val = *iter;
+//
+// val = 1234;
+// }
+//
+// int result = do_test(args[1], args[2]);
+//
Value ret(return_value, true);
std::cout << "set property 1" << std::endl;
- ret["a"] = 1;
-
- std::cout << "set property 2" << std::endl;
-
- ret["2"] = 3;
-
-// ret["hmm"]["s"] = 456;
-
- Value sub;
- sub["something"] = "yes";
-
- ret["b"] = sub;
+// ret["b"] = "hallo";
+ ret["x"]["c"]["d"] = "test 123";
+
std::cout << "done setting properties" << std::endl;
//
// // done
-// return SUCCESS;
+ return SUCCESS;
}
diff --git a/src/value.cpp b/src/value.cpp
index a4dcb25..9224162 100644
--- a/src/value.cpp
+++ b/src/value.cpp
@@ -75,6 +75,17 @@ Value::Value(bool value)
}
/**
+ * Constructor based on single character
+ * @param value
+ */
+Value::Value(char value)
+{
+ // create a string zval
+ MAKE_STD_ZVAL(_val);
+ ZVAL_STRINGL(_val, &value, 1, 1);
+}
+
+/**
* Constructor based on string value
* @param value
*/
@@ -134,11 +145,28 @@ Value::Value(struct _zval_struct *zval, bool ref)
*/
Value::Value(const Value &that)
{
- // just copy the zval, and the refcounter
+ // just copy the zval
_val = that._val;
- // and we have one more reference
+ // and we have one more reference
Z_ADDREF_P(_val);
+
+ // two value objects are both sharing the same zval, we turn the zval into a reference
+ // @todo this is not necessarily correct
+ Z_SET_ISREF_P(_val);
+}
+
+/**
+ * Move constructor
+ * @param value
+ */
+Value::Value(Value &&that)
+{
+ // just copy the zval
+ _val = that._val;
+
+ // clear the other object
+ that._val = nullptr;
}
/**
@@ -146,6 +174,14 @@ Value::Value(const Value &that)
*/
Value::~Value()
{
+ // ignore if moved
+ if (!_val) return;
+
+ // if there were two references or less, we're going to remove a reference
+ // and only one reference will remain, the object will then impossible be
+ // a reference
+ if (Z_REFCOUNT_P(_val) <= 2) Z_UNSET_ISREF_P(_val);
+
// destruct the zval (this function will decrement the reference counter,
// and only destruct if there are no other references left)
zval_ptr_dtor(&_val);
@@ -240,6 +276,26 @@ Value &Value::operator=(bool value)
* @param value
* @return Value
*/
+Value &Value::operator=(char value)
+{
+ // if this is not a reference variable, we should detach it to implement copy on write
+ SEPARATE_ZVAL_IF_NOT_REF(&_val);
+
+ // deallocate current zval (without cleaning the zval structure)
+ zval_dtor(_val);
+
+ // set new value
+ ZVAL_STRINGL(_val, &value, 1, 1);
+
+ // done
+ return *this;
+}
+
+/**
+ * Assignment operator
+ * @param value
+ * @return Value
+ */
Value &Value::operator=(const std::string &value)
{
// if this is not a reference variable, we should detach it to implement copy on write
@@ -307,11 +363,12 @@ Type Value::type() const
/**
* Change the internal type
* @param type
+ * @return Value
*/
-void Value::setType(Type type)
+Value &Value::setType(Type type)
{
// skip if nothing changes
- if (this->type() == type) return;
+ if (this->type() == type) return *this;
// if this is not a reference variable, we should detach it to implement copy on write
SEPARATE_ZVAL_IF_NOT_REF(&_val);
@@ -319,76 +376,52 @@ void Value::setType(Type type)
// run the conversion
switch (type) {
case nullType: convert_to_null(_val); break;
- case intType: convert_to_long(_val); break;
+ case longType: convert_to_long(_val); break;
case decimalType: convert_to_double(_val); break;
case boolType: convert_to_boolean(_val); break;
case arrayType: convert_to_array(_val); break;
case objectType: convert_to_object(_val); break;
case stringType: convert_to_string(_val); break;
}
+
+ // done
+ return *this;
}
/**
- * Is this a NULL value?
- * @return bool
- */
-bool Value::isNull() const
-{
- return Z_TYPE_P(_val) == IS_NULL;
-}
-
-/**
- * Is this a long value?
- * @return bool
- */
-bool Value::isLong() const
-{
- return Z_TYPE_P(_val) == IS_LONG;
-}
-
-/**
- * Is this a boolean value?
- * @return bool
- */
-bool Value::isBool() const
-{
- return Z_TYPE_P(_val) == IS_BOOL;
-}
-
-/**
- * Is this a string value?
- * @return bool
+ * Make a clone of the type
+ * @return Value
*/
-bool Value::isString() const
+Value Value::clone() const
{
- return Z_TYPE_P(_val) == IS_STRING;
+ // the zval that will hold the copy
+ zval *copy;
+
+ // allocate memory
+ ALLOC_ZVAL(copy);
+
+ // copy the data
+ INIT_PZVAL_COPY(copy, _val);
+
+ // run the copy constructor to ensure that everything gets copied
+ zval_copy_ctor(copy);
+
+ // done
+ return Value(copy);
}
/**
- * Is this a decimal value?
- * @return bool
+ * Clone the zval to a different type
+ * @param type
+ * @return Value
*/
-bool Value::isDecimal() const
+Value Value::clone(Type type) const
{
- return Z_TYPE_P(_val) == IS_DOUBLE;
-}
+ // regular clone if nothing changes
+ if (this->type() == type) return clone();
-/**
- * Is this an object value?
- * @return bool
- */
-bool Value::isObject() const
-{
- return Z_TYPE_P(_val) == IS_OBJECT;
-}
-
-/**
- * Is this an array value?
- * @return bool
- */
-bool Value::isArray() const
-{
- return Z_TYPE_P(_val) == IS_ARRAY;
+ // make a clone
+ return clone().setType(type);
}
/**
@@ -400,14 +433,8 @@ long Value::longValue() const
// already a long?
if (isLong()) return Z_LVAL_P(_val);
- // make a copy
- Value copy(*this);
-
- // convert the copy to an int
- copy.setType(intType);
-
- // return the long value
- return copy.longValue();
+ // make a clone
+ return clone(longType).longValue();
}
/**
@@ -419,14 +446,8 @@ bool Value::boolValue() const
// already a bool?
if (isBool()) return Z_BVAL_P(_val);
- // make a copy
- Value copy(*this);
-
- // convert the copy to an int
- copy.setType(boolType);
-
- // return the bool value
- return copy.boolValue();
+ // make a clone
+ return clone(boolType).boolValue();
}
/**
@@ -438,14 +459,8 @@ std::string Value::stringValue() const
// already a string?
if (isString()) return std::string(Z_STRVAL_P(_val), Z_STRLEN_P(_val));
- // make a copy
- Value copy(*this);
-
- // convert the copy to an string
- copy.setType(stringType);
-
- // return the string value
- return copy.stringValue();
+ // make a clone
+ return clone(stringType).stringValue();
}
/**
@@ -457,14 +472,8 @@ const char *Value::rawValue() const
// already a string?
if (isString()) return Z_STRVAL_P(_val);
- // make a copy
- Value copy(*this);
-
- // convert the copy to an string
- copy.setType(stringType);
-
- // return the string value
- return copy.rawValue();
+ // make a clone
+ return clone(stringType).rawValue();
}
/**
@@ -476,14 +485,8 @@ double Value::decimalValue() const
// already a double
if (isDecimal()) return Z_DVAL_P(_val);
- // make a copy
- Value copy(*this);
-
- // convert the copy to an double
- copy.setType(decimalType);
-
- // return the decimal value
- return copy.decimalValue();
+ // make a clone
+ return clone(decimalType).decimalValue();
}
/**
@@ -528,23 +531,6 @@ bool Value::contains(int index) const
/**
* Does the array contain a certain key
* @param key
- * @return bool
- */
-bool Value::contains(const std::string &key) const
-{
- // must be an array
- if (!isArray()) return false;
-
- // unused variable
- zval **result;
-
- // check if index is already in the array
- return zend_hash_find(Z_ARRVAL_P(_val), key.c_str(), key.size() + 1, (void **)&result) != FAILURE;
-}
-
-/**
- * Does the array contain a certain key
- * @param key
* @param size
* @return boolean
*/
@@ -565,14 +551,14 @@ bool Value::contains(const char *key, int size) const
/**
* Get access to a certain array member
- * @param index
+ * @param index
* @return Value
*/
Value Value::get(int index) const
{
- // must be an array
- if (!isArray()) return Value();
-
+ // must be an array
+ if (!isArray()) return Value();
+
// zval to retrieve
zval **result;
@@ -585,12 +571,15 @@ Value Value::get(int index) const
/**
* Get access to a certain assoc member
- * @param key
- * @param size
- * @return Value
+ * @param key
+ * @param size
+ * @return Value
*/
Value Value::get(const char *key, int size) const
{
+ // must be an array
+ if (!isArray()) return Value();
+
// calculate size
if (size < 0) size = strlen(key);
@@ -606,46 +595,73 @@ Value Value::get(const char *key, int size) const
/**
* Set a certain property
- * @param index
- * @param value
+ * @param index
+ * @param value
+ * @return Value
*/
-void Value::set(int index, const Value &value)
+const Value &Value::set(int index, const Value &value)
{
+ // the current value
+ zval **current;
+
+ // check if this index is already in the array, otherwise we return NULL
+ if (isArray() && zend_hash_index_find(Z_ARRVAL_P(_val), index, (void **)&current) != FAILURE)
+ {
+ // skip if nothing is going to change
+ if (value._val == *current) return value;
+ }
+
// must be an array
setType(arrayType);
// if this is not a reference variable, we should detach it to implement copy on write
SEPARATE_ZVAL_IF_NOT_REF(&_val);
- // add the value
+ // add the value (this will decrement refcount on any current variable)
add_index_zval(_val, index, value._val);
// the variable has one more reference (the array entry)
Z_ADDREF_P(value._val);
+
+ // done
+ return value;
}
/**
* Set a certain property
- * @param key
- * @param size
- * @param value
+ * @param key
+ * @param size
+ * @param value
+ * @return Value
*/
-void Value::set(const char *key, int size, const Value &value)
+const Value &Value::set(const char *key, int size, const Value &value)
{
+ // the current value
+ zval **current;
+
+ // check if this index is already in the array, otherwise we return NULL
+ if (isArray() && zend_hash_find(Z_ARRVAL_P(_val), key, size + 1, (void **)&current) != FAILURE)
+ {
+ // skip if nothing is going to change
+ if (value._val == *current) return value;
+ }
+
// must be an array
setType(arrayType);
-
+
// if this is not a reference variable, we should detach it to implement copy on write
SEPARATE_ZVAL_IF_NOT_REF(&_val);
-
- // add the value
+
+ // add the value (this will reduce the refcount of the current value)
add_assoc_zval_ex(_val, key, size+1, value._val);
// the variable has one more reference (the array entry)
Z_ADDREF_P(value._val);
+
+ // done
+ return value;
}
-
/**
* Array access operator
* This can be used for accessing arrays
@@ -654,29 +670,29 @@ void Value::set(const char *key, int size, const Value &value)
*/
Member<int> Value::operator[](int index)
{
- return Member<int>(this, index);
+ return Member<int>(this, index);
}
/**
- * Array access operator
+ * Array access operato
* This can be used for accessing associative arrays
* @param key
* @return Member
*/
Member<std::string> Value::operator[](const std::string &key)
{
- return Member<std::string>(this, key);
+ return Member<std::string>(this, key);
}
/**
* Array access operator
* This can be used for accessing associative arrays
- * @param key
- * @return Member
+ * @param key
+ * @return Member
*/
Member<std::string> Value::operator[](const char *key)
{
- return Member<std::string>(this, key);
+ return Member<std::string>(this, key);
}
/**