diff options
-rw-r--r-- | include/class.h | 14 | ||||
-rw-r--r-- | include/constant.h | 75 | ||||
-rw-r--r-- | include/namespace.h | 50 | ||||
-rw-r--r-- | include/value.h | 1 | ||||
-rw-r--r-- | phpcpp.h | 1 | ||||
-rw-r--r-- | zend/constant.cpp | 85 | ||||
-rw-r--r-- | zend/constantimpl.h | 171 | ||||
-rw-r--r-- | zend/extensionimpl.cpp | 14 | ||||
-rw-r--r-- | zend/extensionimpl.h | 5 | ||||
-rw-r--r-- | zend/includes.h | 2 | ||||
-rw-r--r-- | zend/namespace.cpp | 25 |
11 files changed, 433 insertions, 10 deletions
diff --git a/include/class.h b/include/class.h index e11074c..2c875fa 100644 --- a/include/class.h +++ b/include/class.h @@ -91,12 +91,16 @@ public: /** * Add a static method to a class * - * In C++ a static method is just a plain function, that only at compile - * time has access to the private variables. You can therefore also supply - * global functions as static method, and real static methods (that do not - * even have to come from the same class. + * In C++ a static method is in reality just a plain function, that at + * compile time has access to private properties of the class that it is a + * static member of. * - * In PHP scripts, the function will only be callable as real static method + * Because a C++ static method is not a real method with a 'this' pointer, + * it has the same signature as a normal C++ (non-method) function. Therefore, + * you can register real static member functions (&MyClass::myMethod) as well + * as normal functions (myFunction) as class methods. + * + * In PHP scripts, such functions will be callable as static class methods * * @param name Name of the method * @param method The actual method diff --git a/include/constant.h b/include/constant.h new file mode 100644 index 0000000..619ce46 --- /dev/null +++ b/include/constant.h @@ -0,0 +1,75 @@ +/** + * Constant.h + * + * If you want to define global PHP constants, or class constants you can + * use this constant class for it. Wrap the constant you'd like to create + * in a Php::Constant object and add it to the extension or the class: + * + * extension.add(Php::Constant("CONSTANT_NAME", "value")); + * myclass.add(Php::Constant("CLASS_CONSTANT", "value")); + * + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2015 Copernica BV + */ + +/** + * Set up namespace + */ +namespace Php { + +/** + * Forward declarations + */ +class ConstantImpl; + +/** + * Class definition + */ +class Constant +{ +public: + /** + * Constructor + * @param name Constant name + * @param value Constant value + * @param size Size of the value (in case of a string) + */ + Constant(const char *name, std::nullptr_t value = nullptr); + Constant(const char *name, bool value); + Constant(const char *name, int32_t value); + Constant(const char *name, int64_t value); + Constant(const char *name, double value); + Constant(const char *name, const char *value); + Constant(const char *name, const char *value, size_t size); + Constant(const char *name, const std::string &value); + + /** + * Destructor + */ + virtual ~Constant() {} + +private: + /** + * Pointer to the actual implementation of the constant + * @var std::shared_ptr + */ + std::shared_ptr<ConstantImpl> _impl; + + /** + * Get access to the implementation object + * @return std::shared_ptr + */ + const std::shared_ptr<ConstantImpl> &implementation() const { return _impl; } + + /** + * The extension object has access to privates + */ + friend class ExtensionImpl; + +}; + +/** + * End of namespace + */ +} + diff --git a/include/namespace.h b/include/namespace.h index 84f0740..4bb23db 100644 --- a/include/namespace.h +++ b/include/namespace.h @@ -43,6 +43,12 @@ protected: std::list<std::shared_ptr<ClassBase>> _classes; /** + * Constants defined in the namespace + * @var list + */ + std::list<std::shared_ptr<Constant>> _constants; + + /** * Namespaces defined inside the namespace * @var list */ @@ -163,6 +169,40 @@ public: } /** + * Add a constant to the namespace + * @param constant The constant to add + * @return Namespace Same object to allow chaining + */ + Namespace &add(Constant &&constant) + { + // skip when locked + if (locked()) return *this; + + // and add it to the list of constants + _constants.push_back(std::unique_ptr<Constant>(new Constant(std::move(constant)))); + + // allow chaining + return *this; + } + + /** + * Add a constant to the namespace + * @param constant The constant to add + * @return Namespace Same object to allow chaining + */ + Namespace &add(const Constant &constant) + { + // skip when locked + if (locked()) return *this; + + // and add it to the list of constants + _constants.push_back(std::unique_ptr<Constant>(new Constant(constant))); + + // allow chaining + return *this; + } + + /** * Add a namespace to the namespace by moving it * @param ns The namespace * @return Namespace Same object to allow chaining @@ -231,6 +271,16 @@ public: * @param callback */ void classes(const std::function<void(const std::string &ns, ClassBase &clss)> &callback); + + /** + * Apply a callback to each registered constant + * + * The callback will be called with the name of the namespace, and + * a reference to the registered constant + * + * @param callback + */ + void constants(const std::function<void(const std::string &ns, Constant &constant)> &callback); }; diff --git a/include/value.h b/include/value.h index c3de4d5..a450755 100644 --- a/include/value.h +++ b/include/value.h @@ -1171,6 +1171,7 @@ protected: friend class HashMember<std::string>; friend class Callable; friend class Script; + friend class ConstantImpl; }; /** @@ -59,6 +59,7 @@ #include <phpcpp/classbase.h> #include <phpcpp/interface.h> #include <phpcpp/class.h> +#include <phpcpp/constant.h> #include <phpcpp/namespace.h> #include <phpcpp/extension.h> #include <phpcpp/call.h> diff --git a/zend/constant.cpp b/zend/constant.cpp new file mode 100644 index 0000000..83a4de0 --- /dev/null +++ b/zend/constant.cpp @@ -0,0 +1,85 @@ +/** + * Constant.cpp + * + * Implementation file for the constant class + * + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2015 Copernica BV + */ +#include "includes.h" + +/** + * Set up namespace + */ +namespace Php { + +/** + * Constructor + * @param name Constant name + * @param value Constant value + */ +Constant::Constant(const char *name, std::nullptr_t value) : + _impl(new ConstantImpl(name, value)) {} + +/** + * Constructor + * @param name Constant name + * @param value Constant value + */ +Constant::Constant(const char *name, bool value) : + _impl(new ConstantImpl(name, value)) {} + +/** + * Constructor + * @param name Constant name + * @param value Constant value + */ +Constant::Constant(const char *name, int32_t value) : + _impl(new ConstantImpl(name, value)) {} + +/** + * Constructor + * @param name Constant name + * @param value Constant value + */ +Constant::Constant(const char *name, int64_t value) : + _impl(new ConstantImpl(name, value)) {} + +/** + * Constructor + * @param name Constant name + * @param value Constant value + */ +Constant::Constant(const char *name, double value) : + _impl(new ConstantImpl(name, value)) {} + +/** + * Constructor + * @param name Constant name + * @param value Constant value + */ +Constant::Constant(const char *name, const char *value) : + _impl(new ConstantImpl(name, value)) {} + +/** + * Constructor + * @param name Constant name + * @param value Constant value + * @param size Value size + */ +Constant::Constant(const char *name, const char *value, size_t size) : + _impl(new ConstantImpl(name, value, size)) {} + +/** + * Constructor + * @param name Constant name + * @param value Constant value + */ +Constant::Constant(const char *name, const std::string &value) : + _impl(new ConstantImpl(name, value)) {} + +/** + * End of namespace + */ +} + diff --git a/zend/constantimpl.h b/zend/constantimpl.h new file mode 100644 index 0000000..bf2ac25 --- /dev/null +++ b/zend/constantimpl.h @@ -0,0 +1,171 @@ +/** + * ConstantImpl.h + * + * Implementation file for the constant class + * + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2015 Copernica BV + */ + +/** + * Set up namespace + */ +namespace Php { + +/** + * Class definition + */ +class ConstantImpl +{ +public: + /** + * Constructor + * @param name + * @param value + */ + ConstantImpl(const char *name, std::nullptr_t value = nullptr) : _name(name) + { + // initialize the zval + ZVAL_NULL(&_constant.value); + } + + /** + * Constructor + * @param name + * @param value + */ + ConstantImpl(const char *name, bool value) : _name(name) + { + // initialize the zval + ZVAL_BOOL(&_constant.value, value); + } + + /** + * Constructor + * @param name + * @param value + */ + ConstantImpl(const char *name, int32_t value) : _name(name) + { + // initialize the zval + ZVAL_LONG(&_constant.value, value); + } + + /** + * Constructor + * @param name + * @param value + */ + ConstantImpl(const char *name, int64_t value) : _name(name) + { + // initialize the zval + ZVAL_LONG(&_constant.value, value); + } + + /** + * Constructor + * @param name + * @param value + */ + ConstantImpl(const char *name, double value) : _name(name) + { + // initialize the zval + ZVAL_DOUBLE(&_constant.value, value); + } + + /** + * Constructor + * @param name + * @param value + * @param len + */ + ConstantImpl(const char *name, const char *value, size_t len) : _name(name) + { + // initialize the zval + ZVAL_STRINGL(&_constant.value, value, len, 0); + } + + /** + * Constructor + * @param name + * @param value + */ + ConstantImpl(const char *name, const char *value) : _name(name) + { + // initialize the zval + ZVAL_STRINGL(&_constant.value, value, ::strlen(value), 0); + } + + /** + * Constructor + * @param name + * @param value + */ + ConstantImpl(const char *name, const std::string &value) : _name(name) + { + // initialize the zval + ZVAL_STRINGL(&_constant.value, value.c_str(), value.size(), 0); + } + + /** + * Destructor + */ + virtual ~ConstantImpl() {} + + /** + * Initialize the constant + * @param prefix Namespace prefix + * @param module_number The module number + * @param tsrmls Optional parameter when running in multi-threading context + */ + void initialize(const std::string &prefix, int module_number TSRMLS_DC) + { + // is there a namespace name involved? + if (prefix.size() > 0) + { + // size of the name + auto namelen = ::strlen(_name); + + // include prefix in the full name (name_len should include '\0') + _constant.name_len = prefix.size() + 1 + namelen + 1; + _constant.name = (char *)emalloc(_constant.name_len); + + // copy the entire namespace name, separator and constant name + ::strncpy(_constant.name, prefix.c_str(), prefix.size()); + ::strncpy(_constant.name + prefix.size(), "\\", 1); + ::strncpy(_constant.name + prefix.size() + 1, _name, namelen + 1); + } + else + { + // no namespace, we simply copy the name (name_len should include '\0') + _constant.name_len = ::strlen(_name) + 1; + _constant.name = zend_strndup(_name, _constant.name_len - 1); + } + + // set all the other constant properties + _constant.flags = CONST_CS | CONST_PERSISTENT; + _constant.module_number = module_number; + + // register the zval + zend_register_constant(&_constant TSRMLS_CC); + } + +private: + /** + * Name of the constant + * @var const char * + */ + const char *_name; + + /** + * The zend_constant structure + * @var zend_constant + */ + zend_constant _constant; +}; + +/** + * End of namespace + */ +} + diff --git a/zend/extensionimpl.cpp b/zend/extensionimpl.cpp index fd97a76..47b4419 100644 --- a/zend/extensionimpl.cpp +++ b/zend/extensionimpl.cpp @@ -140,7 +140,7 @@ int ExtensionImpl::processStartup(int type, int module_number TSRMLS_DC) zend_register_ini_entries(entries, module_number TSRMLS_CC); // initialize the extension - extension->initialize(TSRMLS_C); + extension->initialize(module_number TSRMLS_CC); // remember that we're initialized (when you use "apache reload" it is // possible that the processStartup() method is called more than once) @@ -379,11 +379,19 @@ zend_module_entry *ExtensionImpl::module() /** * Initialize the extension after it was started + * @param module_number * @param tsrm_ls */ -void ExtensionImpl::initialize(TSRMLS_D) +void ExtensionImpl::initialize(int module_number TSRMLS_DC) { - // we need to register each class, find out all classes + // the constants are registered after the module is ready + _data->constants([module_number TSRMLS_CC](const std::string &prefix, Constant &c) { + + // forward to implementation class + c.implementation()->initialize(prefix, module_number TSRMLS_CC); + }); + + // we also need to register each class, find out all classes _data->classes([TSRMLS_C](const std::string &prefix, ClassBase &c) { // forward to implementation class diff --git a/zend/extensionimpl.h b/zend/extensionimpl.h index 0a366ba..83deb36 100644 --- a/zend/extensionimpl.h +++ b/zend/extensionimpl.h @@ -104,10 +104,11 @@ public: private: /** * Initialize the namespace after it was registered + * @param module_number * @param tsrm_ls */ - void initialize(TSRMLS_D); - + void initialize(int module_number TSRMLS_DC); + /** * Function that is called when the extension initializes * @param type Module type diff --git a/zend/includes.h b/zend/includes.h index fb14b87..e4dd6b9 100644 --- a/zend/includes.h +++ b/zend/includes.h @@ -78,6 +78,7 @@ #include "../include/classbase.h" #include "../include/interface.h" #include "../include/class.h" +#include "../include/constant.h" #include "../include/namespace.h" #include "../include/extension.h" #include "../include/call.h" @@ -121,6 +122,7 @@ #include "executestate.h" #include "opcodes.h" #include "functor.h" +#include "constantimpl.h" #ifndef ZVAL_COPY_VALUE #define ZVAL_COPY_VALUE(z, v) \ diff --git a/zend/namespace.cpp b/zend/namespace.cpp index 893f2f0..575becf 100644 --- a/zend/namespace.cpp +++ b/zend/namespace.cpp @@ -140,6 +140,31 @@ void Namespace::classes(const std::function<void(const std::string &ns, ClassBas } /** + * Apply a callback to each registered constant + * + * The callback will be called with the name of the namespace, and + * a reference to the registered constant + * + * @param callback + */ +void Namespace::constants(const std::function<void(const std::string &ns, Constant &constant)> &callback) +{ + // loop through the constants, and apply the callback + for (auto &c : _constants) callback(_name, *c); + + // loop through the other namespaces + for (auto &ns : _namespaces) ns->constants([this, callback](const std::string &ns, Constant &constant) { + + // if this is the root namespace, we don't have to change the prefix + if (_name.size() == 0) return callback(ns, constant); + + // construct a new prefix + // @todo this could be slightly inefficient + return callback(_name + "\\" + ns, constant); + }); +} + +/** * End namespace */ } |