summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2013-09-08 16:26:11 -0700
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2013-09-08 16:26:11 -0700
commitdf2520e4b2c87e2302ee4c6cec1e672091efebfb (patch)
treef3bcd4fa7c4d0c6ee601268ceca4d6841ed90d0d /src
parenteb86ac350756afeffa0e2db8be87876d35bc40a8 (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.h2
-rw-r--r--src/argument.cpp74
-rw-r--r--src/arguments.cpp46
-rw-r--r--src/callable.cpp4
-rw-r--r--src/callable.h2
-rw-r--r--src/extension.cpp130
-rw-r--r--src/function.cpp76
-rw-r--r--src/functions.cpp54
-rw-r--r--src/hiddenpointer.h166
-rw-r--r--src/includes.h5
-rw-r--r--src/parameters.cpp39
-rw-r--r--src/value.cpp2
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)