diff options
-rw-r--r-- | include/array.h | 83 | ||||
-rw-r--r-- | include/base.h | 48 | ||||
-rw-r--r-- | include/classbase.h | 13 | ||||
-rw-r--r-- | include/forcedvalue.h | 94 | ||||
-rw-r--r-- | include/hiddenpointer.h | 20 | ||||
-rw-r--r-- | include/type.h | 26 | ||||
-rw-r--r-- | include/value.h | 14 | ||||
-rw-r--r-- | phpcpp.h | 3 | ||||
-rw-r--r-- | src/argument.cpp | 4 | ||||
-rw-r--r-- | src/base.cpp | 14 | ||||
-rw-r--r-- | src/callable.cpp | 2 | ||||
-rw-r--r-- | src/callable.h | 2 | ||||
-rw-r--r-- | src/classbase.cpp | 53 | ||||
-rw-r--r-- | src/includes.h | 3 | ||||
-rw-r--r-- | src/mixedobject.h | 10 | ||||
-rw-r--r-- | src/value.cpp | 30 |
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 ¶meters) - { - // 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; /** @@ -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); |