summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/base.h41
-rw-r--r--include/classbase.h9
-rw-r--r--include/type.h2
-rw-r--r--src/base.cpp72
-rw-r--r--src/classbase.cpp69
5 files changed, 192 insertions, 1 deletions
diff --git a/include/base.h b/include/base.h
index ed6936d..6541549 100644
--- a/include/base.h
+++ b/include/base.h
@@ -179,6 +179,47 @@ public:
*/
virtual Value __invoke(Parameters &params);
+ /**
+ * Cast the object to a string
+ *
+ * This method is called when an object is casted to a string, or when
+ * it is used in a string context
+ *
+ * @return Value The object as a string
+ */
+ virtual Value __toString();
+
+ /**
+ * Cast the object to an integer
+ *
+ * This method is called when an object is casted to an integer, or when
+ * it is used in an integer context
+ *
+ * @return int Integer value
+ */
+ virtual long __toInteger();
+
+ /**
+ * Cast the object to a float
+ *
+ * This method is called when an object is casted to a float, or when it
+ * is used in a float context
+ *
+ * @return double Floating point value
+ */
+ virtual double __toFloat();
+
+ /**
+ * Cast the object to a boolean
+ *
+ * This method is called when an object is casted to a bool, or when it
+ * is used in a boolean context
+ *
+ * @return bool
+ */
+ virtual bool __toBool();
+
+
private:
/**
* Store the object in the zend object cache
diff --git a/include/classbase.h b/include/classbase.h
index 6dba316..da027ab 100644
--- a/include/classbase.h
+++ b/include/classbase.h
@@ -374,6 +374,15 @@ private:
static int getClosure(struct _zval_struct *object, struct _zend_class_entry **entry, union _zend_function **func, struct _zval_struct **object_ptr);
/**
+ * Function to cast the object to a different type
+ * @param object
+ * @param retval
+ * @param type
+ * @return int
+ */
+ static int cast(struct _zval_struct *object, struct _zval_struct *retval, int type);
+
+ /**
* Name of the class
* @var string
*/
diff --git a/include/type.h b/include/type.h
index bec0fd5..e5ebeda 100644
--- a/include/type.h
+++ b/include/type.h
@@ -21,7 +21,7 @@ enum class Type : unsigned char {
Null = 0,
Numeric = 1,
Float = 2,
- Bool = 3,
+ Boolean = 3,
Array = 4,
Object = 5,
String = 6,
diff --git a/src/base.cpp b/src/base.cpp
index a5dc7b3..a9faac3 100644
--- a/src/base.cpp
+++ b/src/base.cpp
@@ -182,7 +182,79 @@ Value Base::__invoke(Parameters &params)
// unreachable code
return nullptr;
}
+
+/**
+ * Cast the object to a string
+ *
+ * This method is called when an object is casted to a string, or when
+ * it is used in a string context
+ *
+ * @return Value The object as a string
+ */
+Value Base::__toString()
+{
+ // 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 nullptr;
+}
+
+/**
+ * Cast the object to an integer
+ *
+ * This method is called when an object is casted to an integer, or when
+ * it is used in an integer context
+ *
+ * @return int Integer value
+ */
+long Base::__toInteger()
+{
+ // 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 0;
+}
+
+/**
+ * Cast the object to a float
+ *
+ * This method is called when an object is casted to a float, or when it
+ * is used in a float context
+ *
+ * @return double Floating point value
+ */
+double Base::__toFloat()
+{
+ // 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 0.0;
+}
+
+/**
+ * Cast the object to a boolean
+ *
+ * This method is called when an object is casted to a bool, or when it
+ * is used in a boolean context
+ *
+ * @return bool
+ */
+bool Base::__toBool()
+{
+ // 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 false;
+}
+
/**
* End namespace
*/
diff --git a/src/classbase.cpp b/src/classbase.cpp
index 00c679a..460bae3 100644
--- a/src/classbase.cpp
+++ b/src/classbase.cpp
@@ -282,12 +282,81 @@ zend_object_handlers *ClassBase::objectHandlers()
handlers.get_method = &ClassBase::getMethod;
handlers.get_closure = &ClassBase::getClosure;
+ // handler to cast to a different type
+ handlers.cast_object = &ClassBase::cast;
+
// remember that object is now initialized
initialized = true;
// done
return &handlers;
}
+
+/**
+ * Function to cast the object to a different type
+ * @param object
+ * @param retval
+ * @param type
+ * @return int
+ */
+int ClassBase::cast(zval *object, zval *retval, int type)
+{
+ // get the base object
+ Base *base = cpp_object(object);
+
+ // retval it not yet initialized --- and again feelings of disbelief,
+ // frustration, wonder and anger come up when you see that there are not two
+ // functions in the Zend engine that have a comparable API
+ INIT_PZVAL(retval);
+
+ // wrap zval in value object
+ Value result(retval, true);
+
+ // when the magic function it not implemented, an exception will be thrown,
+ // and the extension may throw a Php::Exception
+ try
+ {
+ // the result zval
+ zval *result = nullptr;
+
+ // check type
+ switch ((Type)type) {
+ case Type::Numeric: result = Value(base->__toInteger()).detach(); break;
+ case Type::Float: result = Value(base->__toFloat()).detach(); break;
+ case Type::Bool: result = Value(base->__toBool()).detach(); break;
+ case Type::String: result = base->__toString().setType(Type::String).detach(); break;
+ default: throw NotImplemented(); break;
+ }
+
+ // @todo do we turn into endless conversion if the __toString object returns 'this' ??
+ // (and if it does: who cares? If the extension programmer is stupid, why do we have to suffer?)
+
+ // is the object overwritten?
+ if (object == retval) zval_dtor(object);
+
+ // overwrite the result
+ ZVAL_ZVAL(retval, result, 1, 1);
+
+ // done
+ return SUCCESS;
+ }
+ catch (const NotImplemented &exception)
+ {
+ // is there a default?
+ if (std_object_handlers.cast_object) return FAILURE;
+
+ // call default
+ return std_object_handlers.cast_object(object, retval, type);
+ }
+ catch (Exception &exception)
+ {
+ // pass on the exception to php userspace
+ exception.process();
+
+ // done
+ return FAILURE;
+ }
+}
/**
* Function that is called to create space for a cloned object