diff options
-rw-r--r-- | Examples/Exceptions/ExceptionCatch/exception.php | 2 | ||||
-rw-r--r-- | Examples/Exceptions/ExceptionCatch/exceptionCatch.cpp | 8 | ||||
-rw-r--r-- | include/origexception.h | 63 | ||||
-rw-r--r-- | phpcpp.h | 1 | ||||
-rw-r--r-- | src/function.cpp | 7 | ||||
-rw-r--r-- | src/includes.h | 1 | ||||
-rw-r--r-- | src/origexception.cpp | 80 | ||||
-rw-r--r-- | src/value.cpp | 11 |
8 files changed, 164 insertions, 9 deletions
diff --git a/Examples/Exceptions/ExceptionCatch/exception.php b/Examples/Exceptions/ExceptionCatch/exception.php index 0fec704..f0bfe90 100644 --- a/Examples/Exceptions/ExceptionCatch/exception.php +++ b/Examples/Exceptions/ExceptionCatch/exception.php @@ -14,4 +14,4 @@ my_catch_exception_function(function($a, $b, $c) { // throw an exception from PHP - the C++ code will catch this exception throw new Exception("Example exception"); -});} +}); diff --git a/Examples/Exceptions/ExceptionCatch/exceptionCatch.cpp b/Examples/Exceptions/ExceptionCatch/exceptionCatch.cpp index a5f7b96..9efdf93 100644 --- a/Examples/Exceptions/ExceptionCatch/exceptionCatch.cpp +++ b/Examples/Exceptions/ExceptionCatch/exceptionCatch.cpp @@ -11,6 +11,7 @@ * Libraries used. */ #include <phpcpp.h> +#include <iostream> /** * Namespace to use @@ -39,7 +40,8 @@ void my_catch_exception_function(Php::Parameters ¶ms) } catch (Php::Exception &exception) { - // @todo handle the exception that was thrown from PHP space + // handle the exception that was thrown from PHP space + std::cout << "exception caught in CPP code" << std::endl; } } @@ -54,9 +56,7 @@ extern "C" static Php::Extension extension("my_exception_catch","1.0"); // add function to extension - extension.add("my_catch_exception_function", my_catch_exception_function, { - Php::ByVal("callback", Php::callableType); - }); + extension.add("my_catch_exception_function", my_catch_exception_function); // return the extension module return extension.module(); diff --git a/include/origexception.h b/include/origexception.h new file mode 100644 index 0000000..bce0945 --- /dev/null +++ b/include/origexception.h @@ -0,0 +1,63 @@ +/** + * OrigException.h + * + * Class that wraps around an exception that was thrown by PHP code, + * and that could - but not necessarily has to - be caught by C++ + * + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2013 Copernica BV + */ + +/** + * Set up namespace + */ +namespace Php { + +/** + * Class definition + */ +class OrigException : public Value, public Exception +{ +private: + /** + * Has the exception been restored by the C++ code so that it can be dealt by PHP? + * @var boolean + */ + bool _restored; + +public: + /** + * Constructor + * @param zval + */ + OrigException(struct _zval_struct *zval); + + /** + * Copy constructor + * @param exception + */ + OrigException(const OrigException &exception); + + /** + * Move constructor + * @param exception + */ + OrigException(OrigException &&exception); + + /** + * Destructor + */ + virtual ~OrigException(); + + /** + * Restore the exception - because the exception was not handled by C++ code + * @internal + */ + void restore(); +}; + +/** + * End of namespace + */ +} + @@ -45,6 +45,7 @@ #include <phpcpp/classinfo.h> #include <phpcpp/extension.h> #include <phpcpp/exception.h> +#include <phpcpp/originalexception.h> /** * Macro to export a function diff --git a/src/function.cpp b/src/function.cpp index cc4315f..3269448 100644 --- a/src/function.cpp +++ b/src/function.cpp @@ -43,6 +43,13 @@ void invoke_function(INTERNAL_FUNCTION_PARAMETERS) // get the result result = function->invoke(params); } + catch (Php::OrigException &exception) + { + // we caught an exception that was original thrown by PHP code, and not + // processed by C++ code, this means that we're going to restore this + // exception so that it can be further handled by PHP + exception.restore(); + } catch (Php::Exception &exception) { // an exception originally thrown by C++ should be passed on to PHP diff --git a/src/includes.h b/src/includes.h index 18e9951..933e317 100644 --- a/src/includes.h +++ b/src/includes.h @@ -58,6 +58,7 @@ #include "../include/classinfo.h" #include "../include/extension.h" #include "../include/exception.h" +#include "../include/origexception.h" #include "../include/init.h" /** diff --git a/src/origexception.cpp b/src/origexception.cpp new file mode 100644 index 0000000..299730e --- /dev/null +++ b/src/origexception.cpp @@ -0,0 +1,80 @@ +/** + * Implementation of the exception that was originally thrown by PHP + * code or the zend engine, and that could or could not be picked + * up by C++ code + * + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2013 Copernica BV + */ +#include "includes.h" + +/** + * Set up namespace + */ +namespace Php { + +/** + * Constructor + * @param zval + */ +OrigException::OrigException(struct _zval_struct *zval) : + Value(zval), + Exception("OrigException"), + _restored(false) +{ + std::cout << "save the exception" << std::endl; + + // save the exception + zend_exception_save(); +} + +/** + * Copy constructor + * @param exception + */ +OrigException::OrigException(const OrigException &exception) : + Value(exception), + Exception("OrigException"), + _restored(exception._restored) {} + +/** + * Move constructor + * @param exception + */ +OrigException::OrigException(OrigException &&exception) : + Value(std::move(exception)), + Exception("OrigException"), + _restored(exception._restored) {} + +/** + * Destructor + */ +OrigException::~OrigException() +{ + // skip if the exception was restored + if (_restored) return; + + // clean up the exception + zend_clear_exception(); +} + +/** + * Restore the exception + * @internal + */ +void OrigException::restore() +{ + std::cout << "restore the exception" << std::endl; + + // restore the exception + zend_exception_restore(); + + // mark exception as restored + _restored = true; +} + +/** + * End of namespace + */ +} + diff --git a/src/value.cpp b/src/value.cpp index 194934d..49c9c2b 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -868,14 +868,17 @@ Value Value::exec(int argc, zval ***params) // the return zval zval *retval = nullptr; + // the current exception + zval *oldException = EG(exception); + // call the function if (call_user_function_ex(CG(function_table), NULL, _val, &retval, argc, params, 1, NULL) != SUCCESS) return nullptr; - // was a value returned? - if (retval) return Value(retval); + // was an exception thrown? + if (oldException != EG(exception)) throw OrigException(EG(exception)); - // no value was returned, return NULL - return nullptr; + // no (additional) exception was thrown + return retval ? Value(retval) : nullptr; } /** |