From 52fe0c39457421e075959179ee6b64a20b96f0d9 Mon Sep 17 00:00:00 2001 From: Emiel Bruijntjes Date: Sun, 2 Mar 2014 11:33:53 +0100 Subject: types are not a C++11 class, introduced FixedValue class that can not change type, and implemented both Object and Array to make use of that type, implemented - but not yet tested - Base::value() method --- src/argument.cpp | 4 ++-- src/base.cpp | 14 ++++++++++++++ src/callable.cpp | 2 +- src/callable.h | 2 +- src/classbase.cpp | 53 +++++++++++++++++++++++++++++++---------------------- src/includes.h | 3 +-- src/mixedobject.h | 10 ++++++++++ src/value.cpp | 30 +++++++++++++++--------------- 8 files changed, 75 insertions(+), 43 deletions(-) (limited to 'src') 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 @@ -12,6 +12,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); -- cgit v1.2.3