diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-07-26 17:00:10 +0200 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-07-26 17:00:10 +0200 |
commit | 3f1d5ca94f721cf7feff0fc9cb05a5c1b6d39873 (patch) | |
tree | fe166c06985a968e255cc9ca1687c24704c69c42 | |
parent | 542e8a44708668001e59cf08b61c642da5080825 (diff) |
added Value::subclassOf(), and implemented Php::is_a() and Php::is_subclass_of()
-rw-r--r-- | include/call.h | 7 | ||||
-rw-r--r-- | include/fastcall.h | 18 | ||||
-rw-r--r-- | include/value.h | 45 | ||||
-rw-r--r-- | zend/value.cpp | 119 |
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); } /** |