#include "zend_exceptions.h"
#include "zend_vm.h"
#include "zend_dtrace.h"
+#include "zend_smart_str.h"
+
+ZEND_API zend_class_entry *zend_ce_throwable;
+ZEND_API zend_class_entry *zend_ce_exception;
+ZEND_API zend_class_entry *zend_ce_error_exception;
+ZEND_API zend_class_entry *zend_ce_error;
+ZEND_API zend_class_entry *zend_ce_parse_error;
+ZEND_API zend_class_entry *zend_ce_type_error;
+ZEND_API zend_class_entry *zend_ce_arithmetic_error;
+ZEND_API zend_class_entry *zend_ce_division_by_zero_error;
+
+ZEND_API void (*zend_throw_exception_hook)(zval *ex);
-static zend_class_entry *default_exception_ce;
-static zend_class_entry *error_exception_ce;
static zend_object_handlers default_exception_handlers;
-ZEND_API void (*zend_throw_exception_hook)(zval *ex TSRMLS_DC);
-void zend_exception_set_previous(zval *exception, zval *add_previous TSRMLS_DC)
+/* {{{ zend_implement_throwable */
+static int zend_implement_throwable(zend_class_entry *interface, zend_class_entry *class_type)
+{
+ if (instanceof_function(class_type, zend_ce_exception) || instanceof_function(class_type, zend_ce_error)) {
+ return SUCCESS;
+ }
+ zend_error_noreturn(E_ERROR, "Class %s cannot implement interface %s, extend %s or %s instead",
+ ZSTR_VAL(class_type->name),
+ ZSTR_VAL(interface->name),
+ ZSTR_VAL(zend_ce_exception->name),
+ ZSTR_VAL(zend_ce_error->name));
+ return FAILURE;
+}
+/* }}} */
+
+static inline zend_class_entry *i_get_exception_base(zval *object)
+{
+ return instanceof_function(Z_OBJCE_P(object), zend_ce_exception) ? zend_ce_exception : zend_ce_error;
+}
+
+ZEND_API zend_class_entry *zend_get_exception_base(zval *object)
+{
+ return i_get_exception_base(object);
+}
+
+void zend_exception_set_previous(zend_object *exception, zend_object *add_previous)
{
- zval tmp, *previous, zv, *pzv, rv;
- zval *previous, *ancestor;
++ zval *previous, *pzv;
++ zval tmp, zv, rv;
+ zend_class_entry *base_ce;
if (exception == add_previous || !add_previous || !exception) {
return;
}
- if (Z_TYPE_P(add_previous) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(add_previous), default_exception_ce TSRMLS_CC)) {
- zend_error(E_ERROR, "Cannot set non exception as previous exception");
+ ZVAL_OBJ(&tmp, add_previous);
+ if (!instanceof_function(Z_OBJCE(tmp), zend_ce_throwable)) {
+ zend_error_noreturn(E_CORE_ERROR, "Previous exception must implement Throwable");
return;
}
- ancestor = zend_read_property(default_exception_ce, add_previous, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
- while (Z_TYPE_P(ancestor) == IS_OBJECT) {
- if (Z_OBJ_HANDLE_P(ancestor) == Z_OBJ_HANDLE_P(exception)) {
++ pzv = zend_read_property(i_get_exception_base(&tmp), &tmp, "previous", sizeof("previous")-1, 1, &rv);
++ while (Z_TYPE_P(pzv) == IS_OBJECT) {
++ if (Z_OBJ_P(pzv) == exception) {
+ return;
+ }
- ancestor = zend_read_property(default_exception_ce, ancestor, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
++ pzv = zend_read_property(i_get_exception_base(pzv), pzv, "previous", sizeof("previous")-1, 1, &rv);
+ }
- while (exception && exception != add_previous && Z_OBJ_HANDLE_P(exception) != Z_OBJ_HANDLE_P(add_previous)) {
- previous = zend_read_property(default_exception_ce, exception, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
+ ZVAL_OBJ(&zv, exception);
+ pzv = &zv;
+ do {
+ base_ce = i_get_exception_base(pzv);
+ previous = zend_read_property(base_ce, pzv, "previous", sizeof("previous")-1, 1, &rv);
if (Z_TYPE_P(previous) == IS_NULL) {
- zend_update_property(default_exception_ce, exception, "previous", sizeof("previous")-1, add_previous TSRMLS_CC);
- Z_DELREF_P(add_previous);
+ zend_update_property(base_ce, pzv, "previous", sizeof("previous")-1, &tmp);
+ GC_REFCOUNT(add_previous)--;
return;
}
- exception = previous;
- }
+ pzv = previous;
+ } while (pzv && Z_OBJ_P(pzv) != add_previous);
}
-void zend_exception_save(TSRMLS_D) /* {{{ */
+void zend_exception_save(void) /* {{{ */
{
if (EG(prev_exception)) {
- zend_exception_set_previous(EG(exception), EG(prev_exception) TSRMLS_CC);
+ zend_exception_set_previous(EG(exception), EG(prev_exception));
}
if (EG(exception)) {
EG(prev_exception) = EG(exception);