summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-08-26 13:08:39 +0200
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-08-26 13:08:39 +0200
commitf526c4c7a7ada1ab534ca0976c7b66718b9a5660 (patch)
tree68b4db309ee00d3b7ebc1743b4825057b3db7f28 /include
parenta286c34777e48d59410e7511f52f4a6f08000ba3 (diff)
parent97bc6757346d394a4b7d5898983be298e0b0ea98 (diff)
fixed conflict
Diffstat (limited to 'include')
-rw-r--r--include/array.h10
-rw-r--r--include/call.h15
-rw-r--r--include/class.h30
-rw-r--r--include/classbase.h4
-rw-r--r--include/exception.h10
-rw-r--r--include/extension.h16
-rw-r--r--include/fatalerror.h66
-rw-r--r--include/namespace.h37
-rw-r--r--include/object.h28
-rw-r--r--include/value.h58
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;