summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-07-26 17:00:10 +0200
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-07-26 17:00:10 +0200
commit3f1d5ca94f721cf7feff0fc9cb05a5c1b6d39873 (patch)
treefe166c06985a968e255cc9ca1687c24704c69c42
parent542e8a44708668001e59cf08b61c642da5080825 (diff)
added Value::subclassOf(), and implemented Php::is_a() and Php::is_subclass_of()
-rw-r--r--include/call.h7
-rw-r--r--include/fastcall.h18
-rw-r--r--include/value.h45
-rw-r--r--zend/value.cpp119
4 files changed, 129 insertions, 60 deletions
diff --git a/include/call.h b/include/call.h
index e1bb12d..dff815c 100644
--- a/include/call.h
+++ b/include/call.h
@@ -19,6 +19,13 @@ extern bool class_exists(const char *classname, size_t size, bool autoload = tr
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.subclassOf(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
diff --git a/include/fastcall.h b/include/fastcall.h
deleted file mode 100644
index 778a9b2..0000000
--- a/include/fastcall.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * fastcall.h
- *
- * This file holds some PHP functions implementation in C directly.
- *
- */
-
-namespace Php {
-
- inline bool is_a(const Value &obj, const std::string classname, bool allow_string = false) {
- return obj.is(classname, allow_string);
- }
- inline bool is_subclass_of(const Value &obj, const std::string classname, bool allow_string = true) {
- return obj.isSubClassOf(classname, allow_string);
- }
-
-}
-
diff --git a/include/value.h b/include/value.h
index b3c288c..e6b8d69 100644
--- a/include/value.h
+++ b/include/value.h
@@ -964,29 +964,39 @@ public:
// try casting it
return dynamic_cast<T*>(base);
}
-
+
/**
- * Checks if this object is of the class or has the class as one of its parents
- * @param classname
- * @param allow_string
+ * 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
*/
- inline bool is(const std::string &classname, bool allow_string=false) const {
- return isImpl(classname, allow_string, false);
- }
+ 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); }
/**
- * Checks if this object has the class as one of its parents
- * @param classname
+ * 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
*/
- inline bool isSubClassOf(const std::string &classname, bool allow_string=true) const {
- return isImpl(classname, allow_string, true);
- }
+ bool subclassOf(const char *classname, size_t size, bool allowString = false) const;
+ bool subclassOf(const char *classname, bool allowString = false) const { return subclassOf(classname, strlen(classname), allowString); }
+ bool subclassOf(const std::string &classname, bool allowString = false) const { return subclassOf(classname.c_str(), classname.size(), allowString); }
-private:
- bool isImpl(const std::string &classname, bool allow_string, bool only_subclass) const;
+private:
/**
* Call function with a number of parameters
* @param argc Number of parameters
@@ -1070,6 +1080,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;
diff --git a/zend/value.cpp b/zend/value.cpp
index 9b409f7..9258dbd 100644
--- a/zend/value.cpp
+++ b/zend/value.cpp
@@ -1408,42 +1408,105 @@ bool Value::isCallable() const
return zend_is_callable(_val, 0, NULL TSRMLS_CC);
}
-bool Value::isImpl(const std::string &classname, bool allow_string, bool only_subclass) const {
- /*
- * allow_string - is default is false, isSubclassOf is true.
- * if it's allowed, the the autoloader will be called if the class does not exist.
- * default behaviour is different, as 'is' used to be used to test mixed return
- * values and there is no easy way to deprecate this.
- */
+/**
+ * Retrieve the class entry
+ * @param allowString
+ * @return zend_class_entry
+ */
+zend_class_entry Value::classEntry(bool allowString) const
+{
// we need the tsrm_ls variable
TSRMLS_FETCH();
- zend_class_entry *instance_ce;
- zend_class_entry **ce;
-
- if (allow_string && isString()) {
- zend_class_entry **the_ce;
- if (zend_lookup_class(Z_STRVAL_P(_val), Z_STRLEN_P(_val), &the_ce TSRMLS_CC) == FAILURE) {
- return false;
- }
- instance_ce = *the_ce;
- }
- else if (isObject() && HAS_CLASS_ENTRY(*_val)) {
- instance_ce = Z_OBJCE_P(_val);
+ // the class-entry of 'this'
+ zend_class_entry *this_entry;
+
+ // is this an object
+ if (isObject())
+ {
+ // should have a class entry
+ if (!HAS_CLASS_ENTRY(*_val)) return nullptr;
+
+ // class entry can be easily found
+ return Z_OBJCE_P(_val);
}
- else {
- return false;
+ else
+ {
+ // the value is not an object, is this allowed?
+ if (!allowString || !isString()) return nullptr;
+
+ // temporary variable
+ zend_class_entry **ce;
+
+ // find the class entry
+ if (zend_lookup_class(Z_STRVAL_P(_val), Z_STRLEN_P(_val), &ce TSRMLS_CC) == FAILURE) return return;
+
+ // found the entry
+ return *ce;
}
+}
- if (zend_lookup_class_ex(classname.c_str(), (int32_t)classname.length(), NULL, 0, &ce TSRMLS_CC) == FAILURE) {
- return false;
- }
+/**
+ * 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 Value::instanceOf(const char *classname, size_t size, bool allowString) const
+{
+ // we need the tsrm_ls variable
+ TSRMLS_FETCH();
- if (only_subclass && instance_ce == *ce) {
- return false;
- }
+ // the class-entry of 'this'
+ zend_class_entry *this_ce = classEntry(allowString);
+ if (!this_ce) return false;
+
+ // class entry of the parameter
+ zend_class_entry **ce;
+
+ // now we can look up the actual class
+ if (zend_lookup_class_ex(classname, size, NULL, 0, &ce TSRMLS_CC) == FAILURE) return false;
+
+ // check if this is a subclass
+ return instanceof_function(this_ce, *ce TSRMLS_CC);
+}
+
+/**
+ * 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 Value::subclassOf(const char *classname, size_t size, bool allowString) const
+{
+ // we need the tsrm_ls variable
+ TSRMLS_FETCH();
- return instanceof_function(instance_ce, *ce TSRMLS_CC);
+ // the class-entry of 'this'
+ zend_class_entry *this_ce = classEntry(allowString);
+ if (!this_ce) return false;
+
+ // class entry of the parameter
+ zend_class_entry **ce;
+
+ // now we can look up the actual class
+ if (zend_lookup_class_ex(classname, size, NULL, 0, &ce TSRMLS_CC) == FAILURE) return false;
+
+ // should not be identical, it must be a real derived object
+ if (this_ce == *ce) return false;
+
+ // check if this is a subclass
+ return instanceof_function(this_ce, *ce TSRMLS_CC);
}
/**