summaryrefslogtreecommitdiff
path: root/src/value.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/value.cpp')
-rw-r--r--src/value.cpp405
1 files changed, 405 insertions, 0 deletions
diff --git a/src/value.cpp b/src/value.cpp
new file mode 100644
index 0000000..a682dca
--- /dev/null
+++ b/src/value.cpp
@@ -0,0 +1,405 @@
+/**
+ * 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 Copernica BV
+ */
+#include "includes.h"
+
+/**
+ * Set up namespace
+ */
+namespace PhpCpp {
+
+/**
+ * Constructor (value = NULL)
+ */
+Value::Value()
+{
+ // create a null zval
+ MAKE_STD_ZVAL(_val);
+ ZVAL_NULL(_val);
+}
+
+/**
+ * Constructor based on integer value
+ * @param value
+ */
+Value::Value(int 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 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 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::Value(struct _zval_struct *zval)
+{
+ // just copy the zval into this object
+ _val = zval;
+
+ // we see ourselves as reference too
+ ZVAL_ADDREF_P(_val);
+}
+
+/**
+ * Copy constructor
+ * @param value
+ */
+Value::Value(const Value &that)
+{
+ // just copy the zval, and the refcounter
+ _val = that._val;
+
+ // and we have one more reference
+ ZVAL_ADDREF_P(_val);
+}
+
+/**
+ * Destructor
+ */
+Value::~Value()
+{
+ // destruct the zval (this function will decrement the reference counter,
+ // and only destruct if there are no other references left)
+ zval_ptr_dtor(_val);
+}
+
+/**
+ * Assignment operator
+ * @param value
+ * @return Value
+ */
+Value &Value::operator=(const Value &value)
+{
+ // skip self assignment
+ if (this == &value) return *this;
+
+ // 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 = that._val;
+
+ // and we have one more reference
+ ZVAL_ADDREF_P(_val);
+
+ // done
+ return *this;
+}
+
+/**
+ * Assignment operator
+ * @param value
+ * @return Value
+ */
+Value &Value::operator=(int 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
+ SEPARATE_ZVAL_IF_NOT_REF(&_val);
+
+ // deallocate current zval (without cleaning the zval structure)
+ zval_dtor(_val);
+
+ // set new value
+ ZVAL_BOOL(_val, value);
+
+ // done
+ return *this;
+}
+
+/**
+ * Assignment operator
+ * @param value
+ * @return Value
+ */
+Value &Value::operator=(const std::string &value)
+{
+ // if this is not a reference variable, we should detach it to implement copy on write
+ 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);
+
+ // 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
+ SEPARATE_ZVAL_IF_NOT_REF(&_val);
+
+ // deallocate current zval (without cleaning the zval structure)
+ zval_dtor(_val);
+
+ // set new value
+ ZVAL_DOUBLE(_val, value);
+
+ // done
+ return *this;
+}
+
+/**
+ * The type of object
+ * @return Type
+ */
+Type Value::type()
+{
+ return (Type)Z_TYPE_P(_val);
+}
+
+/**
+ * Change the internal type
+ * @param type
+ */
+void Value::setType(Type type)
+{
+ // skip if nothing changes
+ if (this->type() == type) return;
+
+ // run the conversion
+ switch (type) {
+ case nullType: convert_to_null(_val); break;
+ case intType: convert_to_long(_val); break;
+ case decimalType: convert_to_double(_val); break;
+ case boolType: convert_to_bool(_val); break;
+ case arrayType: convert_to_array(_val); break;
+ case objectType: convert_to_object(_val); break;
+ case stringType: convert_to_string(_val); break;
+ case resourceType: convert_to_resource(_val); break;
+ case constantType: convert_to_constant(_val); break;
+ case constantArrayType: convert_to_constant_array(_val); break;
+ case callableType: convert_to_callable(_val); break;
+ }
+}
+
+/**
+ * Is this a NULL value?
+ * @return bool
+ */
+bool Value::isNull()
+{
+ return Z_TYPE_P(_val) == IS_NULL;
+}
+
+/**
+ * Is this an integer value?
+ * @return bool
+ */
+bool Value::isInt()
+{
+ return Z_TYPE_P(_val) == IS_LONG;
+}
+
+/**
+ * Is this a boolean value?
+ * @return bool
+ */
+bool Value::isBool()
+{
+ return Z_TYPE_P(_val) == IS_BOOL;
+}
+
+/**
+ * Is this a string value?
+ * @return bool
+ */
+bool Value::isString()
+{
+ return Z_TYPE_P(_val) == IS_STRING;
+}
+
+/**
+ * Is this a decimal value?
+ * @return bool
+ */
+bool Value::isDecimal()
+{
+ return Z_TYPE_P(_val) == IS_DOUBLE;
+}
+
+/**
+ * Is this an object value?
+ * @return bool
+ */
+bool Value::isObject()
+{
+ return Z_TYPE_P(_val) == IS_OBJECT;
+}
+
+/**
+ * Is this an array value?
+ * @return bool
+ */
+bool Value::isArray()
+{
+ return Z_TYPE_P(_val) == IS_ARRAY;
+}
+
+/**
+ * Retrieve the value as integer
+ * @return int
+ */
+int Value::intValue()
+{
+ // already an int?
+ if (isInt()) return Z_LVAL_P(_val);
+
+ // make a copy
+ Value copy(*this);
+
+ // convert the copy to an int
+ copy.setType(intType);
+
+ // return the int value
+ return copy.intValue();
+}
+
+/**
+ * Retrieve the value as boolean
+ * @return bool
+ */
+bool Value::boolValue()
+{
+ // already a bool?
+ if (isBool()) return Z_BVAL_P(_val);
+
+ // make a copy
+ Value copy(*this);
+
+ // convert the copy to an int
+ copy.setType(boolType);
+
+ // return the int value
+ return copy.intValue();
+}
+
+/**
+ * Retrieve the value as string
+ * @return string
+ */
+std::string Value::stringValue()
+{
+ // already a string?
+ if (isString()) return std::string(Z_STRVAL_P(_val), Z_STRLEN_T(_val));
+
+ // make a copy
+ Value copy(*this);
+
+ // convert the copy to an string
+ copy.setType(stringType);
+
+ // return the string value
+ return copy.stringValue();
+}
+
+/**
+ * Retrieve the value as decimal
+ * @return double
+ */
+double Value::decimalValue()
+{
+ // already a double
+ if (isDecimal()) return Z_DVAL_P(_val);
+
+ // make a copy
+ Value copy(*this);
+
+ // convert the copy to an double
+ copy.setType(decimalType);
+
+ // return the decimal value
+ return copy.decimalValue();
+}
+
+/**
+ * End of namespace
+ */
+}
+