diff options
-rw-r--r-- | include/class.h | 2 | ||||
-rw-r--r-- | include/classbase.h | 12 | ||||
-rw-r--r-- | include/extension.h | 95 | ||||
-rw-r--r-- | include/hiddenpointer.h | 27 | ||||
-rw-r--r-- | include/namespace.h | 203 | ||||
-rw-r--r-- | phpcpp.h | 3 | ||||
-rw-r--r-- | src/callable.cpp | 2 | ||||
-rw-r--r-- | src/callable.h | 2 | ||||
-rw-r--r-- | src/classbase.cpp | 33 | ||||
-rw-r--r-- | src/extension.cpp | 83 | ||||
-rw-r--r-- | src/function.h | 14 | ||||
-rw-r--r-- | src/includes.h | 5 | ||||
-rw-r--r-- | src/namespace.cpp | 103 |
13 files changed, 419 insertions, 165 deletions
diff --git a/include/class.h b/include/class.h index 51cfb46..1ac4f00 100644 --- a/include/class.h +++ b/include/class.h @@ -41,6 +41,8 @@ public: * @param name Name of the class */ Class(const char *name) : ClassBase(name) {} + + // @todo add copy and move constructor /** * Destructor diff --git a/include/classbase.h b/include/classbase.h index 9726e5a..98a430e 100644 --- a/include/classbase.h +++ b/include/classbase.h @@ -88,8 +88,10 @@ public: * this means that this method is called after the module is already available. * This function will inform the Zend engine about the existence of the * class. + * + * @param ns Namespace name */ - void initialize(); + void initialize(const std::string &ns); protected: /** @@ -173,15 +175,15 @@ private: /** * All class methods - * @var set + * @var std::list */ - std::set<std::shared_ptr<Method>> _methods; + std::list<std::shared_ptr<Method>> _methods; /** * All class members (class properties) - * @var set + * @var std::list */ - std::set<std::shared_ptr<Member>> _members; + std::list<std::shared_ptr<Member>> _members; }; /** diff --git a/include/extension.h b/include/extension.h index 4a89cf9..72c7d56 100644 --- a/include/extension.h +++ b/include/extension.h @@ -29,20 +29,9 @@ struct _zend_module_entry; namespace Php { /** - * A couple of predefined native callback functions that can be registered. - * These are functions that optional accept a Request and/or Parameters object, - * and that either return void or a Value object. - */ -typedef void (*native_callback_0)(); -typedef void (*native_callback_1)(Parameters &); -typedef Value (*native_callback_2)(); -typedef Value (*native_callback_3)(Parameters &); - -/** * Forward declaration */ class Extension; -class Function; /** * Optional callback types for starting and stopping the request @@ -53,7 +42,7 @@ typedef bool (*request_callback)(Extension *extension); /** * Class definition */ -class Extension +class Extension : public Namespace { public: /** @@ -77,36 +66,36 @@ public: virtual ~Extension(); /** - * Initialize the extension. - * - * This method is called after the extension has been loaded, constructed - * and after the compatibility has been checked, but before the requests - * are handled. You can override this method to add your own initialization. - * - * The default behavior of this function is to enable all classes that are - * defined in this extension, so that they are also available in PHP. + * Initialize the extension after it was registered * - * The method should return true on success, and false on failure (in which - * case the extension will not be used) + * You can override this method to add your own initialization code. The + * default implementation registers all classes and namespaces * * @return bool */ - virtual bool initialize(); + virtual bool initialize() + { + // initialize the namespace + Namespace::initialize(""); + + // ok + return true; + } /** - * Finalize the extension - * - * This method gets called after all requests were handled, and right before - * the Apache module or CLI script will exit. You can override it to add - * your own cleanup code. + * Finalize the extension after it was registered + * + * You can override this method to do your own cleanup right before the + * extension object is going to be destructed * * @return bool */ virtual bool finalize() { + // ok return true; } - + /** * Start a request * @@ -143,32 +132,6 @@ public: } /** - * Add a native function directly to the extension - * @param name Name of the function - * @param function The function to add - * @param arguments Optional argument specification - */ - void add(const char *name, native_callback_0 function, const Arguments &arguments = {}); - void add(const char *name, native_callback_1 function, const Arguments &arguments = {}); - void add(const char *name, native_callback_2 function, const Arguments &arguments = {}); - void add(const char *name, native_callback_3 function, const Arguments &arguments = {}); - - /** - * Add a native class to the extension - * @param name Name of the class - * @param type The class implementation - */ - template<typename T> - void add(const Class<T> &type) - { - // make a copy of the object - auto *info = new Class<T>(type); - - // and copy it to the list of classes - _classes.insert(std::unique_ptr<ClassBase>(info)); - } - - /** * Retrieve the module entry * * This is the memory address that should be exported by the get_module() @@ -178,19 +141,23 @@ public: */ _zend_module_entry *module(); - -private: /** - * Functions defined in the library - * @var set + * Cast to a module entry + * @return _zend_module_entry* */ - std::set<std::unique_ptr<Function>> _functions; - + operator _zend_module_entry * () + { + return module(); + } + +private: /** - * Classes defined in the library, indexed by their name - * @var set + * Initialize all functions in this namespace + * @param ns Namespace prefix + * @param entries The array to be filled + * @return int Number of functions that were initialized */ - std::set<std::unique_ptr<ClassBase>> _classes; + size_t initialize(const std::string &ns, zend_function_entry entries[]); /** * The information that is passed to the Zend engine diff --git a/include/hiddenpointer.h b/include/hiddenpointer.h index 96bb26a..93fdc7c 100644 --- a/include/hiddenpointer.h +++ b/include/hiddenpointer.h @@ -94,7 +94,32 @@ public: * @param that * @return HiddenPointer */ - HiddenPointer<Type> operator=(const HiddenPointer &that) = delete; + HiddenPointer<Type> operator=(const HiddenPointer &that) + { + // skip self assignmend + if (this == &that) return *this; + + // deallocate current object + if (_allocated) delete[] _buffer; + + // copy allocated setting + _allocated = that._allocated; + + // is the other object allocated? + if (_allocated) + { + // allocate this object too, call constructor + HiddenPointer(that, that); + } + else + { + // just copy the data + _buffer = that._buffer; + } + + // done + return *this; + } /** * Retrieve the pointer diff --git a/include/namespace.h b/include/namespace.h new file mode 100644 index 0000000..727f1dd --- /dev/null +++ b/include/namespace.h @@ -0,0 +1,203 @@ +/** + * Namespace.h + * + * Class that can be used to group various functions and classes into one + * namespace. + * + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2014 Copernica BV + */ + +/** + * Set up namespace + */ +namespace Php { + +/** + * A couple of predefined native callback functions that can be registered. + * These are functions that optional accept a Request and/or Parameters object, + * and that either return void or a Value object. + */ +typedef void (*native_callback_0)(); +typedef void (*native_callback_1)(Parameters &); +typedef Value (*native_callback_2)(); +typedef Value (*native_callback_3)(Parameters &); + +/** + * Forward declaration + */ +class Function; + +/** + * Class definition + */ +class Namespace +{ +public: + /** + * Constructor + * @param name Name of the namespace + */ + Namespace(const char *name) : _name(name) {} + + /** + * Copy constructor + * @param ns Namespace to copy + */ + Namespace(const Namespace &ns) : + _name(ns._name), + _functions(ns._functions), + _classes(ns._classes), + _namespaces(ns._namespaces) {} + + /** + * Move constructor + * @param ns + */ + Namespace(Namespace &&ns) : + _name(std::move(ns._name)), + _functions(std::move(ns._functions)), + _classes(std::move(ns._classes)), + _namespaces(std::move(ns._namespaces)) {} + + /** + * Destructor + */ + virtual ~Namespace() {} + + /** + * Add a native function directly to the extension + * @param name Name of the function + * @param function The function to add + * @param arguments Optional argument specification + */ + void add(const char *name, native_callback_0 function, const Arguments &arguments = {}); + void add(const char *name, native_callback_1 function, const Arguments &arguments = {}); + void add(const char *name, native_callback_2 function, const Arguments &arguments = {}); + void add(const char *name, native_callback_3 function, const Arguments &arguments = {}); + + /** + * Add a native class to the extension by moving it + * @param name Name of the class + * @param type The class implementation + */ + template<typename T> + void add(Class<T> &&type) + { + // make a copy of the object + auto *copy = new Class<T>(std::move(type)); + + // and add it to the list of classes + _classes.push_back(std::unique_ptr<ClassBase>(copy)); + } + + /** + * Add a native class to the extension by copying it + * @param name Name of the class + * @param type The class implementation + */ + template<typename T> + void add(const Class<T> &type) + { + // make a copy of the object + auto *copy = new Class<T>(std::move(type)); + + // and add it to the list of classes + _classes.push_back(std::unique_ptr<ClassBase>(copy)); + } + + /** + * Add a namespace to the extension by moving it + * @param ns The namespace + */ + void add(Namespace &&ns) + { + // make a copy of the object + auto *copy = new Namespace(std::move(ns)); + + // add it to the list of namespaces + _namespaces.push_back(std::unique_ptr<Namespace>(copy)); + } + + /** + * Add a namespace to the extension by copying it + * @param ns The namespace + */ + void add(const Namespace &ns) + { + // make a copy of the object + auto *copy = new Namespace(std::move(ns)); + + // add it to the list of namespaces + _namespaces.push_back(std::unique_ptr<Namespace>(copy)); + } + + +protected: + /** + * Name of the namespace + * @var string + */ + std::string _name; + + /** + * Functions defined by the extension + * @var list + */ + std::list<std::shared_ptr<Function>> _functions; + + /** + * Classes defined by the extension + * @var list + */ + std::list<std::shared_ptr<ClassBase>> _classes; + + /** + * Namespaces defined by the extension + * @var list + */ + std::list<std::shared_ptr<Namespace>> _namespaces; + + /** + * The total number of functions + * @return size_t + */ + size_t functions() + { + // number of functions in this namespace + int result = _functions.size(); + + // number of functions in sub-namespace + for (auto &ns : _namespaces) result += ns->functions(); + + // done + return result; + } + + /** + * Initialize all functions in this namespace + * @param ns Namespace prefix + * @param entries The array to be filled + * @return int Number of functions that were initialized + */ + size_t initialize(const std::string &ns, zend_function_entry entries[]); + + /** + * Initialize the namespace after it was registered + * @param parent Parent namespace + */ + void initialize(const std::string &parent) + { + // loop through the classes in this namespace + for (auto &c : _classes) c->initialize(parent+"\\"+_name); + + // and loop through the other namespaces + for (auto &n : _namespaces) n->initialize(parent+"\\"+_name); + } +}; + +/** + * End namespace + */ +} + @@ -17,9 +17,8 @@ #include <string> #include <initializer_list> #include <vector> -#include <map> #include <memory> -#include <set> +#include <list> #include <exception> /** diff --git a/src/callable.cpp b/src/callable.cpp index d410c0b..5745d79 100644 --- a/src/callable.cpp +++ b/src/callable.cpp @@ -94,7 +94,7 @@ void Callable::initialize(zend_internal_function_info *info, const char *classna // 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 info->_name = _ptr; - info->_name_len = _ptr.length(); + info->_name_len = strlen(_ptr); info->_class_name = classname; // number of required arguments, and the expected return type diff --git a/src/callable.h b/src/callable.h index 1b761ae..d08dc42 100644 --- a/src/callable.h +++ b/src/callable.h @@ -68,6 +68,7 @@ public: /** * Fill a function entry * @param entry Entry to be filled + * @param ns Active namespace * @param classname Optional class name * @param flags Access flags */ @@ -76,6 +77,7 @@ public: /** * Fill function info * @param info Info object to be filled + * @param ns Active namespace * @param classname Optional class name */ void initialize(struct _zend_internal_function_info *info, const char *classname = nullptr) const; diff --git a/src/classbase.cpp b/src/classbase.cpp index 38972f5..b38f6d3 100644 --- a/src/classbase.cpp +++ b/src/classbase.cpp @@ -157,12 +157,17 @@ const struct _zend_function_entry *ClassBase::entries() * this means that this method is called after the module is already available. * This function will inform the Zend engine about the existence of the * class. + * + * @param prefix namespace prefix */ -void ClassBase::initialize() +void ClassBase::initialize(const std::string &prefix) { // the class entry zend_class_entry entry; + // update the name + if (prefix.size() > 0) _name = prefix + "\\" + _name; + // initialize the class entry INIT_CLASS_ENTRY_EX(entry, _name.c_str(), _name.size(), entries()); @@ -214,7 +219,7 @@ void ClassBase::initialize() void ClassBase::add(const char *name, method_callback_0 callback, int flags, const Arguments &args) { // add the method - _methods.insert(std::make_shared<Method>(name, callback, flags, args)); + _methods.push_back(std::make_shared<Method>(name, callback, flags, args)); } /** @@ -227,7 +232,7 @@ void ClassBase::add(const char *name, method_callback_0 callback, int flags, con void ClassBase::add(const char *name, method_callback_1 callback, int flags, const Arguments &args) { // add the method - _methods.insert(std::make_shared<Method>(name, callback, flags, args)); + _methods.push_back(std::make_shared<Method>(name, callback, flags, args)); } /** @@ -240,7 +245,7 @@ void ClassBase::add(const char *name, method_callback_1 callback, int flags, con void ClassBase::add(const char *name, method_callback_2 callback, int flags, const Arguments &args) { // add the method - _methods.insert(std::make_shared<Method>(name, callback, flags, args)); + _methods.push_back(std::make_shared<Method>(name, callback, flags, args)); } /** @@ -253,7 +258,7 @@ void ClassBase::add(const char *name, method_callback_2 callback, int flags, con void ClassBase::add(const char *name, method_callback_3 callback, int flags, const Arguments &args) { // add the method - _methods.insert(std::make_shared<Method>(name, callback, flags, args)); + _methods.push_back(std::make_shared<Method>(name, callback, flags, args)); } /** @@ -265,7 +270,7 @@ void ClassBase::add(const char *name, method_callback_3 callback, int flags, con void ClassBase::add(const char *name, std::nullptr_t value, int flags) { // add property - _members.insert(std::make_shared<NullMember>(name, flags)); + _members.push_back(std::make_shared<NullMember>(name, flags)); } /** @@ -277,7 +282,7 @@ void ClassBase::add(const char *name, std::nullptr_t value, int flags) void ClassBase::add(const char *name, int16_t value, int flags) { // add property - _members.insert(std::make_shared<LongMember>(name, value, flags)); + _members.push_back(std::make_shared<LongMember>(name, value, flags)); } /** @@ -289,7 +294,7 @@ void ClassBase::add(const char *name, int16_t value, int flags) void ClassBase::add(const char *name, int32_t value, int flags) { // add property - _members.insert(std::make_shared<LongMember>(name, value, flags)); + _members.push_back(std::make_shared<LongMember>(name, value, flags)); } /** @@ -301,7 +306,7 @@ void ClassBase::add(const char *name, int32_t value, int flags) void ClassBase::add(const char *name, int64_t value, int flags) { // add property - _members.insert(std::make_shared<LongMember>(name, value, flags)); + _members.push_back(std::make_shared<LongMember>(name, value, flags)); } /** @@ -313,7 +318,7 @@ void ClassBase::add(const char *name, int64_t value, int flags) void ClassBase::add(const char *name, bool value, int flags) { // add property - _members.insert(std::make_shared<BoolMember>(name, value, flags)); + _members.push_back(std::make_shared<BoolMember>(name, value, flags)); } /** @@ -325,7 +330,7 @@ void ClassBase::add(const char *name, bool value, int flags) void ClassBase::add(const char *name, char value, int flags) { // add property - _members.insert(std::make_shared<StringMember>(name, &value, 1, flags)); + _members.push_back(std::make_shared<StringMember>(name, &value, 1, flags)); } /** @@ -337,7 +342,7 @@ void ClassBase::add(const char *name, char value, int flags) void ClassBase::add(const char *name, const std::string &value, int flags) { // add property - _members.insert(std::make_shared<StringMember>(name, value, flags)); + _members.push_back(std::make_shared<StringMember>(name, value, flags)); } /** @@ -349,7 +354,7 @@ void ClassBase::add(const char *name, const std::string &value, int flags) void ClassBase::add(const char *name, const char *value, int flags) { // add property - _members.insert(std::make_shared<StringMember>(name, value, strlen(value), flags)); + _members.push_back(std::make_shared<StringMember>(name, value, strlen(value), flags)); } /** @@ -361,7 +366,7 @@ void ClassBase::add(const char *name, const char *value, int flags) void ClassBase::add(const char *name, double value, int flags) { // add property - _members.insert(std::make_shared<FloatMember>(name, value, flags)); + _members.push_back(std::make_shared<FloatMember>(name, value, flags)); } /** diff --git a/src/extension.cpp b/src/extension.cpp index dae5051..20d5627 100644 --- a/src/extension.cpp +++ b/src/extension.cpp @@ -156,7 +156,8 @@ static int request_shutdown(INIT_FUNC_ARGS) * @param start Request start callback * @param stop Request stop callback */ -Extension::Extension(const char *name, const char *version, request_callback start, request_callback stop) : _start(start), _stop(stop) +Extension::Extension(const char *name, const char *version, request_callback start, request_callback stop) : + Namespace(""), _start(start), _stop(stop) { // keep extension pointer based on the name name2extension[name] = this; @@ -215,54 +216,6 @@ Extension::~Extension() } /** - * Add a native function directly to the extension - * @param name Name of the function - * @param function The function to add - * @param arguments Optional argument specification - */ -void Extension::add(const char *name, native_callback_0 function, const Arguments &arguments) -{ - // add a function - _functions.insert(std::unique_ptr<Function>(new Function(name, function, arguments))); -} - -/** - * Add a native function directly to the extension - * @param name Name of the function - * @param function The function to add - * @param arguments Optional argument specification - */ -void Extension::add(const char *name, native_callback_1 function, const Arguments &arguments) -{ - // add a function - _functions.insert(std::unique_ptr<Function>(new Function(name, function, arguments))); -} - -/** - * Add a native function directly to the extension - * @param name Name of the function - * @param function The function to add - * @param arguments Optional argument specification - */ -void Extension::add(const char *name, native_callback_2 function, const Arguments &arguments) -{ - // add a function - _functions.insert(std::unique_ptr<Function>(new Function(name, function, arguments))); -} - -/** - * Add a native function directly to the extension - * @param name Name of the function - * @param function The function to add - * @param arguments Optional argument specification - */ -void Extension::add(const char *name, native_callback_3 function, const Arguments &arguments) -{ - // add a function - _functions.insert(std::unique_ptr<Function>(new Function(name, function, arguments))); -} - -/** * Retrieve the module entry * @return zend_module_entry */ @@ -272,23 +225,13 @@ zend_module_entry *Extension::module() if (_entry->functions || _functions.size() == 0) return _entry; // allocate memory for the functions - zend_function_entry *entries = new zend_function_entry[_functions.size() + 1]; - - // keep iterator counter - int i = 0; + zend_function_entry *entries = new zend_function_entry[functions() + 1]; - // loop through the functions - for (auto &function : _functions) - { - // retrieve entry - zend_function_entry *entry = &entries[i++]; - - // let the function fill the entry - function->initialize(entry); - } + // initialize the entries + int count = initialize(_name, entries); // last entry should be set to all zeros - zend_function_entry *last = &entries[i]; + zend_function_entry *last = &entries[count]; // all should be set to zero memset(last, 0, sizeof(zend_function_entry)); @@ -301,20 +244,6 @@ zend_module_entry *Extension::module() } /** - * Initialize the extension - * @return bool - */ -bool Extension::initialize() -{ - // loop through the classes - for (auto &iter : _classes) iter->initialize(); - - // done - return true; -} - - -/** * End of namespace */ } diff --git a/src/function.h b/src/function.h index 84d7dcc..40c392f 100644 --- a/src/function.h +++ b/src/function.h @@ -50,6 +50,20 @@ public: } } + /** + * Fill a function entry + * @param prefix Active namespace prefix + * @param entry Entry to be filled + */ + void initialize(const std::string &prefix, struct _zend_function_entry *entry) + { + // if there is a namespace prefix, we should adjust the name + if (prefix.size()) _ptr = HiddenPointer<Callable>(this, prefix+"\\"+(const char *)_ptr); + + // call base initialize + Callable::initialize(entry); + } + private: /** * Union of supported callbacks diff --git a/src/includes.h b/src/includes.h index d2355c1..4117884 100644 --- a/src/includes.h +++ b/src/includes.h @@ -16,9 +16,11 @@ #include <vector> #include <map> #include <memory> -#include <set> +#include <list> #include <exception> +// @todo do we really nead shared_ptr? + // for debug #include <iostream> @@ -62,6 +64,7 @@ #include "../include/abstractclass.h" #include "../include/finalclass.h" #include "../include/interface.h" +#include "../include/namespace.h" #include "../include/extension.h" #include "../include/exception.h" #include "../include/init.h" diff --git a/src/namespace.cpp b/src/namespace.cpp new file mode 100644 index 0000000..0938a90 --- /dev/null +++ b/src/namespace.cpp @@ -0,0 +1,103 @@ +/** + * Namespace.cpp + * + * Implementation of the namespace class + * + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2014 Copernica BV + */ +#include "includes.h" + +/** + * Open namespace + */ +namespace Php { + +/** + * Add a native function directly to the extension + * @param name Name of the function + * @param function The function to add + * @param arguments Optional argument specification + */ +void Namespace::add(const char *name, native_callback_0 function, const Arguments &arguments) +{ + // add a function + _functions.push_back(std::make_shared<Function>(name, function, arguments)); +} + +/** + * Add a native function directly to the extension + * @param name Name of the function + * @param function The function to add + * @param arguments Optional argument specification + */ +void Namespace::add(const char *name, native_callback_1 function, const Arguments &arguments) +{ + // add a function + _functions.push_back(std::make_shared<Function>(name, function, arguments)); +} + +/** + * Add a native function directly to the extension + * @param name Name of the function + * @param function The function to add + * @param arguments Optional argument specification + */ +void Namespace::add(const char *name, native_callback_2 function, const Arguments &arguments) +{ + // add a function + _functions.push_back(std::make_shared<Function>(name, function, arguments)); +} + +/** + * Add a native function directly to the extension + * @param name Name of the function + * @param function The function to add + * @param arguments Optional argument specification + */ +void Namespace::add(const char *name, native_callback_3 function, const Arguments &arguments) +{ + // add a function + _functions.push_back(std::make_shared<Function>(name, function, arguments)); +} + +/** + * Initialize all functions in this namespace + * @param parent Namespace prefix of the parent + * @param entries The array to be filled + * @return int Number of functions that were initialized + */ +size_t Namespace::initialize(const std::string &parent, zend_function_entry entries[]) +{ + // keep iterator counter + int count = 0; + + // the namespace to use + std::string prefix = parent.size() ? parent + "\\" + _name : _name; + + // loop through the functions + for (auto &function : _functions) + { + // retrieve entry + zend_function_entry *entry = &entries[count++]; + + // let the function fill the entry + function->initialize(prefix, entry); + } + + // loop through the namespace + for (auto &ns : _namespaces) + { + // let the namespace initialize + count += ns->initialize(prefix, &entries[count]); + } + + // done + return count; +} + +/** + * End namespace + */ +} + |