From 05a91c74638fe6cffa4e8917528fc803d7a3396b Mon Sep 17 00:00:00 2001 From: andot Date: Sun, 13 Jul 2014 06:43:54 +0800 Subject: [PATCH 1/2] Add returning reference support The old implementation of PHP-CPP do not support returning reference. but now it can. --- include/class.h | 55 ++++++++++++++++-------------- include/classbase.h | 29 +++++++++------- include/namespace.h | 9 ++--- zend/callable.cpp | 83 +++++++++++++++++++++++++++++++++++++++------ zend/callable.h | 22 +++++++++++- zend/classbase.cpp | 29 +++++++++------- zend/classimpl.h | 29 +++++++++------- zend/function.h | 10 +++--- zend/method.h | 27 ++++++++------- zend/namespace.cpp | 20 ++++++----- 10 files changed, 208 insertions(+), 105 deletions(-) diff --git a/include/class.h b/include/class.h index cffc7bd3..421881b8 100644 --- a/include/class.h +++ b/include/class.h @@ -69,24 +69,25 @@ class Class : private ClassBase * @param method The actual method * @param flags Optional flags * @param args Argument descriptions + * @param return_ref Return reference or not * @return Class Same object to allow chaining */ - Class &method(const char *name, void (T::*method)(), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); return *this; } - Class &method(const char *name, void (T::*method)(Parameters ¶ms), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); return *this; } - Class &method(const char *name, Value (T::*method)(), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); return *this; } - Class &method(const char *name, Value (T::*method)(Parameters ¶ms), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); return *this; } - Class &method(const char *name, void (T::*method)(), const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); return *this; } - Class &method(const char *name, void (T::*method)(Parameters ¶ms), const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); return *this; } - Class &method(const char *name, Value (T::*method)(), const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); return *this; } - Class &method(const char *name, Value (T::*method)(Parameters ¶ms), const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); return *this; } - Class &method(const char *name, void (T::*method)() const, int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); return *this; } - Class &method(const char *name, void (T::*method)(Parameters ¶ms) const, int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); return *this; } - Class &method(const char *name, Value (T::*method)() const, int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); return *this; } - Class &method(const char *name, Value (T::*method)(Parameters ¶ms) const, int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); return *this; } - Class &method(const char *name, void (T::*method)() const, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); return *this; } - Class &method(const char *name, void (T::*method)(Parameters ¶ms) const, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); return *this; } - Class &method(const char *name, Value (T::*method)() const, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); return *this; } - Class &method(const char *name, Value (T::*method)(Parameters ¶ms) const, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); return *this; } + Class &method(const char *name, void (T::*method)(), int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), flags, args, return_ref); return *this; } + Class &method(const char *name, void (T::*method)(Parameters ¶ms), int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), flags, args, return_ref); return *this; } + Class &method(const char *name, Value (T::*method)(), int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), flags, args, return_ref); return *this; } + Class &method(const char *name, Value (T::*method)(Parameters ¶ms), int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), flags, args, return_ref); return *this; } + Class &method(const char *name, void (T::*method)(), const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), Public, args, return_ref); return *this; } + Class &method(const char *name, void (T::*method)(Parameters ¶ms), const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), Public, args, return_ref); return *this; } + Class &method(const char *name, Value (T::*method)(), const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), Public, args, return_ref); return *this; } + Class &method(const char *name, Value (T::*method)(Parameters ¶ms), const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), Public, args, return_ref); return *this; } + Class &method(const char *name, void (T::*method)() const, int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), flags, args, return_ref); return *this; } + Class &method(const char *name, void (T::*method)(Parameters ¶ms) const, int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), flags, args, return_ref); return *this; } + Class &method(const char *name, Value (T::*method)() const, int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), flags, args, return_ref); return *this; } + Class &method(const char *name, Value (T::*method)(Parameters ¶ms) const, int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), flags, args, return_ref); return *this; } + Class &method(const char *name, void (T::*method)() const, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), Public, args, return_ref); return *this; } + Class &method(const char *name, void (T::*method)(Parameters ¶ms) const, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), Public, args, return_ref); return *this; } + Class &method(const char *name, Value (T::*method)() const, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), Public, args, return_ref); return *this; } + Class &method(const char *name, Value (T::*method)(Parameters ¶ms) const, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, static_cast(method), Public, args, return_ref); return *this; } /** * Add a static method to a class @@ -102,16 +103,17 @@ class Class : private ClassBase * @param method The actual method * @param flags Optional flags * @param args Argument descriptions + * @param return_ref Return reference or not * @return Class Same object to allow chaining */ - Class &method(const char *name, const native_callback_0 &function, int flags, const Arguments &args = {}) { ClassBase::method(name, function, flags, args); return *this; } - Class &method(const char *name, const native_callback_1 &function, int flags, const Arguments &args = {}) { ClassBase::method(name, function, flags, args); return *this; } - Class &method(const char *name, const native_callback_2 &function, int flags, const Arguments &args = {}) { ClassBase::method(name, function, flags, args); return *this; } - Class &method(const char *name, const native_callback_3 &function, int flags, const Arguments &args = {}) { ClassBase::method(name, function, flags, args); return *this; } - Class &method(const char *name, const native_callback_0 &function, const Arguments &args = {}) { ClassBase::method(name, function, Public, args); return *this; } - Class &method(const char *name, const native_callback_1 &function, const Arguments &args = {}) { ClassBase::method(name, function, Public, args); return *this; } - Class &method(const char *name, const native_callback_2 &function, const Arguments &args = {}) { ClassBase::method(name, function, Public, args); return *this; } - Class &method(const char *name, const native_callback_3 &function, const Arguments &args = {}) { ClassBase::method(name, function, Public, args); return *this; } + Class &method(const char *name, const native_callback_0 &function, int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, function, flags, args, return_ref); return *this; } + Class &method(const char *name, const native_callback_1 &function, int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, function, flags, args, return_ref); return *this; } + Class &method(const char *name, const native_callback_2 &function, int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, function, flags, args, return_ref); return *this; } + Class &method(const char *name, const native_callback_3 &function, int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, function, flags, args, return_ref); return *this; } + Class &method(const char *name, const native_callback_0 &function, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, function, Public, args, return_ref); return *this; } + Class &method(const char *name, const native_callback_1 &function, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, function, Public, args, return_ref); return *this; } + Class &method(const char *name, const native_callback_2 &function, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, function, Public, args, return_ref); return *this; } + Class &method(const char *name, const native_callback_3 &function, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, function, Public, args, return_ref); return *this; } /** * Add an abstract method to the class @@ -123,10 +125,11 @@ class Class : private ClassBase * @param name Name of the method * @param flags Optional flags * @param args Argument descriptions + * @param return_ref Return reference or not * @return Class Same object to allow chaining */ - Class &method(const char *name, int flags, const Arguments &args = {}) { ClassBase::method(name, flags | Abstract, args); return *this; } - Class &method(const char *name, const Arguments &args = {}) { ClassBase::method(name, Public | Abstract, args); return *this; } + Class &method(const char *name, int flags, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, flags | Abstract, args, return_ref); return *this; } + Class &method(const char *name, const Arguments &args = {}, bool return_ref = false) { ClassBase::method(name, Public | Abstract, args, return_ref); return *this; } /** * Add a property to the class diff --git a/include/classbase.h b/include/classbase.h index 9f0bac3c..2928891a 100644 --- a/include/classbase.h +++ b/include/classbase.h @@ -183,15 +183,16 @@ class ClassBase * @param method The actual method * @param flags Optional flags * @param args Description of the supported arguments + * @param return_ref Return reference or not */ - void method(const char *name, const method_callback_0 &method, int flags=0, const Arguments &args = {}); - void method(const char *name, const method_callback_1 &method, int flags=0, const Arguments &args = {}); - void method(const char *name, const method_callback_2 &method, int flags=0, const Arguments &args = {}); - void method(const char *name, const method_callback_3 &method, int flags=0, const Arguments &args = {}); - void method(const char *name, const method_callback_4 &method, int flags=0, const Arguments &args = {}); - void method(const char *name, const method_callback_5 &method, int flags=0, const Arguments &args = {}); - void method(const char *name, const method_callback_6 &method, int flags=0, const Arguments &args = {}); - void method(const char *name, const method_callback_7 &method, int flags=0, const Arguments &args = {}); + void method(const char *name, const method_callback_0 &method, int flags=0, const Arguments &args = {}, bool return_ref = false); + void method(const char *name, const method_callback_1 &method, int flags=0, const Arguments &args = {}, bool return_ref = false); + void method(const char *name, const method_callback_2 &method, int flags=0, const Arguments &args = {}, bool return_ref = false); + void method(const char *name, const method_callback_3 &method, int flags=0, const Arguments &args = {}, bool return_ref = false); + void method(const char *name, const method_callback_4 &method, int flags=0, const Arguments &args = {}, bool return_ref = false); + void method(const char *name, const method_callback_5 &method, int flags=0, const Arguments &args = {}, bool return_ref = false); + void method(const char *name, const method_callback_6 &method, int flags=0, const Arguments &args = {}, bool return_ref = false); + void method(const char *name, const method_callback_7 &method, int flags=0, const Arguments &args = {}, bool return_ref = false); /** * Add a static method to the class @@ -204,11 +205,12 @@ class ClassBase * @param method The actual method * @param flags Optional flags * @param args Description of the supported arguments + * @param return_ref Return reference or not */ - void method(const char *name, const native_callback_0 &method, int flags=0, const Arguments &args = {}); - void method(const char *name, const native_callback_1 &method, int flags=0, const Arguments &args = {}); - void method(const char *name, const native_callback_2 &method, int flags=0, const Arguments &args = {}); - void method(const char *name, const native_callback_3 &method, int flags=0, const Arguments &args = {}); + void method(const char *name, const native_callback_0 &method, int flags=0, const Arguments &args = {}, bool return_ref = false); + void method(const char *name, const native_callback_1 &method, int flags=0, const Arguments &args = {}, bool return_ref = false); + void method(const char *name, const native_callback_2 &method, int flags=0, const Arguments &args = {}, bool return_ref = false); + void method(const char *name, const native_callback_3 &method, int flags=0, const Arguments &args = {}, bool return_ref = false); /** * Add an abstract method to the class @@ -216,8 +218,9 @@ class ClassBase * @param name Name of the method * @param flags Optional flags (like public or protected) * @param args Description of the supported arguments + * @param return_ref Return reference or not */ - void method(const char *name, int flags=0, const Arguments &args = {}); + void method(const char *name, int flags=0, const Arguments &args = {}, bool return_ref = false); /** * Add a property to the class diff --git a/include/namespace.h b/include/namespace.h index e7138503..fb85eb0e 100644 --- a/include/namespace.h +++ b/include/namespace.h @@ -85,12 +85,13 @@ class Namespace * @param name Name of the function * @param function The function to add * @param arguments Optional argument specification + * @param return_ref Return reference or not * @return Namespace Same object to allow chaining */ - Namespace &add(const char *name, const native_callback_0 &function, const Arguments &arguments = {}); - Namespace &add(const char *name, const native_callback_1 &function, const Arguments &arguments = {}); - Namespace &add(const char *name, const native_callback_2 &function, const Arguments &arguments = {}); - Namespace &add(const char *name, const native_callback_3 &function, const Arguments &arguments = {}); + Namespace &add(const char *name, const native_callback_0 &function, const Arguments &arguments = {}, bool return_ref = false); + Namespace &add(const char *name, const native_callback_1 &function, const Arguments &arguments = {}, bool return_ref = false); + Namespace &add(const char *name, const native_callback_2 &function, const Arguments &arguments = {}, bool return_ref = false); + Namespace &add(const char *name, const native_callback_3 &function, const Arguments &arguments = {}, bool return_ref = false); /** * Add a native class to the namespace by moving it diff --git a/zend/callable.cpp b/zend/callable.cpp index a85ab725..81b76502 100644 --- a/zend/callable.cpp +++ b/zend/callable.cpp @@ -51,12 +51,12 @@ void Callable::invoke(INTERNAL_FUNCTION_PARAMETERS) { // get the result Value result(callable->invoke(params)); - + // detach the zval (we don't want it to be destructed) zval *val = result.detach(); - + // @todo php 5.6 has a RETVAL_ZVAL_FAST macro that can be used instead (and is faster) - + // return a full copy of the zval, and do not destruct it RETVAL_ZVAL(val, 1, 0); } @@ -68,6 +68,65 @@ void Callable::invoke(INTERNAL_FUNCTION_PARAMETERS) } } +/** + * Function that is called by the Zend engine every time that a function gets called + * @param ht + * @param return_value + * @param return_value_ptr + * @param this_ptr + * @param return_value_used + * @param tsrm_ls + * @return integer + */ +void Callable::invoke_return_ref(INTERNAL_FUNCTION_PARAMETERS) +{ + // find the function name + const char *name = get_active_function_name(TSRMLS_C); + + // uncover the hidden pointer inside the function name + Callable *callable = HiddenPointer(name); + + // check if sufficient parameters were passed (for some reason this check + // is not done by Zend, so we do it here ourselves) + if (ZEND_NUM_ARGS() < callable->_required) + { + // PHP itself only generates a warning when this happens, so we do the same too + Php::warning << name << "() expects at least " << callable->_required << " parameters, " << ZEND_NUM_ARGS() << " given" << std::flush; + + // and we return null + RETURN_NULL(); + } + else + { + // construct parameters + ParametersImpl params(this_ptr, ZEND_NUM_ARGS() TSRMLS_CC); + + // the function could throw an exception + try + { + // get the result + Value result(callable->invoke(params)); + + // detach the zval (we don't want it to be destructed) + zval *val = result.detach(); + + // get the reference of the result + SEPARATE_ZVAL_TO_MAKE_IS_REF(&val); + + // destroy the old return value + zval_ptr_dtor(return_value_ptr); + + // return the reference + *return_value_ptr = val; + } + catch (Exception &exception) + { + // process the exception + process(exception TSRMLS_CC); + } + } +} + /** * Fill a function entry * @@ -82,7 +141,12 @@ void Callable::initialize(zend_function_entry *entry, const char *classname, int { // fill the members of the entity, and hide a pointer to the current object in the name entry->fname = (const char *)_ptr; - entry->handler = &Callable::invoke; + if (_return_ref) { + entry->handler = &Callable::invoke_return_ref; + } + else { + entry->handler = &Callable::invoke; + } entry->arg_info = _argv; entry->num_args = _argc; entry->flags = flags; @@ -103,9 +167,8 @@ void Callable::initialize(zend_arg_info *info, const char *classname) const // later it is casted to a zend_internal_function object auto *finfo = (zend_internal_function_info *)info; - // fill in all the members, note that return reference is false by default, - // because we do not support returning references in PHP-CPP, although Zend - // engine allows it. Inside the name we hide a pointer to the current object + // fill in all the members. + // Inside the name we hide a pointer to the current object finfo->_name = _ptr; finfo->_name_len = ::strlen(_ptr); finfo->_class_name = classname; @@ -114,8 +177,8 @@ void Callable::initialize(zend_arg_info *info, const char *classname) const finfo->required_num_args = _required; finfo->_type_hint = (unsigned char)_return; - // we do not support return-by-reference - finfo->return_reference = false; + // we support return-by-reference + finfo->return_reference = _return_ref; # if PHP_VERSION_ID >= 50600 // since php 5.6 there are _allow_null and _is_variadic properties. It's @@ -138,7 +201,7 @@ void Callable::initialize(zend_arg_info *info, const char *classname) const info->array_type_hint = false; info->allow_null = false; info->pass_by_reference = false; - info->return_reference = false; + info->return_reference = _return_ref; info->required_num_args = _required; #endif } diff --git a/zend/callable.h b/zend/callable.h index 9958a2a4..7045e5d0 100644 --- a/zend/callable.h +++ b/zend/callable.h @@ -23,8 +23,9 @@ class Callable * Constructor * @param name Function or method name * @param arguments Information about the arguments + * @param return_ref Return reference or not */ - Callable(const char *name, const Arguments &arguments = {}) : _ptr(this, name) + Callable(const char *name, const Arguments &arguments = {}, bool return_ref = false) : _ptr(this, name), _return_ref(return_ref) { // construct vector for arguments _argc = arguments.size(); @@ -52,6 +53,7 @@ class Callable Callable(const Callable &that) : _ptr(that._ptr), _return(that._return), + _return_ref(that._return_ref), _required(that._required), _argc(that._argc), _argv(nullptr) {} @@ -63,6 +65,7 @@ class Callable Callable(Callable &&that) : _ptr(std::move(that._ptr)), _return(that._return), + _return_ref(that._return_ref), _required(that._required), _argc(that._argc), _argv(that._argv) @@ -117,6 +120,12 @@ class Callable */ Type _return = Type::Null; + /** + * Return reference or value + * @var bool + */ + bool _return_ref = false; + /** * Required number of arguments * @var integer @@ -194,6 +203,17 @@ class Callable */ static void invoke(INTERNAL_FUNCTION_PARAMETERS); + /** + * Function that is called by the Zend engine every time that a function gets called + * @param ht + * @param return_value + * @param return_value_ptr + * @param this_ptr + * @param return_value_used + * @param tsrm_ls + * @return integer + */ + static void invoke_return_ref(INTERNAL_FUNCTION_PARAMETERS); }; /** diff --git a/zend/classbase.cpp b/zend/classbase.cpp index 18d81d56..9b8f7336 100644 --- a/zend/classbase.cpp +++ b/zend/classbase.cpp @@ -53,15 +53,16 @@ void ClassBase::notImplemented() * @param method The actual method * @param flags Optional flags * @param args Description of the supported arguments + * @param return_ref Return reference or not */ -void ClassBase::method(const char *name, const method_callback_0 &callback, int flags, const Arguments &args) { _impl->method(name, callback, flags, args); } -void ClassBase::method(const char *name, const method_callback_1 &callback, int flags, const Arguments &args) { _impl->method(name, callback, flags, args); } -void ClassBase::method(const char *name, const method_callback_2 &callback, int flags, const Arguments &args) { _impl->method(name, callback, flags, args); } -void ClassBase::method(const char *name, const method_callback_3 &callback, int flags, const Arguments &args) { _impl->method(name, callback, flags, args); } -void ClassBase::method(const char *name, const method_callback_4 &callback, int flags, const Arguments &args) { _impl->method(name, callback, flags, args); } -void ClassBase::method(const char *name, const method_callback_5 &callback, int flags, const Arguments &args) { _impl->method(name, callback, flags, args); } -void ClassBase::method(const char *name, const method_callback_6 &callback, int flags, const Arguments &args) { _impl->method(name, callback, flags, args); } -void ClassBase::method(const char *name, const method_callback_7 &callback, int flags, const Arguments &args) { _impl->method(name, callback, flags, args); } +void ClassBase::method(const char *name, const method_callback_0 &callback, int flags, const Arguments &args, bool return_ref) { _impl->method(name, callback, flags, args, return_ref); } +void ClassBase::method(const char *name, const method_callback_1 &callback, int flags, const Arguments &args, bool return_ref) { _impl->method(name, callback, flags, args, return_ref); } +void ClassBase::method(const char *name, const method_callback_2 &callback, int flags, const Arguments &args, bool return_ref) { _impl->method(name, callback, flags, args, return_ref); } +void ClassBase::method(const char *name, const method_callback_3 &callback, int flags, const Arguments &args, bool return_ref) { _impl->method(name, callback, flags, args, return_ref); } +void ClassBase::method(const char *name, const method_callback_4 &callback, int flags, const Arguments &args, bool return_ref) { _impl->method(name, callback, flags, args, return_ref); } +void ClassBase::method(const char *name, const method_callback_5 &callback, int flags, const Arguments &args, bool return_ref) { _impl->method(name, callback, flags, args, return_ref); } +void ClassBase::method(const char *name, const method_callback_6 &callback, int flags, const Arguments &args, bool return_ref) { _impl->method(name, callback, flags, args, return_ref); } +void ClassBase::method(const char *name, const method_callback_7 &callback, int flags, const Arguments &args, bool return_ref) { _impl->method(name, callback, flags, args, return_ref); } /** * Add a static method to the class @@ -69,19 +70,21 @@ void ClassBase::method(const char *name, const method_callback_7 &callback, int * @param method The actual method * @param flags Optional flags * @param args Description of the supported arguments + * @param return_ref Return reference or not */ -void ClassBase::method(const char *name, const native_callback_0 &method, int flags, const Arguments &args) { _impl->method(name, method, flags, args); } -void ClassBase::method(const char *name, const native_callback_1 &method, int flags, const Arguments &args) { _impl->method(name, method, flags, args); } -void ClassBase::method(const char *name, const native_callback_2 &method, int flags, const Arguments &args) { _impl->method(name, method, flags, args); } -void ClassBase::method(const char *name, const native_callback_3 &method, int flags, const Arguments &args) { _impl->method(name, method, flags, args); } +void ClassBase::method(const char *name, const native_callback_0 &method, int flags, const Arguments &args, bool return_ref) { _impl->method(name, method, flags, args, return_ref); } +void ClassBase::method(const char *name, const native_callback_1 &method, int flags, const Arguments &args, bool return_ref) { _impl->method(name, method, flags, args, return_ref); } +void ClassBase::method(const char *name, const native_callback_2 &method, int flags, const Arguments &args, bool return_ref) { _impl->method(name, method, flags, args, return_ref); } +void ClassBase::method(const char *name, const native_callback_3 &method, int flags, const Arguments &args, bool return_ref) { _impl->method(name, method, flags, args, return_ref); } /** * Add an abstract method to the class * @param name Name of the method * @param flags Optional flags (like public or protected) * @param args Description of the supported arguments + * @param return_ref Return reference or not */ -void ClassBase::method(const char *name, int flags, const Arguments &args) { _impl->method(name, flags, args); } +void ClassBase::method(const char *name, int flags, const Arguments &args, bool return_ref) { _impl->method(name, flags, args, return_ref); } /** * Add a property to the class diff --git a/zend/classimpl.h b/zend/classimpl.h index bd631b8b..ee8fd83d 100644 --- a/zend/classimpl.h +++ b/zend/classimpl.h @@ -371,15 +371,16 @@ class ClassImpl * @param method The actual method * @param flags Optional flags * @param args Description of the supported arguments + * @param return_ref Return reference or not */ - void method(const char *name, const method_callback_0 &method, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args)); } - void method(const char *name, const method_callback_1 &method, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args)); } - void method(const char *name, const method_callback_2 &method, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args)); } - void method(const char *name, const method_callback_3 &method, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args)); } - void method(const char *name, const method_callback_4 &method, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args)); } - void method(const char *name, const method_callback_5 &method, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args)); } - void method(const char *name, const method_callback_6 &method, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args)); } - void method(const char *name, const method_callback_7 &method, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args)); } + void method(const char *name, const method_callback_0 &method, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args, return_ref)); } + void method(const char *name, const method_callback_1 &method, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args, return_ref)); } + void method(const char *name, const method_callback_2 &method, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args, return_ref)); } + void method(const char *name, const method_callback_3 &method, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args, return_ref)); } + void method(const char *name, const method_callback_4 &method, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args, return_ref)); } + void method(const char *name, const method_callback_5 &method, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args, return_ref)); } + void method(const char *name, const method_callback_6 &method, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args, return_ref)); } + void method(const char *name, const method_callback_7 &method, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, method, flags & MethodModifiers, args, return_ref)); } /** * Add a static method to the class @@ -392,11 +393,12 @@ class ClassImpl * @param method The actual method * @param flags Optional flags * @param args Description of the supported arguments + * @param return_ref Return reference or not */ - void method(const char *name, const native_callback_0 &method, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, method, (flags & MethodModifiers) | Static, args)); } - void method(const char *name, const native_callback_1 &method, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, method, (flags & MethodModifiers) | Static, args)); } - void method(const char *name, const native_callback_2 &method, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, method, (flags & MethodModifiers) | Static, args)); } - void method(const char *name, const native_callback_3 &method, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, method, (flags & MethodModifiers) | Static, args)); } + void method(const char *name, const native_callback_0 &method, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, method, (flags & MethodModifiers) | Static, args, return_ref)); } + void method(const char *name, const native_callback_1 &method, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, method, (flags & MethodModifiers) | Static, args, return_ref)); } + void method(const char *name, const native_callback_2 &method, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, method, (flags & MethodModifiers) | Static, args, return_ref)); } + void method(const char *name, const native_callback_3 &method, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, method, (flags & MethodModifiers) | Static, args, return_ref)); } /** * Add an abstract method to the class @@ -404,8 +406,9 @@ class ClassImpl * @param name Name of the method * @param flags Optional flags (like public or protected) * @param args Description of the supported arguments + * @param return_ref Return reference or not */ - void method(const char *name, int flags=0, const Arguments &args = {}) { _methods.push_back(std::make_shared(name, (flags & (MethodModifiers | Static)) | Abstract , args)); } + void method(const char *name, int flags=0, const Arguments &args = {}, bool return_ref = false) { _methods.push_back(std::make_shared(name, (flags & (MethodModifiers | Static)) | Abstract , args, return_ref)); } /** * Add a property to the class diff --git a/zend/function.h b/zend/function.h index 4c34ac71..60087616 100644 --- a/zend/function.h +++ b/zend/function.h @@ -23,11 +23,13 @@ class Function : public Callable * Constructor * @param name Function name * @param function The native C function + * @param arguments Information about the arguments + * @param return_ref Return reference or not */ - Function(const char *name, const native_callback_0 &function, const Arguments &arguments = {}) : Callable(name, arguments), _type(0) { _function.f0 = function; } - Function(const char *name, const native_callback_1 &function, const Arguments &arguments = {}) : Callable(name, arguments), _type(1) { _function.f1 = function; } - Function(const char *name, const native_callback_2 &function, const Arguments &arguments = {}) : Callable(name, arguments), _type(2) { _function.f2 = function; } - Function(const char *name, const native_callback_3 &function, const Arguments &arguments = {}) : Callable(name, arguments), _type(3) { _function.f3 = function; } + Function(const char *name, const native_callback_0 &function, const Arguments &arguments = {}, bool return_ref = false) : Callable(name, arguments, return_ref), _type(0) { _function.f0 = function; } + Function(const char *name, const native_callback_1 &function, const Arguments &arguments = {}, bool return_ref = false) : Callable(name, arguments, return_ref), _type(1) { _function.f1 = function; } + Function(const char *name, const native_callback_2 &function, const Arguments &arguments = {}, bool return_ref = false) : Callable(name, arguments, return_ref), _type(2) { _function.f2 = function; } + Function(const char *name, const native_callback_3 &function, const Arguments &arguments = {}, bool return_ref = false) : Callable(name, arguments, return_ref), _type(3) { _function.f3 = function; } /** * Copy constructor diff --git a/zend/method.h b/zend/method.h index dd18a9aa..6a2c8f07 100644 --- a/zend/method.h +++ b/zend/method.h @@ -26,20 +26,21 @@ class Method : public Callable * @param callback Native callback * @param flags Access flags * @param args Argument description + * @param return_ref Return reference or not */ - Method(const char *name, const method_callback_0 &callback, int flags, const Arguments &args) : Callable(name, args), _type(0), _flags(flags) { _callback.m0 = callback; } - Method(const char *name, const method_callback_1 &callback, int flags, const Arguments &args) : Callable(name, args), _type(1), _flags(flags) { _callback.m1 = callback; } - Method(const char *name, const method_callback_2 &callback, int flags, const Arguments &args) : Callable(name, args), _type(2), _flags(flags) { _callback.m2 = callback; } - Method(const char *name, const method_callback_3 &callback, int flags, const Arguments &args) : Callable(name, args), _type(3), _flags(flags) { _callback.m3 = callback; } - Method(const char *name, const method_callback_4 &callback, int flags, const Arguments &args) : Callable(name, args), _type(4), _flags(flags) { _callback.m4 = callback; } - Method(const char *name, const method_callback_5 &callback, int flags, const Arguments &args) : Callable(name, args), _type(5), _flags(flags) { _callback.m5 = callback; } - Method(const char *name, const method_callback_6 &callback, int flags, const Arguments &args) : Callable(name, args), _type(6), _flags(flags) { _callback.m6 = callback; } - Method(const char *name, const method_callback_7 &callback, int flags, const Arguments &args) : Callable(name, args), _type(7), _flags(flags) { _callback.m7 = callback; } - Method(const char *name, const native_callback_0 &callback, int flags, const Arguments &args) : Callable(name, args), _type(8), _flags(flags) { _callback.m8 = callback; } - Method(const char *name, const native_callback_1 &callback, int flags, const Arguments &args) : Callable(name, args), _type(9), _flags(flags) { _callback.m9 = callback; } - Method(const char *name, const native_callback_2 &callback, int flags, const Arguments &args) : Callable(name, args), _type(10), _flags(flags) { _callback.m10 = callback; } - Method(const char *name, const native_callback_3 &callback, int flags, const Arguments &args) : Callable(name, args), _type(11), _flags(flags) { _callback.m11 = callback; } - Method(const char *name, int flags, const Arguments &args) : Callable(name, args), _type(9999), _flags(flags) { _callback.m0 = nullptr; } + Method(const char *name, const method_callback_0 &callback, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(0), _flags(flags) { _callback.m0 = callback; } + Method(const char *name, const method_callback_1 &callback, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(1), _flags(flags) { _callback.m1 = callback; } + Method(const char *name, const method_callback_2 &callback, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(2), _flags(flags) { _callback.m2 = callback; } + Method(const char *name, const method_callback_3 &callback, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(3), _flags(flags) { _callback.m3 = callback; } + Method(const char *name, const method_callback_4 &callback, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(4), _flags(flags) { _callback.m4 = callback; } + Method(const char *name, const method_callback_5 &callback, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(5), _flags(flags) { _callback.m5 = callback; } + Method(const char *name, const method_callback_6 &callback, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(6), _flags(flags) { _callback.m6 = callback; } + Method(const char *name, const method_callback_7 &callback, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(7), _flags(flags) { _callback.m7 = callback; } + Method(const char *name, const native_callback_0 &callback, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(8), _flags(flags) { _callback.m8 = callback; } + Method(const char *name, const native_callback_1 &callback, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(9), _flags(flags) { _callback.m9 = callback; } + Method(const char *name, const native_callback_2 &callback, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(10), _flags(flags) { _callback.m10 = callback; } + Method(const char *name, const native_callback_3 &callback, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(11), _flags(flags) { _callback.m11 = callback; } + Method(const char *name, int flags, const Arguments &args, bool return_ref = false) : Callable(name, args, return_ref), _type(9999), _flags(flags) { _callback.m0 = nullptr; } /** * Copy and move constructors diff --git a/zend/namespace.cpp b/zend/namespace.cpp index 9274bf05..18429eff 100644 --- a/zend/namespace.cpp +++ b/zend/namespace.cpp @@ -18,15 +18,16 @@ namespace Php { * @param name Name of the function * @param function The function to add * @param arguments Optional argument specification + * @param return_ref Return reference or not * @return Namespace Same object to allow chaining */ -Namespace &Namespace::add(const char *name, const native_callback_0 &function, const Arguments &arguments) +Namespace &Namespace::add(const char *name, const native_callback_0 &function, const Arguments &arguments, bool return_ref) { // skip when locked if (locked()) return *this; // add a function - _functions.push_back(std::make_shared(name, function, arguments)); + _functions.push_back(std::make_shared(name, function, arguments, return_ref)); // allow chaining return *this; @@ -37,15 +38,16 @@ Namespace &Namespace::add(const char *name, const native_callback_0 &function, c * @param name Name of the function * @param function The function to add * @param arguments Optional argument specification + * @param return_ref Return reference or not * @return Namespace Same object to allow chaining */ -Namespace &Namespace::add(const char *name, const native_callback_1 &function, const Arguments &arguments) +Namespace &Namespace::add(const char *name, const native_callback_1 &function, const Arguments &arguments, bool return_ref) { // skip when locked if (locked()) return *this; // add a function - _functions.push_back(std::make_shared(name, function, arguments)); + _functions.push_back(std::make_shared(name, function, arguments, return_ref)); // allow chaining return *this; @@ -56,15 +58,16 @@ Namespace &Namespace::add(const char *name, const native_callback_1 &function, c * @param name Name of the function * @param function The function to add * @param arguments Optional argument specification + * @param return_ref Return reference or not * @return Namespace Same object to allow chaining */ -Namespace &Namespace::add(const char *name, const native_callback_2 &function, const Arguments &arguments) +Namespace &Namespace::add(const char *name, const native_callback_2 &function, const Arguments &arguments, bool return_ref) { // skip when locked if (locked()) return *this; // add a function - _functions.push_back(std::make_shared(name, function, arguments)); + _functions.push_back(std::make_shared(name, function, arguments, return_ref)); // allow chaining return *this; @@ -75,15 +78,16 @@ Namespace &Namespace::add(const char *name, const native_callback_2 &function, c * @param name Name of the function * @param function The function to add * @param arguments Optional argument specification + * @param return_ref Return reference or not * @return Namespace Same object to allow chaining */ -Namespace &Namespace::add(const char *name, const native_callback_3 &function, const Arguments &arguments) +Namespace &Namespace::add(const char *name, const native_callback_3 &function, const Arguments &arguments, bool return_ref) { // skip when locked if (locked()) return *this; // add a function - _functions.push_back(std::make_shared(name, function, arguments)); + _functions.push_back(std::make_shared(name, function, arguments, return_ref)); // allow chaining return *this; From 26bcad5e24819219bb2c3654833308e938b72767 Mon Sep 17 00:00:00 2001 From: andot Date: Mon, 20 Oct 2014 21:12:41 +0800 Subject: [PATCH 2/2] Fixed reference count of return value. --- zend/callable.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zend/callable.cpp b/zend/callable.cpp index 81b76502..48065e51 100644 --- a/zend/callable.cpp +++ b/zend/callable.cpp @@ -110,6 +110,9 @@ void Callable::invoke_return_ref(INTERNAL_FUNCTION_PARAMETERS) // detach the zval (we don't want it to be destructed) zval *val = result.detach(); + // add one more reference + Z_ADDREF_P(val); + // get the reference of the result SEPARATE_ZVAL_TO_MAKE_IS_REF(&val);