Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions Zend/tests/exception_provide_object.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
--TEST--
Exceptions providing object
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am personally interested in this to be able to inspect the called Closures. If this PR will allow this, please add a test like https://3v4l.org/YqFcG (my usecase it is to able to extract $this and use variable in catch clause of the called closure).

Copy link
Contributor Author

@marc-mabe marc-mabe Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mvorisek I have updated the testcase to include a closure as well. Variables use'd are not part of the trace as the closure object points to the object the closure is bind to.

--FILE--
<?php

class Test {
public $random;

function __construct() {
$this->random = random_int(0, 100);
}

function doThrow(...$args) {
throw new Exception();
}

function funcDoThrow() {
return fn(...$args) => $this->doThrow(...$args);
}
}

function doThrow(...$args) {
(new Test())->funcDoThrow()(...$args);
}

echo "zend.exception_ignore_args=0\n";
echo "zend.exception_provide_object=1\n";
ini_set("zend.exception_ignore_args", 0);
ini_set("zend.exception_provide_object", 1);

try {
doThrow("foo", "bar");
} catch (Exception $e) {
var_dump($e->getTrace());
}

echo "zend.exception_ignore_args=1\n";
echo "zend.exception_provide_object=0\n";
ini_set("zend.exception_ignore_args", 1);
ini_set("zend.exception_provide_object", 0);

try {
doThrow("foo", "bar");
} catch (Exception $e) {
var_dump($e->getTrace());
}

?>
--EXPECTF--
zend.exception_ignore_args=0
zend.exception_provide_object=1
array(3) {
[0]=>
array(7) {
["file"]=>
string(%d) "%sexception_provide_object.php"
["line"]=>
int(%d)
["function"]=>
string(7) "doThrow"
["class"]=>
string(4) "Test"
["object"]=>
object(Test)#%d (%d) {
["random"]=>
int(%d)
}
["type"]=>
string(2) "->"
["args"]=>
array(2) {
[0]=>
string(3) "foo"
[1]=>
string(3) "bar"
}
}
[1]=>
array(7) {
["file"]=>
string(%d) "%sexception_provide_object.php"
["line"]=>
int(%d)
["function"]=>
string(%d) "{closure:Test::funcDoThrow():%d}"
["class"]=>
string(4) "Test"
["object"]=>
object(Test)#%d (%d) {
["random"]=>
int(%d)
}
["type"]=>
string(2) "->"
["args"]=>
array(2) {
[0]=>
string(3) "foo"
[1]=>
string(3) "bar"
}
}
[2]=>
array(4) {
["file"]=>
string(%d) "%sexception_provide_object.php"
["line"]=>
int(%d)
["function"]=>
string(7) "doThrow"
["args"]=>
array(2) {
[0]=>
string(3) "foo"
[1]=>
string(3) "bar"
}
}
}
zend.exception_ignore_args=1
zend.exception_provide_object=0
array(3) {
[0]=>
array(5) {
["file"]=>
string(%d) "%sexception_provide_object.php"
["line"]=>
int(%d)
["function"]=>
string(7) "doThrow"
["class"]=>
string(4) "Test"
["type"]=>
string(2) "->"
}
[1]=>
array(5) {
["file"]=>
string(%d) "%sexception_provide_object.php"
["line"]=>
int(%d)
["function"]=>
string(%d) "{closure:Test::funcDoThrow():%d}"
["class"]=>
string(4) "Test"
["type"]=>
string(2) "->"
}
[2]=>
array(3) {
["file"]=>
string(%d) "%sexception_provide_object.php"
["line"]=>
int(%d)
["function"]=>
string(7) "doThrow"
}
}
1 change: 1 addition & 0 deletions Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ ZEND_INI_BEGIN()
STD_ZEND_INI_BOOLEAN("zend.signal_check", SIGNAL_CHECK_DEFAULT, ZEND_INI_SYSTEM, OnUpdateBool, check, zend_signal_globals_t, zend_signal_globals)
#endif
STD_ZEND_INI_BOOLEAN("zend.exception_ignore_args", "0", ZEND_INI_ALL, OnUpdateBool, exception_ignore_args, zend_executor_globals, executor_globals)
STD_ZEND_INI_BOOLEAN("zend.exception_provide_object", "0", ZEND_INI_ALL, OnUpdateBool, exception_provide_object, zend_executor_globals, executor_globals)
STD_ZEND_INI_ENTRY("zend.exception_string_param_max_len", "15", ZEND_INI_ALL, OnSetExceptionStringParamMaxLen, exception_string_param_max_len, zend_executor_globals, executor_globals)
STD_ZEND_INI_ENTRY("fiber.stack_size", NULL, ZEND_INI_ALL, OnUpdateFiberStackSize, fiber_stack_size, zend_executor_globals, executor_globals)
#ifdef ZEND_CHECK_STACK_LIMIT
Expand Down
11 changes: 8 additions & 3 deletions Zend/zend_exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,14 +290,19 @@ static zend_object *zend_default_exception_new(zend_class_entry *class_type) /*
zval tmp;
zval trace;
zend_string *filename;
int options = 0;

zend_object *object = zend_objects_new(class_type);
object_properties_init(object, class_type);

if (EG(current_execute_data)) {
zend_fetch_debug_backtrace(&trace,
0,
EG(exception_ignore_args) ? DEBUG_BACKTRACE_IGNORE_ARGS : 0, 0);
if (EG(exception_ignore_args)) {
options |= DEBUG_BACKTRACE_IGNORE_ARGS;
}
if (EG(exception_provide_object)) {
options |= DEBUG_BACKTRACE_PROVIDE_OBJECT;
}
zend_fetch_debug_backtrace(&trace, 0, options, 0);
} else {
ZVAL_EMPTY_ARRAY(&trace);
}
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ struct _zend_executor_globals {

int user_error_handler_error_reporting;
bool exception_ignore_args;
bool exception_provide_object;
zval user_error_handler;
zval user_exception_handler;
zend_stack user_error_handlers_error_reporting;
Expand Down
14 changes: 13 additions & 1 deletion php.ini-development
Original file line number Diff line number Diff line change
Expand Up @@ -367,12 +367,24 @@ zend.enable_gc = On

; Allows to include or exclude arguments from stack traces generated for exceptions.
; In production, it is recommended to turn this setting on to prohibit the output
; of sensitive information in stack traces
; of sensitive information in stack traces.
; Note: This increases the refcount of the objects in arguments, and therefore delays
; object destruction until all references have been destroyed.
; Default Value: Off
; Development Value: Off
; Production Value: On
zend.exception_ignore_args = Off

; Allows to include or exclude called object from stack traces generated for exceptions.
; In production, it is recommended to turn this setting off to prohibit the output
; of sensitive information in stack traces.
; Note: This increases the refcount of the objects, and therefore delays object
; destruction until all references have been destroyed.
; Default Value: Off
; Development Value: On
; Production Value: Off
zend.exception_provide_object = On

; Allows setting the maximum string length in an argument of a stringified stack trace
; to a value between 0 and 1000000.
; This has no effect when zend.exception_ignore_args is enabled.
Expand Down
14 changes: 13 additions & 1 deletion php.ini-production
Original file line number Diff line number Diff line change
Expand Up @@ -367,12 +367,24 @@ zend.enable_gc = On

; Allows to include or exclude arguments from stack traces generated for exceptions.
; In production, it is recommended to turn this setting on to prohibit the output
; of sensitive information in stack traces
; of sensitive information in stack traces.
; Note: This increases the refcount of the objects in arguments, and therefore delays
; object destruction until all references have been destroyed.
; Default Value: Off
; Development Value: Off
; Production Value: On
zend.exception_ignore_args = On

; Allows to include or exclude called object from stack traces generated for exceptions.
; In production, it is recommended to turn this setting off to prohibit the output
; of sensitive information in stack traces.
; Note: This increases the refcount of the objects, and therefore delays object
; destruction until all references have been destroyed.
; Default Value: Off
; Development Value: On
; Production Value: Off
zend.exception_provide_object = Off

; Allows setting the maximum string length in an argument of a stringified stack trace
; to a value between 0 and 1000000.
; This has no effect when zend.exception_ignore_args is enabled.
Expand Down
Loading