summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/class.h14
-rw-r--r--include/constant.h75
-rw-r--r--include/namespace.h50
-rw-r--r--include/value.h1
-rw-r--r--phpcpp.h1
-rw-r--r--zend/constant.cpp85
-rw-r--r--zend/constantimpl.h171
-rw-r--r--zend/extensionimpl.cpp14
-rw-r--r--zend/extensionimpl.h5
-rw-r--r--zend/includes.h2
-rw-r--r--zend/namespace.cpp25
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;
};
/**
diff --git a/phpcpp.h b/phpcpp.h
index b5216ff..1d7abc0 100644
--- a/phpcpp.h
+++ b/phpcpp.h
@@ -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
*/
}