@@ -37,8 +37,7 @@ void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {{{ */
37
37
{
38
38
if (exception != NULL ) {
39
39
if (EG (exception )) {
40
- /* FIXME: bail out? */
41
- return ;
40
+ zend_update_property (default_exception_ce , exception , "previous" , sizeof ("previous" )- 1 , EG (exception ) TSRMLS_CC );
42
41
}
43
42
EG (exception ) = exception ;
44
43
}
@@ -121,16 +120,16 @@ ZEND_METHOD(exception, __clone)
121
120
}
122
121
/* }}} */
123
122
124
- /* {{{ proto Exception::__construct(string message, int code)
123
+ /* {{{ proto Exception::__construct(string message, int code [, Exception previous] )
125
124
Exception constructor */
126
125
ZEND_METHOD (exception , __construct )
127
126
{
128
127
char * message = NULL ;
129
128
long code = 0 ;
130
- zval * object ;
129
+ zval * object , * previous = NULL ;
131
130
int argc = ZEND_NUM_ARGS (), message_len ;
132
131
133
- if (zend_parse_parameters_ex (ZEND_PARSE_PARAMS_QUIET , argc TSRMLS_CC , "|sl " , & message , & message_len , & code ) == FAILURE ) {
132
+ if (zend_parse_parameters_ex (ZEND_PARSE_PARAMS_QUIET , argc TSRMLS_CC , "|slO " , & message , & message_len , & code , & previous , default_exception_ce ) == FAILURE ) {
134
133
zend_error (E_ERROR , "Wrong parameters for Exception([string $exception [, long $code ]])" );
135
134
}
136
135
@@ -143,19 +142,23 @@ ZEND_METHOD(exception, __construct)
143
142
if (code ) {
144
143
zend_update_property_long (default_exception_ce , object , "code" , sizeof ("code" )- 1 , code TSRMLS_CC );
145
144
}
145
+
146
+ if (previous ) {
147
+ zend_update_property (default_exception_ce , object , "previous" , sizeof ("previous" )- 1 , previous TSRMLS_CC );
148
+ }
146
149
}
147
150
/* }}} */
148
151
149
- /* {{{ proto ErrorException::__construct(string message, int code, int severity [, string filename [, int lineno]])
152
+ /* {{{ proto ErrorException::__construct(string message, int code, int severity [, string filename [, int lineno [, Exception previous] ]])
150
153
ErrorException constructor */
151
154
ZEND_METHOD (error_exception , __construct )
152
155
{
153
156
char * message = NULL , * filename = NULL ;
154
157
long code = 0 , severity = E_ERROR , lineno ;
155
- zval * object ;
158
+ zval * object , * previous = NULL ;
156
159
int argc = ZEND_NUM_ARGS (), message_len , filename_len ;
157
160
158
- if (zend_parse_parameters_ex (ZEND_PARSE_PARAMS_QUIET , argc TSRMLS_CC , "|sllsl " , & message , & message_len , & code , & severity , & filename , & filename_len , & lineno ) == FAILURE ) {
161
+ if (zend_parse_parameters_ex (ZEND_PARSE_PARAMS_QUIET , argc TSRMLS_CC , "|sllslO " , & message , & message_len , & code , & severity , & filename , & filename_len , & lineno , & previous , default_exception_ce ) == FAILURE ) {
159
162
zend_error (E_ERROR , "Wrong parameters for ErrorException([string $exception [, long $code, [ long $severity, [ string $filename, [ long $lineno ]]]]])" );
160
163
}
161
164
@@ -169,6 +172,10 @@ ZEND_METHOD(error_exception, __construct)
169
172
zend_update_property_long (default_exception_ce , object , "code" , sizeof ("code" )- 1 , code TSRMLS_CC );
170
173
}
171
174
175
+ if (previous ) {
176
+ zend_update_property (default_exception_ce , object , "previous" , sizeof ("previous" )- 1 , previous TSRMLS_CC );
177
+ }
178
+
172
179
zend_update_property_long (default_exception_ce , object , "severity" , sizeof ("severity" )- 1 , severity TSRMLS_CC );
173
180
174
181
if (argc >= 4 ) {
@@ -445,6 +452,15 @@ ZEND_METHOD(exception, getTraceAsString)
445
452
}
446
453
/* }}} */
447
454
455
+ /* {{{ proto string Exception::getPrevious()
456
+ Return previous Exception or NULL. */
457
+ ZEND_METHOD (exception , getPrevious )
458
+ {
459
+ zval * previous ;
460
+ previous = zend_read_property (default_exception_ce , getThis (), "previous" , sizeof ("previous" )- 1 , 1 TSRMLS_CC );
461
+ RETURN_ZVAL (previous , 1 , 0 );
462
+ }
463
+
448
464
int zend_spprintf (char * * message , int max_len , char * format , ...) /* {{{ */
449
465
{
450
466
va_list arg ;
@@ -461,47 +477,60 @@ int zend_spprintf(char **message, int max_len, char *format, ...) /* {{{ */
461
477
Obtain the string representation of the Exception object */
462
478
ZEND_METHOD (exception , __toString )
463
479
{
464
- zval message , file , line , * trace ;
465
- char * str ;
466
- int len ;
480
+ zval message , file , line , * trace , * exception ;
481
+ char * str = estrndup ( "" , 0 ), * prev_str ;
482
+ int len = 0 ;
467
483
zend_fcall_info fci ;
468
484
zval fname ;
469
485
470
- _default_exception_get_entry (getThis (), "message" , sizeof ("message" )- 1 , & message TSRMLS_CC );
471
- _default_exception_get_entry (getThis (), "file" , sizeof ("file" )- 1 , & file TSRMLS_CC );
472
- _default_exception_get_entry (getThis (), "line" , sizeof ("line" )- 1 , & line TSRMLS_CC );
473
-
474
- convert_to_string (& message );
475
- convert_to_string (& file );
476
- convert_to_long (& line );
477
-
486
+ exception = getThis ();
478
487
ZVAL_STRINGL (& fname , "gettraceasstring" , sizeof ("gettraceasstring" )- 1 , 0 );
479
488
480
- fci .size = sizeof (fci );
481
- fci .function_table = & Z_OBJCE_P (getThis ())-> function_table ;
482
- fci .function_name = & fname ;
483
- fci .symbol_table = NULL ;
484
- fci .object_pp = & getThis ();
485
- fci .retval_ptr_ptr = & trace ;
486
- fci .param_count = 0 ;
487
- fci .params = NULL ;
488
- fci .no_separation = 1 ;
489
-
490
- zend_call_function (& fci , NULL TSRMLS_CC );
489
+ while (exception && Z_TYPE_P (exception ) == IS_OBJECT ) {
490
+ prev_str = str ;
491
+ _default_exception_get_entry (exception , "message" , sizeof ("message" )- 1 , & message TSRMLS_CC );
492
+ _default_exception_get_entry (exception , "file" , sizeof ("file" )- 1 , & file TSRMLS_CC );
493
+ _default_exception_get_entry (exception , "line" , sizeof ("line" )- 1 , & line TSRMLS_CC );
494
+
495
+ convert_to_string (& message );
496
+ convert_to_string (& file );
497
+ convert_to_long (& line );
498
+
499
+ fci .size = sizeof (fci );
500
+ fci .function_table = & Z_OBJCE_P (exception )-> function_table ;
501
+ fci .function_name = & fname ;
502
+ fci .symbol_table = NULL ;
503
+ fci .object_pp = & exception ;
504
+ fci .retval_ptr_ptr = & trace ;
505
+ fci .param_count = 0 ;
506
+ fci .params = NULL ;
507
+ fci .no_separation = 1 ;
508
+
509
+ zend_call_function (& fci , NULL TSRMLS_CC );
510
+
511
+ if (Z_TYPE_P (trace ) != IS_STRING ) {
512
+ trace = NULL ;
513
+ }
491
514
492
- if (Z_TYPE_P (trace ) != IS_STRING ) {
493
- trace = NULL ;
494
- }
515
+ if (Z_STRLEN (message ) > 0 ) {
516
+ len = zend_spprintf (& str , 0 , "exception '%s' with message '%s' in %s:%ld\nStack trace:\n%s%s%s" ,
517
+ Z_OBJCE_P (exception )-> name , Z_STRVAL (message ), Z_STRVAL (file ), Z_LVAL (line ),
518
+ (trace && Z_STRLEN_P (trace )) ? Z_STRVAL_P (trace ) : "#0 {main}\n" ,
519
+ len ? "\n\nNext " : "" , prev_str );
520
+ } else {
521
+ len = zend_spprintf (& str , 0 , "exception '%s' in %s:%ld\nStack trace:\n%s%s%s" ,
522
+ Z_OBJCE_P (exception )-> name , Z_STRVAL (file ), Z_LVAL (line ),
523
+ (trace && Z_STRLEN_P (trace )) ? Z_STRVAL_P (trace ) : "#0 {main}\n" ,
524
+ len ? "\n\nNext " : "" , prev_str );
525
+ }
526
+ efree (prev_str );
527
+ zval_dtor (& message );
528
+ zval_dtor (& file );
529
+ zval_dtor (& line );
495
530
496
- if (Z_STRLEN (message ) > 0 ) {
497
- len = zend_spprintf (& str , 0 , "exception '%s' with message '%s' in %s:%ld\nStack trace:\n%s" ,
498
- Z_OBJCE_P (getThis ())-> name , Z_STRVAL (message ), Z_STRVAL (file ), Z_LVAL (line ),
499
- (trace && Z_STRLEN_P (trace )) ? Z_STRVAL_P (trace ) : "#0 {main}\n" );
500
- } else {
501
- len = zend_spprintf (& str , 0 , "exception '%s' in %s:%ld\nStack trace:\n%s" ,
502
- Z_OBJCE_P (getThis ())-> name , Z_STRVAL (file ), Z_LVAL (line ),
503
- (trace && Z_STRLEN_P (trace )) ? Z_STRVAL_P (trace ) : "#0 {main}\n" );
531
+ exception = zend_read_property (default_exception_ce , exception , "previous" , sizeof ("previous" )- 1 , 0 TSRMLS_CC );
504
532
}
533
+ zval_dtor (& fname );
505
534
506
535
/* We store the result in the private property string so we can access
507
536
* the result in uncaught exception handlers without memleaks. */
@@ -511,10 +540,6 @@ ZEND_METHOD(exception, __toString)
511
540
zval_ptr_dtor (& trace );
512
541
}
513
542
514
- zval_dtor (& message );
515
- zval_dtor (& file );
516
- zval_dtor (& line );
517
-
518
543
RETURN_STRINGL (str , len , 0 );
519
544
}
520
545
/* }}} */
@@ -543,6 +568,7 @@ const static zend_function_entry default_exception_functions[] = {
543
568
ZEND_ME (exception , getFile , NULL , ZEND_ACC_PUBLIC |ZEND_ACC_FINAL )
544
569
ZEND_ME (exception , getLine , NULL , ZEND_ACC_PUBLIC |ZEND_ACC_FINAL )
545
570
ZEND_ME (exception , getTrace , NULL , ZEND_ACC_PUBLIC |ZEND_ACC_FINAL )
571
+ ZEND_ME (exception , getPrevious , NULL , ZEND_ACC_PUBLIC |ZEND_ACC_FINAL )
546
572
ZEND_ME (exception , getTraceAsString , NULL , ZEND_ACC_PUBLIC |ZEND_ACC_FINAL )
547
573
ZEND_ME (exception , __toString , NULL , 0 )
548
574
{NULL , NULL , NULL }
@@ -555,6 +581,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_error_exception___construct, 0, 0, 0)
555
581
ZEND_ARG_INFO (0 , severity )
556
582
ZEND_ARG_INFO (0 , filename )
557
583
ZEND_ARG_INFO (0 , lineno )
584
+ ZEND_ARG_INFO (0 , previous )
558
585
ZEND_END_ARG_INFO ()
559
586
560
587
static const zend_function_entry error_exception_functions [] = {
@@ -580,6 +607,7 @@ void zend_register_default_exception(TSRMLS_D) /* {{{ */
580
607
zend_declare_property_null (default_exception_ce , "file" , sizeof ("file" )- 1 , ZEND_ACC_PROTECTED TSRMLS_CC );
581
608
zend_declare_property_null (default_exception_ce , "line" , sizeof ("line" )- 1 , ZEND_ACC_PROTECTED TSRMLS_CC );
582
609
zend_declare_property_null (default_exception_ce , "trace" , sizeof ("trace" )- 1 , ZEND_ACC_PRIVATE TSRMLS_CC );
610
+ zend_declare_property_null (default_exception_ce , "previous" , sizeof ("previous" )- 1 , ZEND_ACC_PRIVATE TSRMLS_CC );
583
611
584
612
INIT_CLASS_ENTRY (ce , "ErrorException" , error_exception_functions );
585
613
error_exception_ce = zend_register_internal_class_ex (& ce , default_exception_ce , NULL TSRMLS_CC );
0 commit comments