diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-11 22:49:19 +0100 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-11 22:49:19 +0100 |
commit | 8c73a24872b5589cbb714be9c8588c7bf81c8563 (patch) | |
tree | d99c45763b66fefdfca2408713ae2a6927f1f90e /src | |
parent | 41d008988b482c643bd11464ba071de05f183d84 (diff) |
implemented __toString, __toInteger, __toFloat and __toBool methods
Diffstat (limited to 'src')
-rw-r--r-- | src/base.cpp | 72 | ||||
-rw-r--r-- | src/classbase.cpp | 69 |
2 files changed, 141 insertions, 0 deletions
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 ¶ms) // 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 |