summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2013-08-29 17:03:00 +0200
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2013-08-29 17:03:00 +0200
commit3537cce27590c6197ffe458ac6cc7dee39040e7b (patch)
treeb780efd8140dc86a9109df48911d696330c5a188
parent8cb852a298cf8aa260883c5bc474bcf8cb7f9a76 (diff)
working with arrays is now almost as simple as it is in PHP
-rw-r--r--include/member.h236
-rw-r--r--include/value.h204
-rw-r--r--phpcpp.h2
-rw-r--r--src/callable.cpp18
-rw-r--r--src/includes.h1
-rw-r--r--src/value.cpp353
-rw-r--r--tests/simple/simple.php4
7 files changed, 687 insertions, 131 deletions
diff --git a/include/member.h b/include/member.h
new file mode 100644
index 0000000..86e3554
--- /dev/null
+++ b/include/member.h
@@ -0,0 +1,236 @@
+/**
+ * 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
+ *
+ * This is an abstract class. You are not supposed to instantiate it
+ * yourself. An instance of it is created when you call Value::operator[]
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2013 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace PhpCpp {
+
+/**
+ * Forward definitions
+ */
+class Value;
+
+/**
+ * Member class
+ */
+template <class Type>
+class Member
+{
+public:
+ /**
+ * Destructor
+ */
+ virtual ~Member() {}
+
+ /**
+ * Assign a numeric value
+ * @param value
+ * @return Member
+ */
+ Member &operator=(long value)
+ {
+ _value->set(_index, value);
+ return *this;
+ }
+
+ /**
+ * Assign a numeric value
+ * @param value
+ * @return Member
+ */
+ Member &operator=(int value)
+ {
+ _value->set(_index, value);
+ return *this;
+ }
+
+ /**
+ * Assign a double value
+ * @param value
+ * @return Member
+ */
+ Member &operator=(double value)
+ {
+ _value->set(_index, value);
+ return *this;
+ }
+
+ /**
+ * Assign a boolean value
+ * @param value
+ * @return Member
+ */
+ Member &operator=(bool value)
+ {
+ _value->set(_index, value);
+ return *this;
+ }
+
+ /**
+ * Assign a string value
+ * @param value
+ * @return Member
+ */
+ Member &operator=(const std::string &value)
+ {
+ _value->set(_index, value);
+ return *this;
+ }
+
+ /**
+ * Assign a byte array value
+ * @param value
+ * @return Member
+ */
+ Member &operator=(const char *value)
+ {
+ _value->set(_index, value);
+ return *this;
+ }
+
+ /**
+ * Retrieve the original value
+ * @return Value
+ */
+ Value value() const
+ {
+ return _value->get(_index);
+ }
+
+ /**
+ * Cast to a value object
+ * @return Value
+ */
+ operator Value () const
+ {
+ return _value->get(_index);
+ }
+
+ /**
+ * Cast to a long
+ * @return long
+ */
+ operator long () const
+ {
+ return _value->get(_index).longValue();
+ }
+
+ /**
+ * Cast to a boolean
+ * @return boolean
+ */
+ operator bool () const
+ {
+ return _value->get(_index).boolValue();
+ }
+
+ /**
+ * Cast to a string
+ * @return string
+ */
+ operator std::string () const
+ {
+ return _value->get(_index).stringValue();
+ }
+
+ /**
+ * Cast to byte array
+ * @return const char *
+ */
+ operator const char * () const
+ {
+ return _value->get(_index).rawValue();
+ }
+
+ /**
+ * Cast to a floating point
+ * @return double
+ */
+ operator double () const
+ {
+ return _value->get(_index).decimalValue();
+ }
+
+ /**
+ * Array access operator
+ * This can be used for accessing arrays
+ * @param index
+ * @return Member
+ */
+ Member operator[](int index)
+ {
+ return _value->get(_index)[index];
+ }
+
+ /**
+ * Array access operator
+ * This can be used for accessing associative arrays
+ * @param key
+ * @return Member
+ */
+ Member operator[](const std::string &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 _value->get(_index)[key];
+ }
+
+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) {}
+
+ /**
+ * The array of which this is a member
+ * @var Value
+ */
+ Value *_value;
+
+ /**
+ * The original index
+ * @var Type
+ */
+ Type _index;
+
+ /**
+ * Value objects may create members
+ */
+ friend class Value;
+};
+
+/**
+ * End of namespace
+ */
+}
+
diff --git a/include/value.h b/include/value.h
index bc25eab..6619dcb 100644
--- a/include/value.h
+++ b/include/value.h
@@ -29,6 +29,11 @@ struct _zval_struct;
namespace PhpCpp {
/**
+ * Forward definitions
+ */
+template <class Type> class Member;
+
+/**
* Class definition
*/
class Value
@@ -38,7 +43,7 @@ public:
* Empty constructor (value = NULL)
*/
Value();
-
+
/**
* Constructor based on integer value
* @param value
@@ -46,6 +51,12 @@ public:
Value(int value);
/**
+ * Constructor based on integer value
+ * @param value
+ */
+ Value(long value);
+
+ /**
* Constructor based on boolean value
* @param value
*/
@@ -58,6 +69,13 @@ public:
Value(const std::string &value);
/**
+ * Constructor based on byte buffer
+ * @param value
+ * @param size
+ */
+ Value(const char *value, int size = -1);
+
+ /**
* Constructor based on decimal value
* @param value
*/
@@ -93,6 +111,13 @@ public:
* @param value
* @return Value
*/
+ Value &operator=(long value);
+
+ /**
+ * Assignment operator
+ * @param value
+ * @return Value
+ */
Value &operator=(int value);
/**
@@ -114,13 +139,20 @@ public:
* @param value
* @return Value
*/
+ Value &operator=(const char *value);
+
+ /**
+ * Assignment operator
+ * @param value
+ * @return Value
+ */
Value &operator=(double value);
/**
* The type of object
* @return Type
*/
- Type type();
+ Type type() const;
/**
* Change the internal type of the variable
@@ -132,79 +164,87 @@ public:
* Is this a NULL value?
* @return bool
*/
- bool isNull();
+ bool isNull() const;
/**
* Is this an integer value?
* @return bool
*/
- bool isInt();
+ bool isLong() const;
/**
* Is this a boolean value?
* @return bool
*/
- bool isBool();
+ bool isBool() const;
/**
* Is this a string value?
* @return bool
*/
- bool isString();
+ bool isString() const;
/**
* Is this a decimal value?
* @return bool
*/
- bool isDecimal();
+ bool isDecimal() const;
/**
* Is this an object value?
* @return bool
*/
- bool isObject();
+ bool isObject() const;
/**
* Is this an array value?
* @return bool
*/
- bool isArray();
+ bool isArray() const;
/**
* Retrieve the value as integer
* @return int
*/
- int intValue();
+ long longValue() const;
/**
* Retrieve the value as boolean
* @return bool
*/
- bool boolValue();
+ bool boolValue() const;
/**
- * Retrieve the value as string
+ * 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
+ * @return const char *
+ */
+ const char *rawValue() const;
+
+ /**
+ * Retrieve the value as a string
* @return string
*/
- std::string stringValue();
+ std::string stringValue() const;
/**
* Retrieve the value as decimal
* @return double
*/
- double decimalValue();
+ double decimalValue() const;
/**
* The number of members in case of an array or object
* @return int
*/
- int size();
+ int size() const;
/**
* The number of members in case of an array or object
* @return int
*/
- int count()
+ int count() const
{
return size();
}
@@ -213,25 +253,47 @@ public:
* The number of members in case of an array or object
* @return int
*/
- int length()
+ int length() const
{
return size();
}
/**
- * Cast to an int
- * @return int
+ * Is a certain index set in the array
+ * @param index
+ * @return bool
+ */
+ bool contains(int index) const;
+
+ /**
+ * Is a certain key set in the array
+ * @param key
+ * @return bool
+ */
+ bool contains(const std::string &key) const;
+
+ /**
+ * Is a certain key set in the array
+ * @param key
+ * @param size
+ * @return bool
+ */
+ bool contains(const char *key, int size) const;
+
+ /**
+ * Cast to a long
+ * @return long
*/
- operator int ()
+ operator long () const
{
- return intValue();
+ return longValue();
}
/**
* Cast to a boolean
* @return boolean
*/
- operator bool ()
+ operator bool () const
{
return boolValue();
}
@@ -240,46 +302,112 @@ public:
* Cast to a string
* @return string
*/
- operator std::string ()
+ operator std::string () const
{
return stringValue();
}
/**
+ * Cast to byte array
+ * @return const char *
+ */
+ operator const char * () const
+ {
+ return rawValue();
+ }
+
+ /**
* Cast to a floating point
* @return double
*/
- operator double ()
+ operator double () const
{
return decimalValue();
}
/**
+ * Get access to a certain array member
+ * @param index
+ * @return Value
+ */
+ Value get(int index) const;
+
+ /**
+ * Get access to a certain assoc member
+ * @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
+ */
+ Value get(const std::string &key) const
+ {
+ return get(key.c_str(), key.size());
+ }
+
+ /**
+ * Set a certain property
+ * @param index
+ * @param value
+ */
+ void set(int index, const Value &value);
+
+ /**
+ * Set a certain property
+ * @param key
+ * @param value
+ */
+ void set(const char *key, int size, const Value &value);
+
+ /**
+ * Set a certain property
+ * @param key
+ * @param size
+ * @param value
+ */
+ void set(const char *key, const Value &value)
+ {
+ set(key, strlen(key), value);
+ }
+
+ /**
+ * Set a certain property
+ * @param key
+ * @param value
+ */
+ void set(const std::string &key, const Value &value)
+ {
+ set(key.c_str(), key.size(), value);
+ }
+
+ /**
* Array access operator
* This can be used for accessing arrays
- * Be aware: if the 'this' object is not already an array, it will be converted into one!
* @param index
- * @return Value
+ * @return Member
*/
- Value operator[](int index);
+ Member<int> operator[](int index);
/**
* Array access operator
* This can be used for accessing associative arrays
- * Be aware: if the 'this' object is not already an array, it will be converted into one!
* @param key
- * @return Value
+ * @return Member
*/
- Value operator[](const std::string &key);
+ Member<std::string> operator[](const std::string &key);
- /**
- * Array access operator
- * This can be used for adding a record to the array
- * Be aware: if the 'this' object is not already an array, it will be converted into one!
- * @param key
- * @return Value
- */
- //Value operator[]();
+ /**
+ * 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 301f802..f9dbdba 100644
--- a/phpcpp.h
+++ b/phpcpp.h
@@ -10,6 +10,7 @@
/**
* Other C and C++ libraries that PhpCpp depends on
*/
+#include <string.h>
#include <string>
#include <initializer_list>
#include <vector>
@@ -21,6 +22,7 @@
#include <phpcpp/request.h>
#include <phpcpp/argument.h>
#include <phpcpp/value.h>
+#include <phpcpp/member.h>
#include <phpcpp/arguments.h>
#include <phpcpp/function.h>
#include <phpcpp/extension.h>
diff --git a/src/callable.cpp b/src/callable.cpp
index b4b1a6e..929f39c 100644
--- a/src/callable.cpp
+++ b/src/callable.cpp
@@ -150,14 +150,22 @@ int Callable::invoke(INTERNAL_FUNCTION_PARAMETERS)
int result = do_test(args[1], args[2]);
- return SUCCESS;
-
Value ret(return_value, true);
- ret = result;
+ std::cout << "set property 1" << std::endl;
+
+ ret["a"] = 1;
+
+ std::cout << "set property 2" << std::endl;
- // done
- return SUCCESS;
+ ret["2"] = 3;
+
+ std::cout << "done setting properties" << std::endl;
+
+
+//
+// // done
+// return SUCCESS;
}
diff --git a/src/includes.h b/src/includes.h
index 37b8b1b..58f14c2 100644
--- a/src/includes.h
+++ b/src/includes.h
@@ -35,6 +35,7 @@
#include "../include/request.h"
#include "../include/argument.h"
#include "../include/value.h"
+#include "../include/member.h"
#include "../include/arguments.h"
#include "../include/function.h"
#include "../include/extension.h"
diff --git a/src/value.cpp b/src/value.cpp
index 64c33ea..a4dcb25 100644
--- a/src/value.cpp
+++ b/src/value.cpp
@@ -53,6 +53,17 @@ Value::Value(int value)
}
/**
+ * Constructor based on long value
+ * @param value
+ */
+Value::Value(long value)
+{
+ // create an integer zval
+ MAKE_STD_ZVAL(_val);
+ ZVAL_LONG(_val, value);
+}
+
+/**
* Constructor based on boolean value
* @param value
*/
@@ -75,6 +86,18 @@ Value::Value(const std::string &value)
}
/**
+ * Constructor based on a byte array
+ * @param value
+ * @param size
+ */
+Value::Value(const char *value, int size)
+{
+ // create a string zval
+ MAKE_STD_ZVAL(_val);
+ ZVAL_STRINGL(_val, value, size < 0 ? strlen(value) : size, 1);
+}
+
+/**
* Constructor based on decimal value
* @param value
*/
@@ -177,6 +200,26 @@ Value &Value::operator=(int value)
* @param value
* @return Value
*/
+Value &Value::operator=(long 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_LONG(_val, value);
+
+ // done
+ return *this;
+}
+
+/**
+ * Assignment operator
+ * @param value
+ * @return Value
+ */
Value &Value::operator=(bool value)
{
// if this is not a reference variable, we should detach it to implement copy on write
@@ -217,6 +260,26 @@ Value &Value::operator=(const std::string &value)
* @param value
* @return Value
*/
+Value &Value::operator=(const 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_STRING(_val, value, 1);
+
+ // done
+ return *this;
+}
+
+/**
+ * Assignment operator
+ * @param value
+ * @return Value
+ */
Value &Value::operator=(double value)
{
// if this is not a reference variable, we should detach it to implement copy on write
@@ -236,7 +299,7 @@ Value &Value::operator=(double value)
* The type of object
* @return Type
*/
-Type Value::type()
+Type Value::type() const
{
return (Type)Z_TYPE_P(_val);
}
@@ -249,6 +312,9 @@ void Value::setType(Type type)
{
// skip if nothing changes
if (this->type() == type) return;
+
+ // if this is not a reference variable, we should detach it to implement copy on write
+ SEPARATE_ZVAL_IF_NOT_REF(&_val);
// run the conversion
switch (type) {
@@ -266,16 +332,16 @@ void Value::setType(Type type)
* Is this a NULL value?
* @return bool
*/
-bool Value::isNull()
+bool Value::isNull() const
{
return Z_TYPE_P(_val) == IS_NULL;
}
/**
- * Is this an integer value?
+ * Is this a long value?
* @return bool
*/
-bool Value::isInt()
+bool Value::isLong() const
{
return Z_TYPE_P(_val) == IS_LONG;
}
@@ -284,7 +350,7 @@ bool Value::isInt()
* Is this a boolean value?
* @return bool
*/
-bool Value::isBool()
+bool Value::isBool() const
{
return Z_TYPE_P(_val) == IS_BOOL;
}
@@ -293,7 +359,7 @@ bool Value::isBool()
* Is this a string value?
* @return bool
*/
-bool Value::isString()
+bool Value::isString() const
{
return Z_TYPE_P(_val) == IS_STRING;
}
@@ -302,7 +368,7 @@ bool Value::isString()
* Is this a decimal value?
* @return bool
*/
-bool Value::isDecimal()
+bool Value::isDecimal() const
{
return Z_TYPE_P(_val) == IS_DOUBLE;
}
@@ -311,7 +377,7 @@ bool Value::isDecimal()
* Is this an object value?
* @return bool
*/
-bool Value::isObject()
+bool Value::isObject() const
{
return Z_TYPE_P(_val) == IS_OBJECT;
}
@@ -320,19 +386,19 @@ bool Value::isObject()
* Is this an array value?
* @return bool
*/
-bool Value::isArray()
+bool Value::isArray() const
{
return Z_TYPE_P(_val) == IS_ARRAY;
}
/**
* Retrieve the value as integer
- * @return int
+ * @return long
*/
-int Value::intValue()
+long Value::longValue() const
{
- // already an int?
- if (isInt()) return Z_LVAL_P(_val);
+ // already a long?
+ if (isLong()) return Z_LVAL_P(_val);
// make a copy
Value copy(*this);
@@ -340,15 +406,15 @@ int Value::intValue()
// convert the copy to an int
copy.setType(intType);
- // return the int value
- return copy.intValue();
+ // return the long value
+ return copy.longValue();
}
/**
* Retrieve the value as boolean
* @return bool
*/
-bool Value::boolValue()
+bool Value::boolValue() const
{
// already a bool?
if (isBool()) return Z_BVAL_P(_val);
@@ -359,15 +425,15 @@ bool Value::boolValue()
// convert the copy to an int
copy.setType(boolType);
- // return the int value
- return copy.intValue();
+ // return the bool value
+ return copy.boolValue();
}
/**
* Retrieve the value as string
* @return string
*/
-std::string Value::stringValue()
+std::string Value::stringValue() const
{
// already a string?
if (isString()) return std::string(Z_STRVAL_P(_val), Z_STRLEN_P(_val));
@@ -383,10 +449,29 @@ std::string Value::stringValue()
}
/**
+ * Retrieve raw string value
+ * @return const char *
+ */
+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();
+}
+
+/**
* Retrieve the value as decimal
* @return double
*/
-double Value::decimalValue()
+double Value::decimalValue() const
{
// already a double
if (isDecimal()) return Z_DVAL_P(_val);
@@ -405,99 +490,193 @@ double Value::decimalValue()
* The number of members in case of an array or object
* @return int
*/
-int Value::size()
+int Value::size() const
{
// is it an array
if (isArray()) return zend_hash_num_elements(Z_ARRVAL_P(_val));
+
+ // not an array, return string size if this is a string
+ if (isString()) return Z_STRLEN_P(_val);
- // not an array
- return 0;
+ // make a copy
+ Value copy(*this);
+
+ // convert the copy to a string
+ copy.setType(decimalType);
+
+ // return the string size
+ return copy.size();
}
/**
- * Array access operator
- * This can be used for accessing arrays
- * Be aware: if the 'this' object is not already an array, it will be converted into one!
+ * Does the array contain a certain index?
* @param index
- * @return Value
+ * @return bool
*/
-Value Value::operator[](int index)
+bool Value::contains(int index) const
{
// must be an array
- if (!isArray()) setType(arrayType);
+ if (!isArray()) return false;
- // the result value
+ // unused variable
zval **result;
// check if this index is already in the array
- if (zend_hash_index_find(Z_ARRVAL_P(_val), index, &result) == FAILURE)
- {
- // construct a new vale
- Value val;
-
- // we want to add a new record
- add_index_zval(Z_ARRVAL_P(_val), index, val._val);
-
- // make the value a reference, so that changing the value will also update the array
- Z_SET_ISREF_P(val._val);
-
- // done
- return val;
- }
- else
- {
- // the index is already in the array, if multiple variables all use this
- // zval, then we want to seperate it, because the other values should
- // not be updated when the member gets updated
- SEPARATE_ZVAL_IF_NOT_REF(result);
-
- // wrap it into a value, and force this to be a reference, so that
- // changing the value will also change the array member
- return Value(*result, true);
- }
+ return zend_hash_index_find(Z_ARRVAL_P(_val), index, (void**)&result) != FAILURE;
}
/**
- * Array access operator
- * This can be used for accessing associative arrays
- * Be aware: if the 'this' object is not already an array, it will be converted into one!
+ * Does the array contain a certain key
* @param key
- * @return Value
+ * @return bool
*/
-Value Value::operator[](const std::string &key)
+bool Value::contains(const std::string &key) const
{
// must be an array
- if (!isArray()) setType(arrayType);
+ 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
+ */
+bool Value::contains(const char *key, int size) const
+{
+ // must be an array
+ if (!isArray()) return false;
+
+ // calculate size
+ if (size < 0) size = strlen(key);
+
+ // unused variable
+ zval **result;
+
+ // check if index is already in the array
+ return zend_hash_find(Z_ARRVAL_P(_val), key, size+1, (void **)&result) != FAILURE;
+}
+
+/**
+ * Get access to a certain array member
+ * @param index
+ * @return Value
+ */
+Value Value::get(int index) const
+{
+ // must be an array
+ if (!isArray()) return Value();
+
+ // zval to retrieve
+ zval **result;
+
+ // check if index is in the array
+ if (zend_hash_index_find(Z_ARRVAL_P(_val), index, (void **)&result) == FAILURE) return Value();
+ // wrap the value
+ return Value(*result);
+}
+
+/**
+ * Get access to a certain assoc member
+ * @param key
+ * @param size
+ * @return Value
+ */
+Value Value::get(const char *key, int size) const
+{
+ // calculate size
+ if (size < 0) size = strlen(key);
+
// the result value
zval **result;
- // check if this index is already in the array
- if (zend_hash_find(Z_ARRVAL_P(_val), key.c_str(), key.size() + 1, &result) == FAILURE)
- {
- // construct a new vale
- Value val;
-
- // we want to add a new record
- add_assoc_zval_ex(Z_ARRVAL_P(_val), key.c_str(), key.size()+1, val._val);
-
- // make the value a reference, so that changing the value will also update the array
- Z_SET_ISREF_P(val._val);
-
- // done
- return val;
- }
- else
- {
- // the index is already in the array, if multiple variables all use this
- // zval, then we want to seperate it, because the other values should
- // not be updated when the member gets updated
- SEPARATE_ZVAL_IF_NOT_REF(result);
-
- // wrap it into a value, and force this to be a reference, so that
- // changing the value will also change the array member
- return Value(*result, true);
- }
+ // check if this index is already in the array, otherwise we return NULL
+ if (zend_hash_find(Z_ARRVAL_P(_val), key, size + 1, (void **)&result) == FAILURE) return Value();
+
+ // wrap the value
+ return Value(*result);
+}
+
+/**
+ * Set a certain property
+ * @param index
+ * @param value
+ */
+void Value::set(int index, const Value &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_index_zval(_val, index, value._val);
+
+ // the variable has one more reference (the array entry)
+ Z_ADDREF_P(value._val);
+}
+
+/**
+ * Set a certain property
+ * @param key
+ * @param size
+ * @param value
+ */
+void Value::set(const char *key, int size, const Value &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_assoc_zval_ex(_val, key, size+1, value._val);
+
+ // the variable has one more reference (the array entry)
+ Z_ADDREF_P(value._val);
+}
+
+
+/**
+ * Array access operator
+ * This can be used for accessing arrays
+ * @param index
+ * @return Member
+ */
+Member<int> Value::operator[](int index)
+{
+ return Member<int>(this, index);
+}
+
+/**
+ * Array access operator
+ * 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);
+}
+
+/**
+ * Array access operator
+ * This can be used for accessing associative arrays
+ * @param key
+ * @return Member
+ */
+Member<std::string> Value::operator[](const char *key)
+{
+ return Member<std::string>(this, key);
}
/**
diff --git a/tests/simple/simple.php b/tests/simple/simple.php
index c8614da..bdf2b74 100644
--- a/tests/simple/simple.php
+++ b/tests/simple/simple.php
@@ -16,4 +16,6 @@ echo("myvar = $myvar\n");
echo("resultaat: $result\n");
-?> \ No newline at end of file
+print_r($result);
+
+?>