diff options
-rw-r--r-- | include/member.h | 236 | ||||
-rw-r--r-- | include/value.h | 204 | ||||
-rw-r--r-- | phpcpp.h | 2 | ||||
-rw-r--r-- | src/callable.cpp | 18 | ||||
-rw-r--r-- | src/includes.h | 1 | ||||
-rw-r--r-- | src/value.cpp | 353 | ||||
-rw-r--r-- | tests/simple/simple.php | 4 |
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: @@ -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); + +?> |