summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/array.h83
-rw-r--r--include/base.h48
-rw-r--r--include/classbase.h13
-rw-r--r--include/forcedvalue.h94
-rw-r--r--include/hiddenpointer.h20
-rw-r--r--include/type.h26
-rw-r--r--include/value.h14
-rw-r--r--phpcpp.h3
-rw-r--r--src/argument.cpp4
-rw-r--r--src/base.cpp14
-rw-r--r--src/callable.cpp2
-rw-r--r--src/callable.h2
-rw-r--r--src/classbase.cpp53
-rw-r--r--src/includes.h3
-rw-r--r--src/mixedobject.h10
-rw-r--r--src/value.cpp30
16 files changed, 237 insertions, 182 deletions
diff --git a/include/array.h b/include/array.h
deleted file mode 100644
index 6956fee..0000000
--- a/include/array.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * Array.h
- *
- * An array is an extension to the Value class. It extends the Value class
- * to initialize the variable as an array, instead of a null pointer
- *
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2013 Copernica BV
- */
-
-/**
- * Set up namespace
- */
-namespace Php {
-
-/**
- * Class definition
- */
-class Array : public Value
-{
-public:
- /**
- * Constructor
- */
- Array() : Value() { setType(arrayType); }
-
- /**
- * Copy constructor
- * @param array
- */
- Array(const Array &array) : Value(array) {}
-
- /**
- * Move constructor
- * @param array
- */
- Array(Array &&that) : Value(std::move(that)) {}
-
- /**
- * Copy constructor from a value object
- * @param value
- */
- Array(const Value &value) : Value(value) { setType(arrayType); }
-
- /**
- * Destructor
- */
- virtual ~Array() {}
-
- /**
- * Change the internal type of the variable
- * @param Type
- */
- virtual Value &setType(Type type) override
- {
- // only possible for arrays
- if (type != arrayType) return *this;
-
- // call base
- return Value::setType(type);
- }
-
-protected:
- /**
- * Validate the object
- * @return Value
- */
- virtual Value &validate() override
- {
- // make sure the value object is an array
- setType(arrayType);
-
- // call base
- return Value::validate();
- }
-
-};
-
-/**
- * End of namespace
- */
-}
-
diff --git a/include/base.h b/include/base.h
index df4076b..93ee66e 100644
--- a/include/base.h
+++ b/include/base.h
@@ -15,59 +15,43 @@ namespace Php {
*/
class Base
{
-public:
+protected:
/**
* Constructor
*/
Base() {}
+public:
/**
* Virtual destructor
*/
virtual ~Base() {}
/**
- * The pseudo constructor that is called from PHP after the object is constructed
- * @param parameters
+ * Convert the object to a Php::Value object (how it is used externally)
+ * @return Value
*/
- virtual void __construct(const Parameters &parameters)
- {
- // call all other possible implementations
- __construct();
- }
+ Value value() const;
/**
- * The pseudo constructor that is called from PHP after the object is constructed
- */
- virtual void __construct() {}
-
- /**
- * The pseudo destructor that is called from PHP right before the object is destructed
- */
- virtual void __destruct() {}
-
- /**
* Get access to a property by name
* @param string
- * @return Property
+ * @return Value
*/
-// Property operator[](const char *name);
-
+ Value operator[](const char *name) const
+ {
+ return value()[name];
+ }
+
/**
* Alternative way to access a property
* @param string
- * @return Property
+ * @return Value
*/
-// Property operator[](const std::string &name);
-
-protected:
- /**
- * All properties of the object
- * @var Properties
- */
-// Properties _properties;
-
-private:
+ Value operator[](const std::string &name) const
+ {
+ return value()[name];
+ }
};
diff --git a/include/classbase.h b/include/classbase.h
index ad501ea..249122a 100644
--- a/include/classbase.h
+++ b/include/classbase.h
@@ -54,14 +54,17 @@ public:
* @todo prefer move
*/
ClassBase(const ClassBase &that) :
- _name(that._name), _type(that._type), _methods(that._methods), _members(that._members) {}
+ _name(that._name), _type(that._type), _methods(that._methods),
+ _members(that._members), _entry(nullptr) {}
/**
* Move constructor
* @param that
*/
ClassBase(ClassBase &&that) :
- _type(that._type), _methods(std::move(that._methods)), _members(std::move(that._members)), _entry(that._entry)
+ _name(std::move(that._name)), _type(that._type),
+ _methods(std::move(that._methods)), _members(std::move(that._members)),
+ _entry(that._entry)
{
// other entry are invalid now (not that it is used..., class objects are
// only moved during extension setup, when the entry pointer has not yet
@@ -165,6 +168,12 @@ private:
std::string _name;
/**
+ * The comment for reflexion, with a stored pointer to ourselves
+ * @var char*
+ */
+ char *_comment = nullptr;
+
+ /**
* The class type (this can be values like Php::Abstract and Php::Final)
* @var ClassType
*/
diff --git a/include/forcedvalue.h b/include/forcedvalue.h
new file mode 100644
index 0000000..29e630a
--- /dev/null
+++ b/include/forcedvalue.h
@@ -0,0 +1,94 @@
+/**
+ * ForcedValue.h
+ *
+ * The ForcedValue is a wrapper around the value class that ensures that a
+ * certain property always has a certain type.
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2013 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+template <Type TYPE>
+class ForcedValue : public Value
+{
+public:
+ /**
+ * Constructor
+ */
+ ForcedValue() : Value() { setType(TYPE); }
+
+ /**
+ * Copy constructor
+ * @param that
+ */
+ ForcedValue(const ForcedValue<TYPE> &that) : Value(that) {}
+
+ /**
+ * Move constructor
+ * @param that
+ */
+ ForcedValue(ForcedValue<TYPE> &&that) : Value(std::move(that)) {}
+
+ /**
+ * Copy constructor from a value object
+ * @param value
+ */
+ ForcedValue(const Value &value) : Value(value) { setType(TYPE); }
+
+ /**
+ * Wrap object around zval
+ * @param zval Zval to wrap
+ * @param ref Force this to be a reference
+ */
+ ForcedValue(struct _zval_struct *zval, bool ref = false) : Value(zval, ref) { setType(TYPE); }
+
+ /**
+ * Destructor
+ */
+ virtual ~ForcedValue() {}
+
+ /**
+ * Change the internal type of the variable
+ * @param Type
+ */
+ virtual Value &setType(Type type) override
+ {
+ // call base
+ return Value::setType(TYPE);
+ }
+
+protected:
+ /**
+ * Validate the object
+ * @return Value
+ */
+ virtual Value &validate() override
+ {
+ // make sure the object has a valid type
+ setType(TYPE);
+
+ // call base
+ return Value::validate();
+ }
+
+};
+
+/**
+ * Define for arrays and objects
+ */
+using Array = ForcedValue<Type::Array>;
+using Object = ForcedValue<Type::Object>;
+
+/**
+ * End of namespace
+ */
+}
+
diff --git a/include/hiddenpointer.h b/include/hiddenpointer.h
index 93fdc7c..cf6bea0 100644
--- a/include/hiddenpointer.h
+++ b/include/hiddenpointer.h
@@ -81,6 +81,16 @@ public:
}
/**
+ * Move constructor
+ * @param that
+ */
+ HiddenPointer(HiddenPointer<Type> &&that) : _allocated(that._allocated), _buffer(that._buffer)
+ {
+ // the other object is no longer allocated
+ that._allocated = false;
+ }
+
+ /**
* Destructor
*/
virtual ~HiddenPointer()
@@ -141,6 +151,16 @@ public:
return _buffer + sizeof(Type *);
}
+ /**
+ * Derefence the pointer
+ * @return Type*
+ */
+ Type *operator->() const
+ {
+ // type is stored in front of the buffer
+ return *((Type **)_buffer);
+ }
+
private:
/**
* Buffer that holds both the pointer and the text - the text starts
diff --git a/include/type.h b/include/type.h
index 717ae90..bec0fd5 100644
--- a/include/type.h
+++ b/include/type.h
@@ -17,19 +17,19 @@ namespace Php {
* Supported types for variables
* The values are the same as the ones used internally in Zend
*/
-typedef enum _Type {
- nullType = 0,
- numericType = 1,
- floatType = 2,
- boolType = 3,
- arrayType = 4,
- objectType = 5,
- stringType = 6,
- resourceType = 7,
- constantType = 8,
- constantArrayType = 9,
- callableType = 10
-} Type;
+enum class Type : unsigned char {
+ Null = 0,
+ Numeric = 1,
+ Float = 2,
+ Bool = 3,
+ Array = 4,
+ Object = 5,
+ String = 6,
+ Resource = 7,
+ Constant = 8,
+ ConstantArray = 9,
+ Callable = 10
+};
/**
* End of namespace
diff --git a/include/value.h b/include/value.h
index d4fae0b..fc6e4fe 100644
--- a/include/value.h
+++ b/include/value.h
@@ -285,13 +285,13 @@ public:
* Check if the value is of a certain type
* @return bool
*/
- bool isNull() const { return type() == nullType; }
- bool isNumeric() const { return type() == numericType; }
- bool isBool() const { return type() == boolType; }
- bool isString() const { return type() == stringType; }
- bool isFloat() const { return type() == floatType; }
- bool isObject() const { return type() == objectType; }
- bool isArray() const { return type() == arrayType; }
+ bool isNull() const { return type() == Type::Null; }
+ bool isNumeric() const { return type() == Type::Numeric; }
+ bool isBool() const { return type() == Type::Bool; }
+ bool isString() const { return type() == Type::String; }
+ bool isFloat() const { return type() == Type::Float; }
+ bool isObject() const { return type() == Type::Object; }
+ bool isArray() const { return type() == Type::Array; }
bool isCallable() const;
/**
diff --git a/phpcpp.h b/phpcpp.h
index dae3709..daef707 100644
--- a/phpcpp.h
+++ b/phpcpp.h
@@ -26,7 +26,7 @@
*/
#include <phpcpp/type.h>
#include <phpcpp/value.h>
-#include <phpcpp/array.h>
+#include <phpcpp/forcedvalue.h>
#include <phpcpp/hiddenpointer.h>
#include <phpcpp/globals.h>
#include <phpcpp/argument.h>
@@ -36,7 +36,6 @@
#include <phpcpp/hashmember.h>
#include <phpcpp/parameters.h>
#include <phpcpp/modifiers.h>
-#include <phpcpp/properties.h>
#include <phpcpp/base.h>
#include <phpcpp/classtype.h>
#include <phpcpp/classbase.h>
diff --git a/src/argument.cpp b/src/argument.cpp
index e8e7c8a..080bf79 100644
--- a/src/argument.cpp
+++ b/src/argument.cpp
@@ -29,7 +29,7 @@ Argument::Argument(const char *name, Type type, bool required, bool byref)
_info->name = name;
_info->name_len = strlen(name);
#if PHP_VERSION_ID >= 50400
- _info->type_hint = type == arrayType || type == callableType ? type : 0;
+ _info->type_hint = (unsigned char)(type == Type::Array || type == Type::Callable ? type : Type::Null);
#endif
_info->class_name = NULL;
_info->class_name_len = 0;
@@ -57,7 +57,7 @@ Argument::Argument(const char *name, const char *classname, bool nullable, bool
_info->name = name;
_info->name_len = strlen(name);
#if PHP_VERSION_ID >= 50400
- _info->type_hint = objectType;
+ _info->type_hint = (unsigned char)Type::Object;
#endif
_info->class_name = classname;
_info->class_name_len = strlen(classname);
diff --git a/src/base.cpp b/src/base.cpp
index 60e8c2d..b5f2f86 100644
--- a/src/base.cpp
+++ b/src/base.cpp
@@ -13,6 +13,20 @@
namespace Php {
/**
+ * Convert the object to a Php::Value object (how it is used externally)
+ * @return Value
+ */
+Value Base::value() const
+{
+ // because the object is stored in a MixedObject, we know that the zend_object
+ // structure is right in front of the this pointer
+ zend_object *object = (zend_object *)this - sizeof(zend_object);
+
+ // wrap the properties table, as a reference
+ return Object(*object->properties_table, true);
+}
+
+/**
* End of namespace
*/
}
diff --git a/src/callable.cpp b/src/callable.cpp
index 5745d79..66333d5 100644
--- a/src/callable.cpp
+++ b/src/callable.cpp
@@ -99,7 +99,7 @@ void Callable::initialize(zend_internal_function_info *info, const char *classna
// number of required arguments, and the expected return type
info->required_num_args = _required;
- info->_type_hint = _return;
+ info->_type_hint = (unsigned char)_return;
// we do not support return-by-reference
info->return_reference = false;
diff --git a/src/callable.h b/src/callable.h
index d08dc42..5b32558 100644
--- a/src/callable.h
+++ b/src/callable.h
@@ -94,7 +94,7 @@ protected:
* Suggestion for the return type
* @var Type
*/
- Type _return = nullType;
+ Type _return = Type::Null;
/**
* Required number of arguments
diff --git a/src/classbase.cpp b/src/classbase.cpp
index 134164d..39c8790 100644
--- a/src/classbase.cpp
+++ b/src/classbase.cpp
@@ -62,11 +62,15 @@ static zend_object_value create_object(zend_class_entry *type TSRMLS_DC)
// retrieve the classinfo object
#if PHP_VERSION_ID >= 50400
- ClassBase *info = (ClassBase *)base->info.user.doc_comment;
+ const char *comment = base->info.user.doc_comment;
#else
- ClassBase *info = *((ClassBase **)base->doc_comment);
+ const char *comment = base->doc_comment;
#endif
+ // the first byte of the comment is an empty string (null character), but
+ // the next bytes contain a pointer to the ClassInfo class
+ ClassBase *info = *((ClassBase **)(comment + 1));
+
// store the class
object->php.ce = type;
@@ -76,6 +80,7 @@ static zend_object_value create_object(zend_class_entry *type TSRMLS_DC)
// initialize the hash table
zend_hash_init(object->php.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+
// initialize the properties
#if PHP_VERSION_ID < 50399
@@ -108,6 +113,11 @@ ClassBase::~ClassBase()
{
// destruct the entries
if (_entries) delete[] _entries;
+
+ // php 5.3 deallocated the doc_comment by iself
+#if PHP_VERSION_ID >= 50400
+ if (_comment) free(_comment);
+#endif
}
/**
@@ -176,30 +186,29 @@ void ClassBase::initialize(const std::string &prefix)
// register the class
_entry = zend_register_internal_class(&entry TSRMLS_CC);
-
+
+ // allocate doc comment to contain an empty string + a hidden pointer
+ if (!_comment)
+ {
+ // allocate now
+ _comment = (char *)malloc(1 + sizeof(ClassBase *));
+
+ // empty string on first position
+ _comment[0] = '\0';
+
+ // this pointer has to be copied to temporary pointer, as &this causes compiler error
+ ClassBase *base = this;
+
+ // copy the 'this' pointer to the doc-comment
+ memcpy(_comment+1, &base, sizeof(ClassBase *));
+ }
+
// store pointer to the class in the unused doc_comment member
#if PHP_VERSION_ID >= 50400
- _entry->info.user.doc_comment = (const char *)this;
+ _entry->info.user.doc_comment = _comment;
#else
- /**
- * PHP 5.3 will free the doc_comment pointer if it
- * is not NULL, which will result in the classinfo
- * object being freed without being destructed
- * properly, leading to segfaults when the destruct
- * is called at a later stage (during module_shutdown).
- *
- * To prevent this we create an extra pointer that
- * points to our this pointer. We do *not* free this
- * pointer ourselves, because PHP does this. This
- * way it does not free the classinfo.
- */
- char **wrapper = (char**)malloc(sizeof(char**));
-
- // have the wrapper point to us
- *wrapper = (char *)this;
-
// and store the wrapper inside the comment
- _entry->doc_comment = (char *)wrapper;
+ _entry->doc_comment = _comment;
#endif
// set access types flags for class
diff --git a/src/includes.h b/src/includes.h
index 53dd354..c15ae93 100644
--- a/src/includes.h
+++ b/src/includes.h
@@ -47,7 +47,7 @@
*/
#include "../include/type.h"
#include "../include/value.h"
-#include "../include/array.h"
+#include "../include/forcedvalue.h"
#include "../include/hiddenpointer.h"
#include "../include/globals.h"
#include "../include/argument.h"
@@ -57,7 +57,6 @@
#include "../include/hashmember.h"
#include "../include/parameters.h"
#include "../include/modifiers.h"
-#include "../include/properties.h"
#include "../include/base.h"
#include "../include/classtype.h"
#include "../include/classbase.h"
diff --git a/src/mixedobject.h b/src/mixedobject.h
index 55a27ec..4db74da 100644
--- a/src/mixedobject.h
+++ b/src/mixedobject.h
@@ -17,7 +17,17 @@ namespace Php {
*/
struct MixedObject
{
+ /**
+ * The actual object is the first member, so that casting
+ * the MixedObject to a zend_object will also result in a valid pointer
+ * @var zend_object
+ */
zend_object php;
+
+ /**
+ * Pointer to the C++ implementation
+ * @var Base
+ */
Base *cpp;
};
diff --git a/src/value.cpp b/src/value.cpp
index 8827e6e..644e60c 100644
--- a/src/value.cpp
+++ b/src/value.cpp
@@ -1172,13 +1172,13 @@ Value &Value::setType(Type type)
// run the conversion
switch (type) {
- case nullType: convert_to_null(_val); break;
- case numericType: convert_to_long(_val); break;
- case floatType: convert_to_double(_val); break;
- case boolType: convert_to_boolean(_val); break;
- case arrayType: convert_to_array(_val); break;
- case objectType: convert_to_object(_val); break;
- case stringType: convert_to_string(_val); break;
+ 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;
}
// done
@@ -1241,7 +1241,7 @@ long Value::numericValue() const
if (isNumeric()) return Z_LVAL_P(_val);
// make a clone
- return clone(numericType).numericValue();
+ return clone(Type::Numeric).numericValue();
}
/**
@@ -1254,7 +1254,7 @@ bool Value::boolValue() const
if (isBool()) return Z_BVAL_P(_val);
// make a clone
- return clone(boolType).boolValue();
+ return clone(Type::Bool).boolValue();
}
/**
@@ -1267,7 +1267,7 @@ std::string Value::stringValue() const
if (isString()) return std::string(Z_STRVAL_P(_val), Z_STRLEN_P(_val));
// make a clone
- return clone(stringType).stringValue();
+ return clone(Type::String).stringValue();
}
/**
@@ -1280,7 +1280,7 @@ const char *Value::rawValue() const
if (isString()) return Z_STRVAL_P(_val);
// make a clone
- return clone(stringType).rawValue();
+ return clone(Type::String).rawValue();
}
/**
@@ -1293,7 +1293,7 @@ double Value::floatValue() const
if (isFloat()) return Z_DVAL_P(_val);
// make a clone
- return clone(floatType).floatValue();
+ return clone(Type::Float).floatValue();
}
/**
@@ -1336,7 +1336,7 @@ int Value::size() const
Value copy(*this);
// convert the copy to a string
- copy.setType(stringType);
+ copy.setType(Type::String);
// return the string size
return copy.size();
@@ -1476,7 +1476,7 @@ const Value &Value::set(int index, const Value &value)
}
// must be an array
- setType(arrayType);
+ setType(Type::Array);
// if this is not a reference variable, we should detach it to implement copy on write
SEPARATE_ZVAL_IF_NOT_REF(&_val);
@@ -1528,7 +1528,7 @@ const Value &Value::set(const char *key, int size, const Value &value)
else
{
// must be an array
- setType(arrayType);
+ setType(Type::Array);
// if this is not a reference variable, we should detach it to implement copy on write
SEPARATE_ZVAL_IF_NOT_REF(&_val);