diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2013-09-08 16:26:11 -0700 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2013-09-08 16:26:11 -0700 |
commit | df2520e4b2c87e2302ee4c6cec1e672091efebfb (patch) | |
tree | f3bcd4fa7c4d0c6ee601268ceca4d6841ed90d0d /src | |
parent | eb86ac350756afeffa0e2db8be87876d35bc40a8 (diff) |
Refactoring function class, and making it even more easy to directly enable native C functions in PHP
Diffstat (limited to 'src')
-rw-r--r-- | src/arginfo.h | 2 | ||||
-rw-r--r-- | src/argument.cpp | 74 | ||||
-rw-r--r-- | src/arguments.cpp | 46 | ||||
-rw-r--r-- | src/callable.cpp | 4 | ||||
-rw-r--r-- | src/callable.h | 2 | ||||
-rw-r--r-- | src/extension.cpp | 130 | ||||
-rw-r--r-- | src/function.cpp | 76 | ||||
-rw-r--r-- | src/functions.cpp | 54 | ||||
-rw-r--r-- | src/hiddenpointer.h | 166 | ||||
-rw-r--r-- | src/includes.h | 5 | ||||
-rw-r--r-- | src/parameters.cpp | 39 | ||||
-rw-r--r-- | src/value.cpp | 2 |
12 files changed, 298 insertions, 302 deletions
diff --git a/src/arginfo.h b/src/arginfo.h index 0080667..39e0e99 100644 --- a/src/arginfo.h +++ b/src/arginfo.h @@ -10,7 +10,7 @@ /** * Set up namespace */ -namespace PhpCpp { +namespace Php { /** * Class definition diff --git a/src/argument.cpp b/src/argument.cpp index 627ee05..387151a 100644 --- a/src/argument.cpp +++ b/src/argument.cpp @@ -11,59 +11,65 @@ /** * Set up namespace */ -namespace PhpCpp { +namespace Php { /** - * Constructor if this argument should be an instance of a certain class - * @param name Name of the argument - * @param classname If a specific class is required, the class type - * @param null Are NULL values allowed in stead of an instance? - * @param ref Is this a pass-by-reference argument? + * Move constructor + * @param argument */ -Argument::Argument(const std::string &name, const std::string &classname, bool null, bool ref) +Argument::Argument(Argument &&argument) { - _refcount = new int(1); - _info = new ArgInfo(name, classname, null, ref); + // copy data + _info = argument._info; } /** - * Constructor if the argument can be anything - * Note that only arrayType and callableType are supported type-hints - * @param name Name of the argument - * @param type Type hint (arrayType or callableType) - * @param ref Is this a pass-by-reference argument? + * Change the name + * @param name + * @return Argument */ -Argument::Argument(const std::string &name, Type type, bool ref) +Argument &Argument::name(const char *name) { - _refcount = new int(1); - _info = new ArgInfo(name, type, ref); + _info->name = name; + _info->name_len = strlen(name); + return *this; } /** - * Constructor if the argument can be anything - * @param name Name of the argument - * @param ref Is this a pass-by-reference argument? + * Change the type + * @param type + * @return Argument */ -Argument::Argument(const std::string &name, bool ref) +Argument &Argument::type(Type type) { - _refcount = new int(1); - _info = new ArgInfo(name, ref); + _info->type_hint = type; + return *this; } /** - * Clean up the object + * Require the parameter to be a certain class + * @param name Name of the class + * @param null Are null values allowed? + * @return Argument */ -void Argument::cleanup() +Argument &Argument::object(const char *classname, bool null) { - // one reference less - (*_refcount)--; - - // leap out if still in use - if (*_refcount > 0) return; - - // release memory - delete _refcount; - delete _info; + _info->type_hint = objectType; + _info->class_name = classname; + _info->class_name_len = strlen(classname); + _info->allow_null = null; + return *this; +} + +/** + * Is this a by-ref argument? + * @param bool Mark as by-ref variable + * @return Argument + */ +Argument &Argument::byref(bool value) +{ + _info->pass_by_reference = value; + return *this; } /** diff --git a/src/arguments.cpp b/src/arguments.cpp index e5e7ae5..53f030b 100644 --- a/src/arguments.cpp +++ b/src/arguments.cpp @@ -11,13 +11,55 @@ /** * Set up namespace */ -namespace PhpCpp { +namespace Php { + +/** + * Constructor + * @param min The min number of arguments + * @param max The max number of arguments + */ +Arguments::Arguments(int min, int max) +{ + // copy arguments + _min = min; + _max = max; + // max should be appropriate + if (_max < _min) _max = _min; + + // allocate memory for the arguments, with one extra record to hold information + _argv = new zend_arg_info[_max + 1]; + + // initialize the arguments + for (int i=1; i<_max+1; i++) + { + // initialize the argument + _argv[i].name = NULL; + _argv[i].name_len = 0; + _argv[i].class_name = NULL; + _argv[i].class_name_len = 0; + _argv[i].type_hint = nullType; + _argv[i].allow_null = false; + _argv[i].pass_by_reference = false; + } +} + +/** + * Destructor + */ +Arguments::~Arguments() +{ + // deallocate arguments + delete[] _argv; +} + /** * Constructor * @param argc Number of arguments * @param tsrm_ls */ +/* + Arguments::Arguments(int argc TSRMLS_DC) { // reserve plenty of space @@ -33,6 +75,8 @@ Arguments::Arguments(int argc TSRMLS_DC) push_back(Value(*arg)); } } +* +*/ /** * End of namespace diff --git a/src/callable.cpp b/src/callable.cpp index 69ef148..4db463c 100644 --- a/src/callable.cpp +++ b/src/callable.cpp @@ -11,7 +11,7 @@ /** * Namespace */ -namespace PhpCpp { +namespace Php { /** * Function that is called by the Zend engine every time that a function gets called @@ -101,7 +101,7 @@ void Callable::process(const std::initializer_list<Argument> &arguments) for (auto it = begin(arguments); it != arguments.end(); it++) { // fill the argument structure - it->internal()->fill(&_argv[++i]); +// it->internal()->fill(&_argv[++i]); } } diff --git a/src/callable.h b/src/callable.h index b6f1e98..293e3aa 100644 --- a/src/callable.h +++ b/src/callable.h @@ -14,7 +14,7 @@ /** * Set up namespace */ -namespace PhpCpp { +namespace Php { /** * Class definition diff --git a/src/extension.cpp b/src/extension.cpp index 2ed4fa7..2d9ef9f 100644 --- a/src/extension.cpp +++ b/src/extension.cpp @@ -9,7 +9,7 @@ /** * Set up namespace */ -namespace PhpCpp { +namespace Php { /** * If this extension is compiled for a PHP version with multi @@ -142,43 +142,109 @@ static int request_shutdown(INIT_FUNC_ARGS) * @param name Name of the extension * @param version Version number */ -Extension::Extension(const char *name, const char *version, const Functions &functions) +Extension::Extension(const char *name, const char *version) : _ptr(this, name) { - // allocate memory + // allocate memory (we allocate this on the heap so that the size of the + // entry does not have to be defined in the .h file. We pay a performance + // price for this, but we pay this price becuase the design goal of the + // PHP-C++ library is to have an interface that is as simple as possible _entry = new zend_module_entry; - // assign all members (apart from the globals) - _entry->size = sizeof(zend_module_entry); // size of the data - _entry->zend_api = ZEND_MODULE_API_NO; // api number - _entry->zend_debug = ZEND_DEBUG; // debug mode enabled? - _entry->zts = USING_ZTS; // is thread safety enabled? - _entry->ini_entry = NULL; // the php.ini record - _entry->deps = NULL; // dependencies on other modules - _entry->name = HiddenPointer<Extension>(this, name); // extension name, with a hidden pointer to the extension object - _entry->functions = functions.internal(); // functions supported by this module - _entry->module_startup_func = extension_startup; // startup function for the whole extension - _entry->module_shutdown_func = extension_shutdown; // shutdown function for the whole extension - _entry->request_startup_func = request_startup; // startup function per request - _entry->request_shutdown_func = request_shutdown; // shutdown function per request - _entry->info_func = NULL; // information for retrieving info - _entry->version = version; // version string - _entry->globals_size = 0; // size of the global variables - _entry->globals_ptr = NULL; // pointer to the globals - _entry->globals_ctor = NULL; // constructor for global variables - _entry->globals_dtor = NULL; // destructor for global variables - _entry->post_deactivate_func = NULL; // unknown function - _entry->module_started = 0; // module is not yet started - _entry->type = 0; // temporary or persistent module, will be filled by Zend engine - _entry->handle = NULL; // dlopen() handle, will be filled by Zend engine - _entry->module_number = 0; // module number will be filled in by Zend engine - _entry->build_id = ZEND_MODULE_BUILD_ID; // check if extension and zend engine are compatible - - // things that only need to be initialized + // assign all members (apart from the globals) + _entry->size = sizeof(zend_module_entry); // size of the data + _entry->zend_api = ZEND_MODULE_API_NO; // api number + _entry->zend_debug = ZEND_DEBUG; // debug mode enabled? + _entry->zts = USING_ZTS; // is thread safety enabled? + _entry->ini_entry = NULL; // the php.ini record + _entry->deps = NULL; // dependencies on other modules + _entry->name = _ptr; // extension name, with a hidden pointer to the extension object + _entry->functions = NULL; // functions supported by this module (none for now) + _entry->module_startup_func = extension_startup; // startup function for the whole extension + _entry->module_shutdown_func = extension_shutdown; // shutdown function for the whole extension + _entry->request_startup_func = request_startup; // startup function per request + _entry->request_shutdown_func = request_shutdown; // shutdown function per request + _entry->info_func = NULL; // information for retrieving info + _entry->version = version; // version string + _entry->globals_size = 0; // size of the global variables + _entry->globals_ptr = NULL; // pointer to the globals + _entry->globals_ctor = NULL; // constructor for global variables + _entry->globals_dtor = NULL; // destructor for global variables + _entry->post_deactivate_func = NULL; // unknown function + _entry->module_started = 0; // module is not yet started + _entry->type = 0; // temporary or persistent module, will be filled by Zend engine + _entry->handle = NULL; // dlopen() handle, will be filled by Zend engine + _entry->module_number = 0; // module number will be filled in by Zend engine + _entry->build_id = ZEND_MODULE_BUILD_ID; // check if extension and zend engine are compatible + + // things that only need to be initialized #ifdef ZTS - _entry->globals_id_ptr = NULL; + _entry->globals_id_ptr = NULL; #else - _entry->globals_ptr = NULL; + _entry->globals_ptr = NULL; #endif + +} + +/** + * Destructor + */ +Extension::~Extension() +{ + // deallocate functions + if (_entry->functions) delete[] _entry->functions; + + // deallocate entry + delete _entry; +} + +/** + * Add a function to the library + * @param name Function name + * @param function Function object + * @return Function + */ +Function &Extension::add(const char *name, const Function &function) +{ + // add the function to the map + return _functions[name] = function; +} + +/** + * Retrieve the module entry + * @return zend_module_entry + */ +zend_module_entry *Extension::module() +{ + // check if functions we're already defined + if (_entry->functions || _functions.size() == 0) return _entry; + + // allocate memory for the functions + zend_function_entry *functions = new zend_function_entry[_functions.size() + 1]; + + // keep iterator counter + int i = 0; + + // loop through the functions + for (auto it = begin(_functions); it != _functions.end(); it++) + { + // retrieve entry + zend_function_entry *entry = &functions[i]; + + // let the function fill the entry + it->second.fill(it->first, entry); + } + + // last entry should be set to all zeros + zend_function_entry *last = &functions[i]; + + // all should be set to zero + memset(last, 0, sizeof(zend_function_entry)); + + // store functions in entry object + _entry->functions = functions; + + // return the entry + return _entry; } /** diff --git a/src/function.cpp b/src/function.cpp index cb56d78..8612cf1 100644 --- a/src/function.cpp +++ b/src/function.cpp @@ -11,25 +11,83 @@ /** * Set up namespace */ -namespace PhpCpp { +namespace Php { /** - * Constructor + * 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 invoke_function(INTERNAL_FUNCTION_PARAMETERS) +{ + // find the function name + const char *name = get_active_function_name(TSRMLS_C); + + // uncover the hidden pointer inside the function name + Function *function = HiddenPointer<Function>(name); + + // wrap the return value + Value ret(return_value, true); + + // construct parameters + Parameters params(ZEND_NUM_ARGS()); + + // call the appropriate object + ret = function->invoke(params); +} + +/** + * Fill a function entry + * + * This method is called when the extension is registering itself, when the + * function or method introces himself + * * @param name Name of the function - * @param arguments The arguments that can be passed to the function + * @param entry Entry to be filled */ -Function::Function(const std::string &name, const std::initializer_list<Argument> &arguments) +void Function::fill(const char *name, zend_function_entry *entry) { - // create callable object - _callable = new Callable(name, arguments); + // fill the members of the entity, and hide a pointer to the current object in the name + entry->fname = HiddenPointer<Function>(this, name); + entry->handler = invoke_function; + entry->arg_info = _arguments->internal(); + entry->num_args = _arguments->argc(); + + // there are no flags like deprecated, private or protected + entry->flags = 0; + + // we should fill the first argument as well + fill(name, (zend_internal_function_info *)entry->arg_info); } /** - * Destructor + * Fill a function entry + * @param name Name of the function + * @param info Info to be filled */ -Function::~Function() +void Function::fill(const char *name, zend_internal_function_info *info) { - if (_callable) delete _callable; + // fill in all the members, note that return reference is false by default, + // because we do want to return references, inside the name we hide a pointer + // to the current object + info->_name = HiddenPointer<Function>(this, name); + info->_name_len = strlen(name); + info->_class_name = NULL; + + // number of required arguments, and the expected return type + info->required_num_args = _arguments->required(); + info->_type_hint = _type; + + // we do not support return-by-reference + info->return_reference = false; + + // passing by reference is not used + info->pass_rest_by_reference = false; } /** diff --git a/src/functions.cpp b/src/functions.cpp deleted file mode 100644 index f9e0ffb..0000000 --- a/src/functions.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Functions.cpp - * - * Implementation for the functions class - * - * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> - * @copyright 2013 Copernica BV - */ -#include "includes.h" - -/** - * Set up namespace - */ -namespace PhpCpp { - -/** - * Constructor - * @param functions The functions to parse - */ -Functions::Functions(const std::initializer_list<Function> &functions) : _functions(functions) -{ - // allocate the function entries - _entries = new zend_function_entry[functions.size() + 1]; - - // keep iterator counter - int i = 0; - - // loop through the functions - for (auto it = begin(functions); it != functions.end(); it++) - { - // let the callable fill the array - it->internal()->fill(&_entries[i++]); - } - - // last entry should be set to all zeros - zend_function_entry *last = &_entries[i]; - - // all should be set to zero - memset(last, 0, sizeof(zend_function_entry)); -} - -/** - * Destructor - */ -Functions::~Functions() -{ - delete[] _entries; -} - -/** - * End of namespace - */ -} - diff --git a/src/hiddenpointer.h b/src/hiddenpointer.h deleted file mode 100644 index 8e03eb2..0000000 --- a/src/hiddenpointer.h +++ /dev/null @@ -1,166 +0,0 @@ -/** - * HiddenPointer.h - * - * Helper class that we use to hide a pointer in a string. We do this - * by creating a string buffer that is a littlebit bigger, and put - * the hidden pointer in front of the name - * - * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> - * @copyright 2013 Copernica BV - */ - -/** - * Set up namespace - */ -namespace PhpCpp { - -/** - * Class definition - */ -template <typename Type> -class HiddenPointer -{ -public: - /** - * Constructor to hide the pointer in a buffer - * @param pointer The pointer to hide - * @param text The visible text - * @param size Optional text size - */ - HiddenPointer(Type *pointer, const char *text, int size=-1) - { - // calculate size - if (size < 0) size = strlen(text); - - // reserve enough room for the text and the pointer - _data.reserve(size + sizeof(Type *)); - - // store the pointer - _data.assign(std::string((const char *)&pointer, sizeof(Type *))); - - // append the text - _data.append(text, size); - - // store pointers - _pointer = pointer; - _text = _data.c_str() + sizeof(Type *); - } - - /** - * Hide pointer in buffer - * @param pointer - * @param text - */ - HiddenPointer(Type *pointer, const std::string &text) : HiddenPointer(pointer, text.c_str(), text.size()) {} - - /** - * Constructor to retrieve the object given a buffer - * @param text The visible text - * @param size Size of the text - */ - HiddenPointer(const char *text, int size=-1) - { - // calculate size - if (size < 0) size = strlen(text); - - // the pointer is stored right in front of the name - _pointer = *((Type **)(text - sizeof(Type *))); - _text = text; - } - - /** - * Copy constructor - * @param that - */ - HiddenPointer(const HiddenPointer<Type> &that) : _pointer(that._pointer), _text(that._text), _data(that._data) - { - // if data is filled, the text is located inside the data - if (_data.size() > 0) _text = _data.c_str() + sizeof(Type *); - } - - /** - * Destructor - */ - virtual ~HiddenPointer() {} - - /** - * Assignment operator - * @param that - * @return HiddenPointer - */ - HiddenPointer<Type> operator=(const HiddenPointer &that) - { - // skip self assignment - if (&that == this) return *this; - - // copy members - _pointer = that._pointer; - _text = that._text; - _data = that._data; - - // if data is filled, the text is located inside the data - if (_data.size() > 0) _text = _data.c_str() + sizeof(Type *); - } - - /** - * Retrieve the pointer - * @return Type* - */ - Type *pointer() - { - return _pointer; - } - - /** - * Retrieve the text - * @return const char * - */ - const char *text() - { - return _text; - } - - /** - * Cast to the pointer - * @return Type* - */ - operator Type* () - { - return _pointer; - } - - /** - * Cast to text - * @return const char * - */ - operator const char * () - { - return _text; - } - -private: - /** - * The actual pointer - * @var Type* - */ - Type *_pointer; - - /** - * The original text - * @var text - */ - const char *_text; - - /** - * Optional data buffer - * @var string - */ - std::string _data; - -}; - -/** - * End of namespace - */ -} - diff --git a/src/includes.h b/src/includes.h index 28d8b51..1a464e0 100644 --- a/src/includes.h +++ b/src/includes.h @@ -14,6 +14,8 @@ #include <string> #include <initializer_list> #include <vector> +#include <map> +#include <memory> // for debugging #include <iostream> @@ -31,12 +33,14 @@ /** * Include other files from this library */ +#include "../include/hiddenpointer.h" #include "../include/type.h" #include "../include/request.h" #include "../include/argument.h" #include "../include/value.h" #include "../include/member.h" #include "../include/arguments.h" +#include "../include/parameters.h" #include "../include/function.h" #include "../include/functions.h" #include "../include/extension.h" @@ -46,4 +50,3 @@ */ #include "callable.h" #include "arginfo.h" -#include "hiddenpointer.h" diff --git a/src/parameters.cpp b/src/parameters.cpp new file mode 100644 index 0000000..d31f49c --- /dev/null +++ b/src/parameters.cpp @@ -0,0 +1,39 @@ +/** + * Parameters.cpp + * + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2013 Copernica BV + */ +#include "includes.h" + +/** + * Set up namespace + */ +namespace Php { + +/** + * Parameters + * @param argc Number of arguments + * @param tsrm_ls + */ +Parameters::Parameters(int argc TSRMLS_DC) +{ + // reserve plenty of space + reserve(argc); + + // loop through the arguments + for (int i=0; i<argc; i++) + { + // get the argument + zval **arg = (zval **) (zend_vm_stack_top(TSRMLS_C) - 1 - (argc-i)); + + // append value + push_back(Value(*arg)); + } +} + +/** + * End of namespace + */ +} + diff --git a/src/value.cpp b/src/value.cpp index 9224162..f386822 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -29,7 +29,7 @@ /** * Set up namespace */ -namespace PhpCpp { +namespace Php { /** * Constructor (value = NULL) |