diff options
-rw-r--r-- | include/base.h | 14 | ||||
-rw-r--r-- | include/class.h | 16 | ||||
-rw-r--r-- | include/classbase.h | 16 | ||||
-rw-r--r-- | include/interface.h | 12 | ||||
-rw-r--r-- | include/type.h | 2 | ||||
-rw-r--r-- | src/base.cpp | 22 | ||||
-rw-r--r-- | src/classbase.cpp | 51 |
7 files changed, 131 insertions, 2 deletions
diff --git a/include/base.h b/include/base.h index 6541549..e99023b 100644 --- a/include/base.h +++ b/include/base.h @@ -218,6 +218,20 @@ public: * @return bool */ virtual bool __toBool(); + + /** + * Compare the object with a different object of the same type + * + * This method should return 0 if both objects are equal, a negative value + * if the 'this' object is smaller, and a positive value if the 'this' + * object is bigger. + * + * The passed in object is an instance of base + * + * @param that Object to compare with + * @return int + */ + virtual bool __compare(const Base &that) const; private: diff --git a/include/class.h b/include/class.h index 6bcefda..eabcec6 100644 --- a/include/class.h +++ b/include/class.h @@ -185,6 +185,22 @@ private: } /** + * Compare two objects + * @param object1 + * @param object2 + * @return int + */ + virtual int compare(Base *object1, Base *object2) const override + { + // cast to the actual implementation type + T *t1 = (T *)object1; + T *t2 = (T *)object2; + + // compare the two objects + return t1->__compare(*t2); + } + + /** * Namespaces have access to the private base class */ friend class Namespace; diff --git a/include/classbase.h b/include/classbase.h index da027ab..01f1d55 100644 --- a/include/classbase.h +++ b/include/classbase.h @@ -108,6 +108,14 @@ public: virtual Base *clone(Base *orig) const = 0; /** + * Compare two objects + * @param object1 + * @param object2 + * @return int + */ + virtual int compare(Base *object1, Base *object2) const = 0; + + /** * Is this a traversable class? * @return bool */ @@ -383,6 +391,14 @@ private: static int cast(struct _zval_struct *object, struct _zval_struct *retval, int type); /** + * Function to compare two objects + * @param object1 + * @param object2 + * @return int + */ + static int compare(struct _zval_struct *object1, struct _zval_struct *object2); + + /** * Name of the class * @var string */ diff --git a/include/interface.h b/include/interface.h index bdff75d..52d1a97 100644 --- a/include/interface.h +++ b/include/interface.h @@ -71,6 +71,18 @@ private: } /** + * Compare two objects + * @param object1 + * @param object2 + * @return int + */ + virtual int compare(Base *object1, Base *object2) const override + { + // this is never called for interfaces + return 0; + } + + /** * Namespaces have access to the private base class */ friend class Namespace; diff --git a/include/type.h b/include/type.h index e5ebeda..bec0fd5 100644 --- a/include/type.h +++ b/include/type.h @@ -21,7 +21,7 @@ enum class Type : unsigned char { Null = 0, Numeric = 1, Float = 2, - Boolean = 3, + Bool = 3, Array = 4, Object = 5, String = 6, diff --git a/src/base.cpp b/src/base.cpp index a9faac3..a77b30f 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -256,6 +256,28 @@ bool Base::__toBool() } /** + * Compare the object with a different object of the same type + * + * This method should return 0 if both objects are equal, a negative value + * if the 'this' object is smaller, and a positive value if the 'this' + * object is bigger. + * + * The passed in object is an instance of base + * + * @param that Object to compare with + * @return int + */ +bool Base::__compare(const Base &that) const +{ + // throw an exception that will be caught in the ClassBase class, + // so that the default implementation of the function can be called + throw NotImplemented(); + + // unreachable code + return 1; +} + +/** * End namespace */ } diff --git a/src/classbase.cpp b/src/classbase.cpp index 460bae3..f7d8d94 100644 --- a/src/classbase.cpp +++ b/src/classbase.cpp @@ -285,6 +285,9 @@ zend_object_handlers *ClassBase::objectHandlers() // handler to cast to a different type handlers.cast_object = &ClassBase::cast; + // method to compare two objects + handlers.compare_objects = &ClassBase::compare; + // remember that object is now initialized initialized = true; @@ -293,6 +296,52 @@ zend_object_handlers *ClassBase::objectHandlers() } /** + * Function to compare two objects + * @param object1 + * @param object2 + * @return int + */ +int ClassBase::compare(zval *object1, zval *object2) +{ + // prevent exceptions + try + { + // retrieve the class entry linked to this object + auto *entry = zend_get_class_entry(object1); + + // other object must be of the same type + if (entry != zend_get_class_entry(object2)) throw NotImplemented(); + + // we need the C++ class meta-information object + ClassBase *meta = cpp_class(entry); + + // get the base objects + Base *base1 = cpp_object(object1); + Base *base2 = cpp_object(object2); + + // run the compare method + return meta->compare(base1, base2); + } + catch (const NotImplemented &exception) + { + // it was not implemented, do we have a default? + if (!std_object_handlers.compare_objects) return 1; + + // call default + return std_object_handlers.compare_objects(object1, object2); + } + catch (Exception &exception) + { + // a Php::Exception was thrown by the extension __compare function, + // pass this on to user space + exception.process(); + + // what shall we return here... + return 1; + } +} + +/** * Function to cast the object to a different type * @param object * @param retval @@ -343,7 +392,7 @@ int ClassBase::cast(zval *object, zval *retval, int type) catch (const NotImplemented &exception) { // is there a default? - if (std_object_handlers.cast_object) return FAILURE; + if (!std_object_handlers.cast_object) return FAILURE; // call default return std_object_handlers.cast_object(object, retval, type); |