diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-08-26 13:08:39 +0200 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-08-26 13:08:39 +0200 |
commit | f526c4c7a7ada1ab534ca0976c7b66718b9a5660 (patch) | |
tree | 68b4db309ee00d3b7ebc1743b4825057b3db7f28 /include | |
parent | a286c34777e48d59410e7511f52f4a6f08000ba3 (diff) | |
parent | 97bc6757346d394a4b7d5898983be298e0b0ea98 (diff) |
fixed conflict
Diffstat (limited to 'include')
-rw-r--r-- | include/array.h | 10 | ||||
-rw-r--r-- | include/call.h | 15 | ||||
-rw-r--r-- | include/class.h | 30 | ||||
-rw-r--r-- | include/classbase.h | 4 | ||||
-rw-r--r-- | include/exception.h | 10 | ||||
-rw-r--r-- | include/extension.h | 16 | ||||
-rw-r--r-- | include/fatalerror.h | 66 | ||||
-rw-r--r-- | include/namespace.h | 37 | ||||
-rw-r--r-- | include/object.h | 28 | ||||
-rw-r--r-- | include/value.h | 58 |
10 files changed, 253 insertions, 21 deletions
diff --git a/include/array.h b/include/array.h index 0b6ceb9..4d6b6b1 100644 --- a/include/array.h +++ b/include/array.h @@ -31,7 +31,7 @@ public: Array(const Value &value) : Value(value) { // type must be valid - if (value.type() != Type::Array) throw Php::Exception("Assigning a non-array to an array variable"); + if (value.type() != Type::Array) throw FatalError("Assigning a non-array to an array variable"); } /** @@ -41,7 +41,7 @@ public: Array(Value &&value) : Value(std::move(value)) { // type must be valid - if (value.type() != Type::Array) throw Php::Exception("Moving a non-array to an array variable"); + if (value.type() != Type::Array) throw FatalError("Moving a non-array to an array variable"); } /** @@ -76,7 +76,7 @@ public: virtual Value &setType(Type type) override { // throw exception if things are going wrong - if (type != Type::Array) throw Php::Exception("Changing type of a fixed array variable"); + if (type != Type::Array) throw FatalError("Changing type of a fixed array variable"); // call base return Value::setType(Type::Array); @@ -93,7 +93,7 @@ public: if (this == &value) return *this; // type must be valid - if (value.type() != Type::Array) throw Php::Exception("Assigning a non-array to a fixed array variable"); + if (value.type() != Type::Array) throw FatalError("Assigning a non-array to a fixed array variable"); // call base Value::operator=(value); @@ -113,7 +113,7 @@ public: if (this == &value) return *this; // type must be valid - if (value.type() != Type::Array) throw Php::Exception("Moving a non-array to a fixed array variable"); + if (value.type() != Type::Array) throw FatalError("Moving a non-array to a fixed array variable"); // call base Value::operator=(std::move(value)); diff --git a/include/call.h b/include/call.h index 16de1fe..1a0c59f 100644 --- a/include/call.h +++ b/include/call.h @@ -13,6 +13,21 @@ namespace Php { /** + * List of functions that are available for use in PHP + */ +extern bool class_exists(const char *classname, size_t size, bool autoload = true); +inline bool class_exists(const char *classname, bool autoload = true) { return class_exists(classname, strlen(classname), autoload); } +inline bool class_exists(const std::string &classname, bool autoload = true) { return class_exists(classname.c_str(), classname.size(), autoload); } +extern Value eval(const std::string &phpCode); +inline bool is_a(const Value &obj, const char *classname, size_t size, bool allow_string = false) { return obj.instanceOf(classname, size, allow_string); } +inline bool is_a(const Value &obj, const char *classname, bool allow_string = false) { return is_a(obj, classname, strlen(classname), allow_string); } +inline bool is_a(const Value &obj, const std::string &classname, bool allow_string = false) { return is_a(obj, classname.c_str(), classname.size(), allow_string); } +inline bool is_subclass_of(const Value &obj, const char *classname, size_t size, bool allow_string = true) { return obj.derivedFrom(classname, size, allow_string); } +inline bool is_subclass_of(const Value &obj, const char *classname, bool allow_string = true) { return is_subclass_of(obj, classname, strlen(classname), allow_string); } +inline bool is_subclass_of(const Value &obj, const std::string &classname, bool allow_string = true) { return is_subclass_of(obj, classname.c_str(), classname.size(), allow_string); } + + +/** * Call a function in PHP * @param name Name of the function to call * @param params Variable number of parameters diff --git a/include/class.h b/include/class.h index e0316df..cffc7bd 100644 --- a/include/class.h +++ b/include/class.h @@ -202,13 +202,39 @@ public: private: /** + * Method to create the object if it is default constructable + * @param orig + * @return Base* + */ + template <typename X = T> + typename std::enable_if<std::is_default_constructible<X>::value, Base*>::type + static maybeConstruct() + { + // create a new instance + return new X(); + } + + /** + * Method to create the object if it is not default constructable + * @param orig + * @return Base* + */ + template <typename X = T> + typename std::enable_if<!std::is_default_constructible<X>::value, Base*>::type + static maybeConstruct() + { + // create empty instance + return nullptr; + } + + /** * Construct a new instance of the object * @return Base */ virtual Base* construct() const override { // construct an instance - return new T(); + return maybeConstruct<T>(); } /** @@ -225,7 +251,7 @@ private: } /** - * Method to clone the object if it is copy constructable + * Method to clone the object if it is not copy constructable * @param orig * @return Base* */ diff --git a/include/classbase.h b/include/classbase.h index a736c4e..9f0bac3 100644 --- a/include/classbase.h +++ b/include/classbase.h @@ -2,9 +2,9 @@ * ClassBase.h * * This is the base class of the "Class" class. This is an internal class that - * is used by the PHP-CPP library. But because the constructor is protected, + * is used by the PHP-CPP library. Because the constructor is protected, * you can not create any instances if this class yourself (and you are not - * supposed to do that either. + * supposed to do that either). * * Further more, because this base class is a 'private' base of Class, all * features of it are normally also inaccessible. diff --git a/include/exception.h b/include/exception.h index 671df9e..aff0afc 100644 --- a/include/exception.h +++ b/include/exception.h @@ -75,6 +75,16 @@ public: // yes, it is native return true; } + + /** + * Report this error as a fatal error + * @return bool + */ + virtual bool report() const + { + // this is not done here + return false; + } }; /** diff --git a/include/extension.h b/include/extension.h index f03c8fb..562fceb 100644 --- a/include/extension.h +++ b/include/extension.h @@ -111,6 +111,9 @@ public: */ Extension &add(Ini &&ini) { + // skip when locked + if (locked()) return *this; + // and add it to the list of classes _ini_entries.emplace_back(new Ini(std::move(ini))); @@ -125,6 +128,9 @@ public: */ Extension &add(const Ini &ini) { + // skip when locked + if (locked()) return *this; + // and add it to the list of classes _ini_entries.emplace_back(new Ini(ini)); @@ -180,6 +186,16 @@ public: { return module(); } + +protected: + /** + * Is the extension object in a locked state? This happens after the + * get_module() function was called for the first time ("apache reload" + * forces a new call to get_module()) + * + * @return bool + */ + virtual bool locked() const override; private: /** diff --git a/include/fatalerror.h b/include/fatalerror.h new file mode 100644 index 0000000..b178f25 --- /dev/null +++ b/include/fatalerror.h @@ -0,0 +1,66 @@ +/** + * FatalError.h + * + * + * Normally, fatal errors are reported with a call to zend_error(). + * + * However, this will trigger a longjmp(), which will cause objects + * constructed in the extension not to be destructed. We use therefore + * this FatalError class, which is a normally exception that _does_ + * cause objects to be destructed. + * + * When it is caught, right before control is handed back to the Zend + * engine, it will turn the exception into a zend_error() call and + * thus a longjmp. + * + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2014 Copernica BV + */ + +/** + * Set up namespace + */ +namespace Php { + +/** + * Class definition + */ +class FatalError : public Exception +{ +public: + /** + * Constructor + * @param message + */ + FatalError(const std::string &message) : Exception(message) {} + + /** + * Destructor + */ + virtual ~FatalError() throw() + { + } + + /** + * Is this a native exception (one that was thrown from C++ code) + * @return bool + */ + virtual bool native() const + { + // although it is native, we return 0 because it should not persist + // as exception, but it should live on as zend_error() in stead + return false; + } + + /** + * Report this error as a fatal error + * @return bool + */ + virtual bool report() const override; +}; + +/** + * End of namespace + */ +} + diff --git a/include/namespace.h b/include/namespace.h index 828c12c..e713850 100644 --- a/include/namespace.h +++ b/include/namespace.h @@ -48,6 +48,25 @@ protected: */ std::list<std::shared_ptr<Namespace>> _namespaces; + /** + * Is the object locked? + * + * After the object is locked, no more elements can be added to it. + * This happens after the call to get_module - it the no longer makes + * sense to add more objects. When 'apache reload' is executed, the + * get_module() function is called for a second (or third, or fourth) + * time, but the classes, functions and namespaces will then not be + * filled. + * + * @var bool + */ + virtual bool locked() const + { + // by default, namespaces are not locked (only derived extension + // objects can end up in a locked state + return false; + } + public: /** @@ -81,6 +100,9 @@ public: template<typename T> Namespace &add(Class<T> &&type) { + // skip when locked + if (locked()) return *this; + // make a copy of the object, and add it to the list of classes _classes.push_back(std::unique_ptr<ClassBase>(new Class<T>(std::move(type)))); @@ -96,6 +118,9 @@ public: template<typename T> Namespace &add(const Class<T> &type) { + // skip when locked + if (locked()) return *this; + // and add it to the list of classes _classes.push_back(std::unique_ptr<ClassBase>(new Class<T>(type))); @@ -110,6 +135,9 @@ public: */ Namespace &add(Interface &&interface) { + // skip when locked + if (locked()) return *this; + // make a copy and add it to the list of classes _classes.push_back(std::unique_ptr<ClassBase>(new Interface(std::move(interface)))); @@ -124,6 +152,9 @@ public: */ Namespace &add(const Interface &interface) { + // skip when locked + if (locked()) return *this; + // make a copy and add it to the list of classes _classes.push_back(std::unique_ptr<ClassBase>(new Interface(interface))); @@ -138,6 +169,9 @@ public: */ Namespace &add(Namespace &&ns) { + // skip when locked + if (locked()) return *this; + // add it to the list of namespaces _namespaces.push_back(std::unique_ptr<Namespace>(new Namespace(std::move(ns)))); @@ -152,6 +186,9 @@ public: */ Namespace &add(const Namespace &ns) { + // skip when locked + if (locked()) return *this; + // make a copy and add it to the list of namespaces _namespaces.push_back(std::unique_ptr<Namespace>(new Namespace(ns))); diff --git a/include/object.h b/include/object.h index 97c9482..6350259 100644 --- a/include/object.h +++ b/include/object.h @@ -31,7 +31,7 @@ public: Object(Value &&value) : Value(std::move(value)) { // throw exception in case of problems - if (value.type() != Type::Object) throw Php::Exception("Constructing an object variable by moving a non object"); + if (value.type() != Type::Object) throw FatalError("Constructing an object variable by moving a non object"); } /** @@ -41,11 +41,21 @@ public: */ Object(const Value &value) : Value() { - // string types are instantiated - if (value.isString()) instantiate(value); - - // otherwise copy the other object - else operator=(value); + // when a string is passed in, we are going to make a new instance of the + // passed in string + if (value.isString()) + { + // instantiate the object + instantiate(value); + + // and call the __construct method + call("__construct"); + } + else + { + // this simply copies the other object + operator=(value); + } } /** @@ -123,7 +133,7 @@ public: virtual Value &setType(Type type) override { // throw exception if things are going wrong - if (type != Type::Object) throw Php::Exception("Changing type of a fixed object variable"); + if (type != Type::Object) throw FatalError("Changing type of a fixed object variable"); // call base return Value::setType(type); @@ -140,7 +150,7 @@ public: if (this == &value) return *this; // type must be valid - if (value.type() != Type::Object) throw Php::Exception("Assigning a non-object to an object variable"); + if (value.type() != Type::Object) throw FatalError("Assigning a non-object to an object variable"); // call base Value::operator=(value); @@ -160,7 +170,7 @@ public: if (this == &value) return *this; // type must be valid - if (value.type() != Type::Object) throw Php::Exception("Moving a non-object to an object variable"); + if (value.type() != Type::Object) throw FatalError("Moving a non-object to an object variable"); // call base Value::operator=(std::move(value)); diff --git a/include/value.h b/include/value.h index c6b1af9..2fe940a 100644 --- a/include/value.h +++ b/include/value.h @@ -100,7 +100,7 @@ public: * @param value */ template <typename T> - Value(const std::map<std::string,T> &value) + Value(const std::map<std::string,T> &value) : Value(Type::Array) { // set all elements for (auto &iter : value) setRaw(iter.first.c_str(), iter.first.size(), iter.second); @@ -322,6 +322,17 @@ public: bool operator> (const char *value) const { return ::strcmp(rawValue(), value) > 0; } /** + * Comparison operators for hardcoded Value + * @param value + */ + bool operator==(const Value &value) const; + bool operator!=(const Value &value) const { return !operator==(value); } + bool operator< (const Value &value) const; + bool operator> (const Value &value) const { return value.operator<(*this); } + bool operator<=(const Value &value) const { return !operator>(value); } + bool operator>=(const Value &value) const { return !operator<(value); } + + /** * Comparison operators * @param value */ @@ -376,7 +387,7 @@ public: * variables - other variables return nullptr. * * If you are going to write to the buffer, make sure that you first call - * the resize() method to ensure that the buffer is big enough. + * the reserve() method to ensure that the buffer is big enough. * * @return char * */ @@ -385,7 +396,7 @@ public: /** * Resize buffer space. If you want to write directly to the buffer (which * is returned by the buffer() method), you should first reserve enough - * space in it. This can be done with this resize() method. This will also + * space in it. This can be done with this reserve() method. This will also * turn the Value object into a string (if it was not already a string). * The writable buffer is returned. * @@ -489,6 +500,9 @@ public: // result variable std::map<std::string,T> result; + + // loop through the original map, and copy everything to the result + for (auto &iter : map) result[iter.first] = iter.second; // done return result; @@ -951,6 +965,37 @@ public: // try casting it return dynamic_cast<T*>(base); } + + /** + * Check whether this object is an instance of a certain class + * + * If you set the parameter 'allowString' to true, and the Value object + * holds a string, the string will be treated as class name. + * + * @param classname The class of which this should be an instance + * @param size Length of the classname string + * @param allowString Is it allowed for 'this' to be a string + * @return bool + */ + bool instanceOf(const char *classname, size_t size, bool allowString = false) const; + bool instanceOf(const char *classname, bool allowString = false) const { return instanceOf(classname, strlen(classname), allowString); } + bool instanceOf(const std::string &classname, bool allowString = false) const { return instanceOf(classname.c_str(), classname.size(), allowString); } + + /** + * Check whether this object is derived from a certain class. + * + * If you set the parameter 'allowString' to true, and the Value object + * holds a string, the string will be treated as class name. + * + * @param classname The class of which this should be an instance + * @param size Length of the classname string + * @param allowString Is it allowed for 'this' to be a string + * @return bool + */ + bool derivedFrom(const char *classname, size_t size, bool allowString = false) const; + bool derivedFrom(const char *classname, bool allowString = false) const { return derivedFrom(classname, strlen(classname), allowString); } + bool derivedFrom(const std::string &classname, bool allowString = false) const { return derivedFrom(classname.c_str(), classname.size(), allowString); } + private: /** @@ -1036,6 +1081,13 @@ protected: iterator createIterator(bool begin) const; /** + * Retrieve the class entry + * @param allowString Allow the 'this' object to be a string + * @return zend_class_entry + */ + struct _zend_class_entry *classEntry(bool allowString = true) const; + + /** * The Globals and Member classes can access the zval directly */ friend class Globals; |