diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-04-06 21:53:24 +0200 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-04-06 21:53:24 +0200 |
commit | 35fd3ccbeb4def71b4d8a59dfbb5c31201b099b9 (patch) | |
tree | 915223360aed4743aa6127fde4836aa413a260e5 /src/value.cpp | |
parent | da4710512865e6816585ac4ab8edab2fa125e2d8 (diff) |
renamed src directory to zend directory, disabled TSRM debug code
Diffstat (limited to 'src/value.cpp')
-rw-r--r-- | src/value.cpp | 1911 |
1 files changed, 0 insertions, 1911 deletions
diff --git a/src/value.cpp b/src/value.cpp deleted file mode 100644 index 2ca1585..0000000 --- a/src/value.cpp +++ /dev/null @@ -1,1911 +0,0 @@ -/** - * Value.cpp - * - * Implementation for the Value class, which wraps a PHP userspace - * value (a 'zval' in Zend's terminology) into a C++ object - * - * Reminder for the implementer: - * - * A 'zval' is an object that represents a _value_ in the PHP user space, - * and thus not a variable. A 'value' or 'zval' can be used by many - * different variables at the same time. The 'refcount' property of the - * zval holds the number of variables ($a, $b, $c, et cetera) that are - * all linked to the same value. With this system, PHP can implement copy - * on write behavior. - * - * Next to the refcount, the zval also holds a is_ref property, which is - * set to true if all variables linked to the value are references of each - * other. Thus is $a, $b and $c all point to the same variable, and is_ref - * is set to true, changing the value means that the $a, $b and $c value - * are all updated. If is_res was false, a change to $a would not mean a - * change to $b, and the zval should have been copied first. - * - * - * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> - * @copyright 2013, 2014 Copernica BV - */ -#include "includes.h" - -/** - * Set up namespace - */ -namespace Php { - -/** - * Constructor (value = NULL) - */ -Value::Value() -{ - // create a null zval - MAKE_STD_ZVAL(_val); - ZVAL_NULL(_val); -} - -/** - * Constructor for null ptr -*/ -Value::Value(std::nullptr_t value) -{ - // create a null zval - MAKE_STD_ZVAL(_val); - ZVAL_NULL(_val); -} - -/** - * Constructor based on integer value - * @param value - */ -Value::Value(int16_t value) -{ - // create an integer zval - MAKE_STD_ZVAL(_val); - ZVAL_LONG(_val, value); -} - -/** - * Constructor based on integer value - * @param value - */ -Value::Value(int32_t value) -{ - // create an integer zval - MAKE_STD_ZVAL(_val); - ZVAL_LONG(_val, value); -} - -/** - * Constructor based on int64_t value - * @param value - */ -Value::Value(int64_t value) -{ - // create an integer zval - MAKE_STD_ZVAL(_val); - ZVAL_LONG(_val, value); -} - -/** - * Constructor based on boolean value - * @param value - */ -Value::Value(bool value) -{ - // create a boolean zval - MAKE_STD_ZVAL(_val); - ZVAL_BOOL(_val, 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 - */ -Value::Value(const std::string &value) -{ - // create a string zval - MAKE_STD_ZVAL(_val); - ZVAL_STRINGL(_val, value.c_str(), value.size(), 1); -} - -/** - * 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 - */ -Value::Value(double value) -{ - // create a double zval - MAKE_STD_ZVAL(_val); - ZVAL_DOUBLE(_val, value); -} - -/** - * Wrap object around zval - * @param zval Value to wrap - * @param ref Force this to be a reference - */ -Value::Value(struct _zval_struct *val, bool ref) -{ - // just copy the zval into this object - _val = val; - - // if the variable is not already a reference, and it has more than one - // variable pointing to it, we should seperate it so that any changes - // we're going to make will not change the other variable - if (ref && Z_REFCOUNT_P(_val) > 1) - { - // separate the zval - SEPARATE_ZVAL_IF_NOT_REF(&_val); - } - - // we see ourselves as reference too - Z_ADDREF_P(_val); - - // we're ready if we do not have to force it as a reference - if (!ref || Z_ISREF_P(_val)) return; - - // make this a reference - Z_SET_ISREF_P(_val); -} - -/** - * Wrap around an object - * @param object - */ -Value::Value(const Base *object) -{ - // there are two options: the object was constructed from user space, - // and is already linked to a handle, or it was constructed from C++ - // space, and no handle does yet exist, find the implementation object - auto *impl = object->implementation(); - - // do we have a handle? - if (!impl) throw Php::Exception("Assigning an unassigned object to a variable"); - - // make a regular zval, and set it to an object - MAKE_STD_ZVAL(_val); - Z_TYPE_P(_val) = IS_OBJECT; - Z_OBJ_HANDLE_P(_val) = impl->handle(); - - // we need the tsrm_ls variable - TSRMLS_FETCH(); - - // we have to lookup the object in the object-table - zend_object_store_bucket *obj_bucket = &EG(objects_store).object_buckets[impl->handle()]; - - // this is copy-pasted from zend_objects.c - and it is necessary too! - if (!obj_bucket->bucket.obj.handlers) obj_bucket->bucket.obj.handlers = &std_object_handlers; - - // store the handlers in the zval too (cast is necessary for php 5.3) - Z_OBJ_HT_P(_val) = (zend_object_handlers*)obj_bucket->bucket.obj.handlers; - - // run the copy constructor - zval_copy_ctor(_val); -} - -/** - * Copy constructor - * @param value - */ -Value::Value(const Value &that) -{ - // is the other variable a reference? - if (Z_ISREF_P(that._val)) - { - // because this is supposed to be a COPY, we can not add ourselves - // to the variable but have to allocate a new variable - ALLOC_ZVAL(_val); - INIT_PZVAL_COPY(_val, that._val); - - // we have to call the copy constructor to copy the entire other zval - zval_copy_ctor(_val); - } - else - { - // simply use the same zval - _val = that._val; - } - - // that zval has one more reference - Z_ADDREF_P(_val); - - -// Below the old implementation - I thought really hard about it and I though -// it was a correct and very smart implementation. However, it does not work -// when you swap two variables. I changed it to the implementation above, but -// maybe that implementation introduces other bugs??? Let's keep the old -// implementation for a while in this file, but commented out -// -// // how many references does the other object have? -// if (Z_REFCOUNT_P(that._val) > 1 && !Z_ISREF_P(that._val)) -// { -// // there are already multiple variables linked to this value, and it -// // is not a reference. this implies that we can not turn this variable -// // into a reference, otherwise strange things could happen, we're going -// // to create a new zval -// ALLOC_ZVAL(_val); -// INIT_PZVAL_COPY(_val, that._val); -// zval_copy_ctor(_val); -// } -// else -// { -// // simply use the same zval -// _val = that._val; -// } -// -// // the other object only has one variable using it, or it is already -// // a variable by reference, we can safely add one more reference to it -// // and make it a variable by reference if it was not already a ref -// Z_ADDREF_P(_val); -// -// // make reference -// Z_SET_ISREF_P(_val); -} - -/** - * Move constructor - * @param value - */ -Value::Value(Value &&that) : _val(that._val) -{ - // clear the other object - that._val = nullptr; -} - -/** - * Destructor - */ -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); -} - -/** - * Detach the zval - * - * This will unlink the zval internal structure from the Value object, - * so that the destructor will not reduce the number of references and/or - * deallocate the zval structure. This is used for functions that have to - * return a zval pointer, that would otherwise be deallocated the moment - * the function returns. - * - * @return zval - */ -zval *Value::detach() -{ - // leap out if already detached - if (!_val) return nullptr; - - // copy return value - zval *result = _val; - - // decrement reference counter - Z_DELREF_P(_val); - - // reset internal object - _val = nullptr; - - // done - return result; -} - -/** - * Attach a different zval - * - * This will first detach the current zval, and link the Value object to - * a different zval. - * - * @param val - */ -void Value::attach(struct _zval_struct *val) -{ - // detach first - if (_val) detach(); - - // store the zval - _val = val; - - // add one more reference - Z_ADDREF_P(_val); -} - -/** - * Attach a different zval - * - * This will first detach the current zval, and link the Value object to - * a new zval - * - * @param hashtable - */ -void Value::attach(struct _hashtable *hashtable) -{ - // detach first - if (_val) detach(); - - // construct a new zval - MAKE_STD_ZVAL(_val); - - // store pointer to the hashtable, and mark the zval as an array - Z_ARRVAL_P(_val) = hashtable; - Z_TYPE_P(_val) = IS_ARRAY; - - // add a reference - Z_ADDREF_P(_val); -} - -/** - * Retrieve the refcount - * @return int - */ -int Value::refcount() -{ - return Z_REFCOUNT_P(_val); -} - -/** - * Move operator - * @param value - * @return Value - */ -Value &Value::operator=(Value &&value) -{ - // skip self assignment - if (this == &value) return *this; - - // is the object a reference? - if (Z_ISREF_P(_val)) - { - // @todo difference if the other object is a reference or not? - - // the current object is a reference, this means that we should - // keep the zval object, and copy the other value into it, get - // the current refcount - int refcount = Z_REFCOUNT_P(_val); - - // make the copy - *_val = *value._val; - - // restore reference and refcount setting - Z_SET_ISREF_TO_P(_val, true); - Z_SET_REFCOUNT_P(_val, refcount); - - // how many references did the old variable have? - if (Z_REFCOUNT_P(value._val) > 1) - { - // the other object already had multiple references, this - // implies that many other PHP variables are also referring - // to it, and we still need to store its contents, with one - // reference less - Z_DELREF_P(value._val); - - // and we need to run the copy constructor on the current - // value, because we're making a deep copy - zval_copy_ctor(_val); - } - else - { - // we need the tsrm_ls variable - TSRMLS_FETCH(); - - // the last and only reference to the other object was - // removed, we no longer need it - FREE_ZVAL(value._val); - - // the other object is no longer valid - value._val = nullptr; - } - } - else - { - // destruct the zval (this function will decrement the reference counter, - // and only destruct if there are no other references left) - zval_ptr_dtor(&_val); - - // just copy the zval completely - _val = value._val; - - // the other object is no longer valid - value._val = nullptr; - } - - // done - return *this; -} - -/** - * Assignment operator - * @param value - * @return Value - */ -Value &Value::operator=(const Value &value) -{ - // skip self assignment - if (this == &value) return *this; - - // is the object a reference? - if (Z_ISREF_P(_val)) - { - // the current object is a reference, this means that we should - // keep the zval object, and copy the other value into it, get - // the current refcount - int refcount = Z_REFCOUNT_P(_val); - - // clean up the current zval (but keep the zval structure) - zval_dtor(_val); - - // make the copy - *_val = *value._val; - zval_copy_ctor(_val); - - // restore refcount and reference setting - Z_SET_ISREF_TO_P(_val, true); - Z_SET_REFCOUNT_P(_val, refcount); - } - else - { - // destruct the zval (this function will decrement the reference counter, - // and only destruct if there are no other references left) - zval_ptr_dtor(&_val); - - // just copy the zval, and the refcounter - _val = value._val; - - // and we have one more reference - Z_ADDREF_P(_val); - } - - // update the object - return *this; -} - - -/** - * Assignment operator - * @param value - * @return Value - */ -Value &Value::operator=(std::nullptr_t 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); - - // change to null value - ZVAL_NULL(_val); - - // update the object - return *this; -} - -/** - * Assignment operator - * @param value - * @return Value - */ -Value &Value::operator=(int16_t 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); - - // update the object - return *this; -} - -/** - * Assignment operator - * @param value - * @return Value - */ -Value &Value::operator=(int32_t 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); - - // update the object - return *this; -} - -/** - * Assignment operator - * @param value - * @return Value - */ -Value &Value::operator=(int64_t 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); - - // update the object - 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 - SEPARATE_ZVAL_IF_NOT_REF(&_val); - - // deallocate current zval (without cleaning the zval structure) - zval_dtor(_val); - - // set new value - ZVAL_BOOL(_val, value); - - // update the object - return *this; -} - -/** - * Assignment operator - * @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); - - // update the object - 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 - SEPARATE_ZVAL_IF_NOT_REF(&_val); - - // deallocate current zval (without cleaning the zval structure) - zval_dtor(_val); - - // set new value - ZVAL_STRINGL(_val, value.c_str(), value.size(), 1); - - // update the object - return *this; -} - -/** - * Assignment operator - * @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); - - // update the object - 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 - SEPARATE_ZVAL_IF_NOT_REF(&_val); - - // deallocate current zval (without cleaning the zval structure) - zval_dtor(_val); - - // set new value - ZVAL_DOUBLE(_val, value); - - // update the object - return *this; -} - -/** - * Add a value to the object - * @param value - * @return Value - */ -Value &Value::operator+=(const Value &value) { return Arithmetic<std::plus>(this).assign(value); } -Value &Value::operator+=(int16_t value) { return Arithmetic<std::plus>(this).assign(value); } -Value &Value::operator+=(int32_t value) { return Arithmetic<std::plus>(this).assign(value); } -Value &Value::operator+=(int64_t value) { return Arithmetic<std::plus>(this).assign(value); } -Value &Value::operator+=(bool value) { return Arithmetic<std::plus>(this).assign(value); } -Value &Value::operator+=(char value) { return Arithmetic<std::plus>(this).assign(value); } -Value &Value::operator+=(const std::string &value) { return Arithmetic<std::plus>(this).assign(value); } -Value &Value::operator+=(const char *value) { return Arithmetic<std::plus>(this).assign(value); } -Value &Value::operator+=(double value) { return Arithmetic<std::plus>(this).assign(value); } - -/** - * Subtract a value from the object - * @param value - * @return Value - */ -Value &Value::operator-=(const Value &value) { return Arithmetic<std::minus>(this).assign(value); } -Value &Value::operator-=(int16_t value) { return Arithmetic<std::minus>(this).assign(value); } -Value &Value::operator-=(int32_t value) { return Arithmetic<std::minus>(this).assign(value); } -Value &Value::operator-=(int64_t value) { return Arithmetic<std::minus>(this).assign(value); } -Value &Value::operator-=(bool value) { return Arithmetic<std::minus>(this).assign(value); } -Value &Value::operator-=(char value) { return Arithmetic<std::minus>(this).assign(value); } -Value &Value::operator-=(const std::string &value) { return Arithmetic<std::minus>(this).assign(value); } -Value &Value::operator-=(const char *value) { return Arithmetic<std::minus>(this).assign(value); } -Value &Value::operator-=(double value) { return Arithmetic<std::minus>(this).assign(value); } - -/** - * Multiply the object with a certain value - * @param value - * @return Value - */ -Value &Value::operator*=(const Value &value) { return Arithmetic<std::multiplies>(this).assign(value); } -Value &Value::operator*=(int16_t value) { return Arithmetic<std::multiplies>(this).assign(value); } -Value &Value::operator*=(int32_t value) { return Arithmetic<std::multiplies>(this).assign(value); } -Value &Value::operator*=(int64_t value) { return Arithmetic<std::multiplies>(this).assign(value); } -Value &Value::operator*=(bool value) { return Arithmetic<std::multiplies>(this).assign(value); } -Value &Value::operator*=(char value) { return Arithmetic<std::multiplies>(this).assign(value); } -Value &Value::operator*=(const std::string &value) { return Arithmetic<std::multiplies>(this).assign(value); } -Value &Value::operator*=(const char *value) { return Arithmetic<std::multiplies>(this).assign(value); } -Value &Value::operator*=(double value) { return Arithmetic<std::multiplies>(this).assign(value); } - -/** - * Divide the object with a certain value - * @param value - * @return Value - */ -Value &Value::operator/=(const Value &value) { return Arithmetic<std::divides>(this).assign(value); } -Value &Value::operator/=(int16_t value) { return Arithmetic<std::divides>(this).assign(value); } -Value &Value::operator/=(int32_t value) { return Arithmetic<std::divides>(this).assign(value); } -Value &Value::operator/=(int64_t value) { return Arithmetic<std::divides>(this).assign(value); } -Value &Value::operator/=(bool value) { return Arithmetic<std::divides>(this).assign(value); } -Value &Value::operator/=(char value) { return Arithmetic<std::divides>(this).assign(value); } -Value &Value::operator/=(const std::string &value) { return Arithmetic<std::divides>(this).assign(value); } -Value &Value::operator/=(const char *value) { return Arithmetic<std::divides>(this).assign(value); } -Value &Value::operator/=(double value) { return Arithmetic<std::divides>(this).assign(value); } - -/** - * Divide the object with a certain value and get the rest - * Note that this does not use the Arithmetic object, because no conversion between floats is necessary - * @param value - * @return Value - */ -Value &Value::operator%=(const Value &value) { return operator=(numericValue() % value.numericValue()); } -Value &Value::operator%=(int16_t value) { return operator=(numericValue() % value); } -Value &Value::operator%=(int32_t value) { return operator=(numericValue() % value); } -Value &Value::operator%=(int64_t value) { return operator=(numericValue() % value); } -Value &Value::operator%=(bool value) { return operator=(numericValue() % value); } -Value &Value::operator%=(char value) { return operator=(numericValue() % value); } -Value &Value::operator%=(const std::string &value) { return operator=(numericValue() % atoi(value.c_str())); } -Value &Value::operator%=(const char *value) { return operator=(numericValue() % atoi(value)); } -Value &Value::operator%=(double value) { return operator=(numericValue() % (int)value); } - -/** - * Assignment operator - * @param value - * @return Value - */ -Value Value::operator+(const Value &value) { return Arithmetic<std::plus>(this).apply(value); } -Value Value::operator+(int16_t value) { return Arithmetic<std::plus>(this).apply(value); } -Value Value::operator+(int32_t value) { return Arithmetic<std::plus>(this).apply(value); } -Value Value::operator+(int64_t value) { return Arithmetic<std::plus>(this).apply(value); } -Value Value::operator+(bool value) { return Arithmetic<std::plus>(this).apply(value); } -Value Value::operator+(char value) { return Arithmetic<std::plus>(this).apply(value); } -Value Value::operator+(const std::string &value) { return Arithmetic<std::plus>(this).apply(value); } -Value Value::operator+(const char *value) { return Arithmetic<std::plus>(this).apply(value); } -Value Value::operator+(double value) { return Arithmetic<std::plus>(this).apply(value); } - -/** - * Subtraction operator - * @param value - * @return Value - */ -Value Value::operator-(const Value &value) { return Arithmetic<std::minus>(this).apply(value); } -Value Value::operator-(int16_t value) { return Arithmetic<std::minus>(this).apply(value); } -Value Value::operator-(int32_t value) { return Arithmetic<std::minus>(this).apply(value); } -Value Value::operator-(int64_t value) { return Arithmetic<std::minus>(this).apply(value); } -Value Value::operator-(bool value) { return Arithmetic<std::minus>(this).apply(value); } -Value Value::operator-(char value) { return Arithmetic<std::minus>(this).apply(value); } -Value Value::operator-(const std::string &value) { return Arithmetic<std::minus>(this).apply(value); } -Value Value::operator-(const char *value) { return Arithmetic<std::minus>(this).apply(value); } -Value Value::operator-(double value) { return Arithmetic<std::minus>(this).apply(value); } - -/** - * Multiplication operator - * @param value - * @return Value - */ -Value Value::operator*(const Value &value) { return Arithmetic<std::multiplies>(this).apply(value); } -Value Value::operator*(int16_t value) { return Arithmetic<std::multiplies>(this).apply(value); } -Value Value::operator*(int32_t value) { return Arithmetic<std::multiplies>(this).apply(value); } -Value Value::operator*(int64_t value) { return Arithmetic<std::multiplies>(this).apply(value); } -Value Value::operator*(bool value) { return Arithmetic<std::multiplies>(this).apply(value); } -Value Value::operator*(char value) { return Arithmetic<std::multiplies>(this).apply(value); } -Value Value::operator*(const std::string &value) { return Arithmetic<std::multiplies>(this).apply(value); } -Value Value::operator*(const char *value) { return Arithmetic<std::multiplies>(this).apply(value); } -Value Value::operator*(double value) { return Arithmetic<std::multiplies>(this).apply(value); } - -/** - * Division operator - * @param value - * @return Value - */ -Value Value::operator/(const Value &value) { return Arithmetic<std::divides>(this).apply(value); } -Value Value::operator/(int16_t value) { return Arithmetic<std::divides>(this).apply(value); } -Value Value::operator/(int32_t value) { return Arithmetic<std::divides>(this).apply(value); } -Value Value::operator/(int64_t value) { return Arithmetic<std::divides>(this).apply(value); } -Value Value::operator/(bool value) { return Arithmetic<std::divides>(this).apply(value); } -Value Value::operator/(char value) { return Arithmetic<std::divides>(this).apply(value); } -Value Value::operator/(const std::string &value) { return Arithmetic<std::divides>(this).apply(value); } -Value Value::operator/(const char *value) { return Arithmetic<std::divides>(this).apply(value); } -Value Value::operator/(double value) { return Arithmetic<std::divides>(this).apply(value); } - -/** - * Modulus operator - * @param value - * @return Value - */ -Value Value::operator%(const Value &value) { return Value(numericValue() % value.numericValue()); } -Value Value::operator%(int16_t value) { return Value(numericValue() % value); } -Value Value::operator%(int32_t value) { return Value(numericValue() % value); } -Value Value::operator%(int64_t value) { return Value(numericValue() % value); } -Value Value::operator%(bool value) { return Value(numericValue() % value); } -Value Value::operator%(char value) { return Value(numericValue() % value); } -Value Value::operator%(const std::string &value) { return Value(numericValue() % atoi(value.c_str())); } -Value Value::operator%(const char *value) { return Value(numericValue() % atoi(value)); } -Value Value::operator%(double value) { return Value(numericValue() % (int)value); } - -/** - * Call the function in PHP - * We have ten variants of this function, depending on the number of parameters - * This call operator is only useful when the variable represents a callable - * @param p0-p10 Parameters of the function to be called. - * @return Value - */ -Value Value::operator()() const -{ - // call with zero parameters - return exec(0, NULL); -} - -/** - * Call the function - if the variable holds a callable thing - * @param p0 The first parameter - * @return Value - */ -Value Value::operator()(Value p0) const -{ - // array of parameters - zval **params[1] = { &p0._val }; - - // call the function - return exec(1, params); -} - -/** - * Call the function - if the variable holds a callable thing - * @param p0 The first parameter - * @param p1 The second parameter - * @return Value - */ -Value Value::operator()(Value p0, Value p1) const -{ - // array of parameters - zval **params[2] = { &p0._val, &p1._val }; - - // call the function - return exec(2, params); -} - -/** - * Call the function - if the variable holds a callable thing - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @return Value - */ -Value Value::operator()(Value p0, Value p1, Value p2) const -{ - // array of parameters - zval **params[3] = { &p0._val, &p1._val, &p2._val }; - - // call the function - return exec(3, params); -} - -/** - * Call the function - if the variable holds a callable thing - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @return Value - */ -Value Value::operator()(Value p0, Value p1, Value p2, Value p3) const -{ - // array of parameters - zval **params[4] = { &p0._val, &p1._val, &p2._val, &p3._val }; - - // call the function - return exec(4, params); -} - -/** - * Call the function - if the variable holds a callable thing - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @param p4 The fifth parameter - * @return Value - */ -Value Value::operator()(Value p0, Value p1, Value p2, Value p3, Value p4) const -{ - // array of parameters - zval **params[5] = { &p0._val, &p1._val, &p2._val, &p3._val, &p4._val }; - - // call the function - return exec(5, params); -} - -/** - * Call the function - if the variable holds a callable thing - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @param p4 The fifth parameter - * @param p5 The sixth parameter - * @return Value - */ -Value Value::operator()(Value p0, Value p1, Value p2, Value p3, Value p4, Value p5) const -{ - // array of parameters - zval **params[6] = { &p0._val, &p1._val, &p2._val, &p3._val, &p4._val, &p5._val }; - - // call the function - return exec(6, params); -} - -/** - * Call the function - if the variable holds a callable thing - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @param p4 The fifth parameter - * @param p5 The sixth parameter - * @param p6 The seventh parameter - * @return Value - */ -Value Value::operator()(Value p0, Value p1, Value p2, Value p3, Value p4, Value p5, Value p6) const -{ - // array of parameters - zval **params[7] = { &p0._val, &p1._val, &p2._val, &p3._val, &p4._val, &p5._val, &p6._val }; - - // call the function - return exec(7, params); -} - -/** - * Call the function - if the variable holds a callable thing - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @param p4 The fifth parameter - * @param p5 The sixth parameter - * @param p6 The seventh parameter - * @param p7 The eighth parameter - * @return Value - */ -Value Value::operator()(Value p0, Value p1, Value p2, Value p3, Value p4, Value p5, Value p6, Value p7) const -{ - // array of parameters - zval **params[8] = { &p0._val, &p1._val, &p2._val, &p3._val, &p4._val, &p5._val, &p6._val, &p7._val }; - - // call the function - return exec(8, params); -} - -/** - * Call the function - if the variable holds a callable thing - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @param p4 The fifth parameter - * @param p5 The sixth parameter - * @param p6 The seventh parameter - * @param p7 The eighth parameter - * @param p8 The ninth parameter - * @return Value - */ -Value Value::operator()(Value p0, Value p1, Value p2, Value p3, Value p4, Value p5, Value p6, Value p7, Value p8) const -{ - // array of parameters - zval **params[9] = { &p0._val, &p1._val, &p2._val, &p3._val, &p4._val, &p5._val, &p6._val, &p7._val, &p8._val }; - - // call the function - return exec(9, params); -} - -/** - * Call the function - if the variable holds a callable thing - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @param p4 The fifth parameter - * @param p5 The sixth parameter - * @param p6 The seventh parameter - * @param p7 The eighth parameter - * @param p8 The ninth parameter - * @param p9 The tenth parameter - * @return Value - */ -Value Value::operator()(Value p0, Value p1, Value p2, Value p3, Value p4, Value p5, Value p6, Value p7, Value p8, Value p9) const -{ - // array of parameters - zval **params[10] = { &p0._val, &p1._val, &p2._val, &p3._val, &p4._val, &p5._val, &p6._val, &p7._val, &p8._val, &p9._val }; - - // call the function - return exec(10, params); -} - -/** - * Call the method - if the variable holds an object with the given method - * @param name name of the method to call - * @return Value - */ -Value Value::call(const char *name) -{ - // call with zero parameters - return exec(name, 0, NULL); -} - -/** - * Call the method - if the variable holds an object with the given method - * @param name name of the method to call - * @param p0 The first parameter - * @return Value - */ -Value Value::call(const char *name, Value p0) -{ - // array of parameters - zval **params[] = { &p0._val }; - - // call with zero parameters - return exec(name, 1, params); -} - -/** - * Call the method - if the variable holds an object with the given method - * @param name name of the method to call - * @param p0 The first parameter - * @param p1 The second parameter - * @return Value - */ -Value Value::call(const char *name, Value p0, Value p1) -{ - // array of parameters - zval **params[] = { &p0._val, &p1._val }; - - // call with zero parameters - return exec(name, 2, params); -} - -/** - * Call the method - if the variable holds an object with the given method - * @param name name of the method to call - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @return Value - */ -Value Value::call(const char *name, Value p0, Value p1, Value p2) -{ - // array of parameters - zval **params[] = { &p0._val, &p1._val, &p2._val }; - - // call with zero parameters - return exec(name, 3, params); -} - -/** - * Call the method - if the variable holds an object with the given method - * @param name name of the method to call - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @return Value - */ -Value Value::call(const char *name, Value p0, Value p1, Value p2, Value p3) -{ - // array of parameters - zval **params[] = { &p0._val, &p1._val, &p2._val, &p3._val }; - - // call with zero parameters - return exec(name, 4, params); -} - -/** - * Call the method - if the variable holds an object with the given method - * @param name name of the method to call - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @param p4 The fifth parameter - * @return Value - */ -Value Value::call(const char *name, Value p0, Value p1, Value p2, Value p3, Value p4) -{ - // array of parameters - zval **params[] = { &p0._val, &p1._val, &p2._val, &p3._val, &p4._val }; - - // call with zero parameters - return exec(name, 5, params); -} - -/** - * Call the method - if the variable holds an object with the given method - * @param name name of the method to call - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @param p4 The fifth parameter - * @param p5 The sixth parameter - * @return Value - */ -Value Value::call(const char *name, Value p0, Value p1, Value p2, Value p3, Value p4, Value p5) -{ - // array of parameters - zval **params[] = { &p0._val, &p1._val, &p2._val, &p3._val, &p4._val, &p5._val }; - - // call with zero parameters - return exec(name, 6, params); -} - -/** - * Call the method - if the variable holds an object with the given method - * @param name name of the method to call - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @param p4 The fifth parameter - * @param p5 The sixth parameter - * @param p6 The seventh parameter - * @return Value - */ -Value Value::call(const char *name, Value p0, Value p1, Value p2, Value p3, Value p4, Value p5, Value p6) -{ - // array of parameters - zval **params[] = { &p0._val, &p1._val, &p2._val, &p3._val, &p4._val, &p5._val, &p6._val }; - - // call with zero parameters - return exec(name, 7, params); -} - -/** - * Call the method - if the variable holds an object with the given method - * @param name name of the method to call - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @param p4 The fifth parameter - * @param p5 The sixth parameter - * @param p6 The seventh parameter - * @param p7 The eighth parameter - * @return Value - */ -Value Value::call(const char *name, Value p0, Value p1, Value p2, Value p3, Value p4, Value p5, Value p6, Value p7) -{ - // array of parameters - zval **params[] = { &p0._val, &p1._val, &p2._val, &p3._val, &p4._val, &p5._val, &p6._val, &p7._val }; - - // call with zero parameters - return exec(name, 8, params); -} - -/** - * Call the method - if the variable holds an object with the given method - * @param name name of the method to call - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @param p4 The fifth parameter - * @param p5 The sixth parameter - * @param p6 The seventh parameter - * @param p7 The eighth parameter - * @param p8 The ninth parameter - * @return Value - */ -Value Value::call(const char *name, Value p0, Value p1, Value p2, Value p3, Value p4, Value p5, Value p6, Value p7, Value p8) -{ - // array of parameters - zval **params[] = { &p0._val, &p1._val, &p2._val, &p3._val, &p4._val, &p5._val, &p6._val, &p7._val, &p8._val }; - - // call with zero parameters - return exec(name, 9, params); -} - -/** - * Call the method - if the variable holds an object with the given method - * @param name name of the method to call - * @param p0 The first parameter - * @param p1 The second parameter - * @param p2 The third parameter - * @param p3 The fourth parameter - * @param p4 The fifth parameter - * @param p5 The sixth parameter - * @param p6 The seventh parameter - * @param p7 The eighth parameter - * @param p8 The ninth parameter - * @param p9 The tenth parameter - * @return Value - */ -Value Value::call(const char *name, Value p0, Value p1, Value p2, Value p3, Value p4, Value p5, Value p6, Value p7, Value p8, Value p9) -{ - // array of parameters - zval **params[] = { &p0._val, &p1._val, &p2._val, &p3._val, &p4._val, &p5._val, &p6._val, &p7._val, &p8._val, &p9._val }; - - // call with zero parameters - return exec(name, 10, params); -} - -/** - * Helper function that runs the actual call - * @param object The object to call it on - * @param method The function or method to call - * @param args Number of arguments - * @param params The parameters - * @return Value - */ -static Value do_exec(zval **object, zval *method, int argc, zval ***params) -{ - // the return zval - zval *retval = nullptr; - - // we need the tsrm_ls variable - TSRMLS_FETCH(); - - // the current exception - zval *oldException = EG(exception); - - // call the function - if (call_user_function_ex(CG(function_table), object, method, &retval, argc, params, 1, NULL TSRMLS_CC) != SUCCESS) - { - // throw an exception, the function does not exist - throw Exception("Invalid call to "+Value(method).stringValue()); - - // unreachable, but let's return at least something to prevent compiler warnings - return nullptr; - } - else - { - // was an exception thrown inside the function? In that case we throw a C++ new exception - // to give the C++ code the chance to catch it - if (oldException != EG(exception) && EG(exception)) throw OrigException(EG(exception) TSRMLS_CC); - - // no (additional) exception was thrown - return retval ? Value(retval) : nullptr; - } -} - -/** - * Call function with a number of parameters - * @param argc Number of parameters - * @param argv The parameters - * @return Value - */ -Value Value::exec(int argc, zval ***params) const -{ - // call helper function - return do_exec(nullptr, _val, argc, params); -} - -/** - * Call method with a number of parameters - * @param name Name of method to call - * @param argc Number of parameters - * @param argv The parameters - * @return Value - */ -Value Value::exec(const char *name, int argc, struct _zval_struct ***params) -{ - // wrap the name in a Php::Value object to get a zval - Value method(name); - - // call helper function - return do_exec(&_val, method._val, argc, params); -} - -/** - * The type of object - * @return Type - */ -Type Value::type() const -{ - // return regular type - return (Type)Z_TYPE_P(_val); -} - -/** - * Change the internal type - * @param type - * @return Value - */ -Value &Value::setType(Type type) -{ - // skip if nothing changes - 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); - - // run the conversion - switch (type) { - case Type::Null: convert_to_null(_val); break; - case Type::Numeric: convert_to_long(_val); break; - case Type::Float: convert_to_double(_val); break; - case Type::Bool: convert_to_boolean(_val); break; - case Type::Array: convert_to_array(_val); break; - case Type::Object: convert_to_object(_val); break; - case Type::String: convert_to_string(_val); break; - case Type::Resource: throw Php::Exception("Resource types can not be handled by the PHP-CPP library"); break; - case Type::Constant: throw Php::Exception("Constant types can not be assigned to a PHP-CPP library variable"); break; - case Type::ConstantArray: throw Php::Exception("Constant types can not be assigned to a PHP-CPP library variable"); break; - case Type::Callable: throw Php::Exception("Callable types can not be assigned to a PHP-CPP library variable"); break; - } - - // done - return *this; -} - -/** - * Check if the variable holds something that is callable - * @return bool - */ -bool Value::isCallable() const -{ - // we need the tsrm_ls variable - TSRMLS_FETCH(); - - // we can not rely on the type, because strings can be callable as well - return zend_is_callable(_val, 0, NULL TSRMLS_CC); -} - -/** - * Make a clone of the type - * @return Value - */ -Value Value::clone() const -{ - // 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); -} - -/** - * Clone the zval to a different type - * @param type - * @return Value - */ -Value Value::clone(Type type) const -{ - // regular clone if nothing changes - if (this->type() == type) return clone(); - - // make a clone - return clone().setType(type); -} - -/** - * Retrieve the value as integer - * @return long - */ -int64_t Value::numericValue() const -{ - // already a long? - if (isNumeric()) return Z_LVAL_P(_val); - - // make a clone - return clone(Type::Numeric).numericValue(); -} - -/** - * Retrieve the value as boolean - * @return bool - */ -bool Value::boolValue() const -{ - // already a bool? - if (isBool()) return Z_BVAL_P(_val); - - // make a clone - return clone(Type::Bool).boolValue(); -} - -/** - * Retrieve the value as string - * @return string - */ -std::string Value::stringValue() const -{ - // already a string? - if (isString()) return std::string(Z_STRVAL_P(_val), Z_STRLEN_P(_val)); - - // make a clone - return clone(Type::String).stringValue(); -} - -/** - * Access to the raw buffer - * @return char * - */ -char *Value::buffer() const -{ - // must be a string - if (!isString()) return nullptr; - - // already a string? - return Z_STRVAL_P(_val); -} - -/** - * Reserve enough space - * @param size - * @return char* - */ -char *Value::reserve(size_t size) -{ - // must be a string - setType(Type::String); - - // is the current buffer too small? - if (Z_STRLEN_P(_val) < (int)size) - { - // is there already a buffer? - if (!Z_STRVAL_P(_val)) Z_STRVAL_P(_val) = (char *)emalloc(size+1); - - // reallocate an existing buffer - else Z_STRVAL_P(_val) = (char *)erealloc(Z_STRVAL_P(_val), size+1); - - // last byte should be zero - Z_STRVAL_P(_val)[size] = 0; - } - - // store size - Z_STRLEN_P(_val) = size; - - // done - return Z_STRVAL_P(_val); -} - -/** - * Access to the raw buffer - * @return const char * - */ -const char *Value::rawValue() const -{ - // must be a string - if (isString()) return Z_STRVAL_P(_val); - - // make a clone and return that buffer - return clone(Type::String).rawValue(); -} - -/** - * Retrieve the value as decimal - * @return double - */ -double Value::floatValue() const -{ - // already a double - if (isFloat()) return Z_DVAL_P(_val); - - // make a clone - return clone(Type::Float).floatValue(); -} - -/** - * The number of members in case of an array or object - * @return int - */ -int Value::size() const -{ - // is it an array? - if (isArray()) - { - // get the number of elements - return zend_hash_num_elements(Z_ARRVAL_P(_val)); - } - - // or an object? - else if (isObject()) - { - // the count_elements member function should be defined - if (!Z_OBJ_HT_P(_val)->count_elements) return 0; - - // create a variable to hold the result - long result; - - // we need the tsrm_ls variable - TSRMLS_FETCH(); - - // call the function - return Z_OBJ_HT_P(_val)->count_elements(_val, &result TSRMLS_CC) == SUCCESS ? result : 0; - } - - // not an array, return string size if this is a string - else if (isString()) - { - // get string size - return Z_STRLEN_P(_val); - } - - // in all other situations, we convert the variable to a string - else - { - // make a copy - Value copy(*this); - - // convert the copy to a string - copy.setType(Type::String); - - // return the string size - return copy.size(); - } -} - -/** - * Convert the object to a map with string index and Php::Value value - * @return std::map - */ -std::map<std::string,Php::Value> Value::mapValue() const -{ - // result variable - std::map<std::string,Php::Value> result; - - // iterate over the object - for (auto &iter : *this) result[iter.first.rawValue()] = iter.second; - - // done - return result; -} - -/** - * Internal helper method to retrieve an iterator - * @param begin Should the iterator start at the begin - * @return iterator - */ -ValueIterator Value::createIterator(bool begin) const -{ - // check type - if (isArray()) return ValueIterator(new HashIterator(Z_ARRVAL_P(_val), begin)); - - // get access to the hast table - if (isObject()) - { - // we need the TSRMLS_CC variable - TSRMLS_FETCH(); - - // is a special iterator method defined in the class entry? - auto *entry = zend_get_class_entry(_val TSRMLS_CC); - - // check if there is an iterator - if (entry->get_iterator) - { - // the object implements Traversable interface, we have to use a - // special iterator to user that interface too - return ValueIterator(new TraverseIterator(_val, begin TSRMLS_CC)); - } - else - { - // construct a regular iterator - return ValueIterator(new HashIterator(Z_OBJ_HT_P(_val)->get_properties(_val TSRMLS_CC), begin)); - } - } - - // invalid - return ValueIterator(new InvalidIterator()); -} - -/** - * Return an iterator for iterating over the values - * This is only meaningful for Value objects that hold an array or an object - * @return iterator - */ -ValueIterator Value::begin() const -{ - return createIterator(true); -} - -/** - * Return an iterator for iterating over the values - * This is only meaningful for Value objects that hold an array or an object - * @return iterator - */ -ValueIterator Value::end() const -{ - return createIterator(false); -} - -/** - * Does the array contain a certain index? - * @param index - * @return bool - */ -bool Value::contains(int index) const -{ - // must be an array - if (!isArray()) return false; - - // unused variable - zval **result; - - // check if this index is already in the array - return zend_hash_index_find(Z_ARRVAL_P(_val), index, (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 -{ - // calculate size - if (size < 0) size = strlen(key); - - // deal with arrays - if (isArray()) - { - // 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; - } - else if (isObject()) - { - // we need the tsrmls_cc variable - TSRMLS_FETCH(); - - // retrieve the class entry - auto *entry = zend_get_class_entry(_val TSRMLS_CC); - - // read the property (cast necessary for php 5.3) - zval *property = zend_read_property(entry, _val, (char *)key, size, 0 TSRMLS_CC); - - // check if valid - return property != nullptr; - } - else - { - // scalar variable - return false; - } -} - -/** - * 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 -{ - // must be an array - if (!isArray() && !isObject()) return Value(); - - // calculate size - if (size < 0) size = strlen(key); - - // are we in an object or an array? - if (isArray()) - { - // the result value - zval **result; - - // 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); - } - else - { - // we need the tsrm_ls variable - TSRMLS_FETCH(); - - // retrieve the class entry - auto *entry = zend_get_class_entry(_val TSRMLS_CC); - - // read the property (case necessary for php 5.3) - zval *property = zend_read_property(entry, _val, (char *)key, size, 1 TSRMLS_CC); - - // wrap in value - return Value(property); - } -} - -/** - * Set a certain property without performing any checks - * This method can be used when it is already known that the object is an array - * @param index - * @param value - * @return Value - */ -void Value::setRaw(int index, const Value &value) -{ - // 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 (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); -} - -/** - * Set a certain property - * @param index - * @param value - * @return Value - */ -void 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 **)¤t) != FAILURE) - { - // skip if nothing is going to change - if (value._val == *current) return; - } - - // must be an array - setType(Type::Array); - - // set property - setRaw(index, value); -} - -/** - * Set a certain property without running any checks - * @param key - * @param size - * @param value - */ -void Value::setRaw(const char *key, int size, const Value &value) -{ - // is this an object? - if (isObject()) - { - // if this is not a reference variable, we should detach it to implement copy on write - SEPARATE_ZVAL_IF_NOT_REF(&_val); - - // we need the tsrm_ls variable - TSRMLS_FETCH(); - - // retrieve the class entry - auto *entry = zend_get_class_entry(_val TSRMLS_CC); - - // update the property (cast necessary for php 5.3) - zend_update_property(entry, _val, (char *)key, size, value._val TSRMLS_CC); - } - else - { - // 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 (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); - } -} - -/** - * Set a certain property - * @param key - * @param size - * @param value - * @return Value - */ -void 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 **)¤t) != FAILURE) - { - // skip if nothing is going to change - if (value._val == *current) return; - } - - // this should be an object or an array - if (!isObject()) setType(Type::Array); - - // done - setRaw(key, size, value); -} - -/** - * Array access operator - * This can be used for accessing arrays - * @param index - * @return HashMember - */ -HashMember<int> Value::operator[](int index) -{ - return HashMember<int>(this, index); -} - -/** - * Array access operato - * This can be used for accessing associative arrays - * @param key - * @return HashMember - */ -HashMember<std::string> Value::operator[](const std::string &key) -{ - return HashMember<std::string>(this, key); -} - -/** - * Array access operator - * This can be used for accessing associative arrays - * @param key - * @return HashMember - */ -HashMember<std::string> Value::operator[](const char *key) -{ - return HashMember<std::string>(this, key); -} - -/** - * Retrieve the original implementation - * - * This only works for classes that were implemented using PHP-CPP, - * it returns nullptr for all other classes - * - * @return Base* - */ -Base *Value::implementation() const -{ - // must be an object - if (!isObject()) return nullptr; - - // we need the tsrm_ls variable - TSRMLS_FETCH(); - - // retrieve the mixed object that contains the base - return ObjectImpl::find(_val TSRMLS_CC)->object(); -} - -/** - * Custom output stream operator - * @param stream - * @param value - * @return ostream - */ -std::ostream &operator<<(std::ostream &stream, const Value &value) -{ - return stream << value.stringValue(); -} - -/** - * End of namespace - */ -} - |