zend_llist_destroy(&zend_observer_error_callbacks);
}
-static void zend_observer_fcall_install(zend_function *function) {
+static void zend_observer_fcall_install(zend_execute_data *execute_data) {
zend_llist_element *element;
zend_llist *list = &zend_observers_fcall_list;
+ zend_function *function = execute_data->func;
zend_op_array *op_array = &function->op_array;
if (fcall_handlers_arena == NULL) {
for (element = list->head; element; element = element->next) {
zend_observer_fcall_init init;
memcpy(&init, element->data, sizeof init);
- zend_observer_fcall_handlers handlers = init(function);
+ zend_observer_fcall_handlers handlers = init(execute_data);
if (handlers.begin || handlers.end) {
zend_llist_add_element(&handlers_list, &handlers);
}
fcall_data = ZEND_OBSERVER_DATA(op_array);
if (!fcall_data) {
- zend_observer_fcall_install((zend_function *)op_array);
+ zend_observer_fcall_install(execute_data);
fcall_data = ZEND_OBSERVER_DATA(op_array);
}
int observer_observe_functions;
int observer_show_return_type;
int observer_show_return_value;
+ int observer_show_init_backtrace;
int observer_nesting_depth;
ZEND_END_MODULE_GLOBALS(zend_test)
STD_PHP_INI_BOOLEAN("zend_test.observer.observe_functions", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_observe_functions, zend_zend_test_globals, zend_test_globals)
STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_type", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_type, zend_zend_test_globals, zend_test_globals)
STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_value", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_value, zend_zend_test_globals, zend_test_globals)
+ STD_PHP_INI_BOOLEAN("zend_test.observer.show_init_backtrace", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_init_backtrace, zend_zend_test_globals, zend_test_globals)
PHP_INI_END()
-static zend_observer_fcall_handlers observer_fcall_init(zend_function *fbc);
+static zend_observer_fcall_handlers observer_fcall_init(zend_execute_data *execute_data);
PHP_MINIT_FUNCTION(zend_test)
{
}
}
-static zend_observer_fcall_handlers observer_fcall_init(zend_function *fbc)
+static void observer_show_init_backtrace(zend_execute_data *execute_data)
{
+ zend_execute_data *ex = execute_data;
+ php_printf("%*s<!--\n", 2 * ZT_G(observer_nesting_depth), "");
+ do {
+ zend_function *fbc = ex->func;
+ int indent = 2 * ZT_G(observer_nesting_depth) + 4;
+ if (fbc->common.function_name) {
+ if (fbc->common.scope) {
+ php_printf("%*s%s::%s()\n", indent, "", ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
+ } else {
+ php_printf("%*s%s()\n", indent, "", ZSTR_VAL(fbc->common.function_name));
+ }
+ } else {
+ php_printf("%*s{main} %s\n", indent, "", ZSTR_VAL(fbc->op_array.filename));
+ }
+ } while ((ex = ex->prev_execute_data) != NULL);
+ php_printf("%*s-->\n", 2 * ZT_G(observer_nesting_depth), "");
+}
+
+static zend_observer_fcall_handlers observer_fcall_init(zend_execute_data *execute_data)
+{
+ zend_function *fbc = execute_data->func;
if (ZT_G(observer_show_output)) {
observer_show_init(fbc);
+ if (ZT_G(observer_show_init_backtrace)) {
+ observer_show_init_backtrace(execute_data);
+ }
}
if (ZT_G(observer_observe_all)) {
--- /dev/null
+--TEST--
+Observer: Show backtrace on init
+--SKIPIF--
+<?php if (!extension_loaded('zend-test')) die('skip: zend-test extension required'); ?>
+--INI--
+zend_test.observer.enabled=1
+zend_test.observer.observe_all=1
+zend_test.observer.show_init_backtrace=1
+--FILE--
+<?php
+class TestClass
+{
+ private function bar($number)
+ {
+ return $number + 2;
+ }
+
+ public function foo()
+ {
+ return array_map(function ($value) {
+ return $this->bar($value);
+ }, [40, 1335]);
+ }
+}
+
+function gen()
+{
+ $test = new TestClass();
+ yield $test->foo();
+}
+
+function foo()
+{
+ return gen()->current();
+}
+
+var_dump(foo());
+?>
+--EXPECTF--
+<!-- init '%s/observer_backtrace_%d.php' -->
+<!--
+ {main} %s/observer_backtrace_%d.php
+-->
+<file '%s/observer_backtrace_%d.php'>
+ <!-- init foo() -->
+ <!--
+ foo()
+ {main} %s/observer_backtrace_%d.php
+ -->
+ <foo>
+ <!-- init gen() -->
+ <!--
+ gen()
+ Generator::current()
+ foo()
+ {main} %s/observer_backtrace_%d.php
+ -->
+ <gen>
+ <!-- init TestClass::foo() -->
+ <!--
+ TestClass::foo()
+ gen()
+ Generator::current()
+ foo()
+ {main} %s/observer_backtrace_%d.php
+ -->
+ <TestClass::foo>
+ <!-- init TestClass::{closure}() -->
+ <!--
+ TestClass::{closure}()
+ array_map()
+ TestClass::foo()
+ gen()
+ Generator::current()
+ foo()
+ {main} %s/observer_backtrace_%d.php
+ -->
+ <TestClass::{closure}>
+ <!-- init TestClass::bar() -->
+ <!--
+ TestClass::bar()
+ TestClass::{closure}()
+ array_map()
+ TestClass::foo()
+ gen()
+ Generator::current()
+ foo()
+ {main} %s/observer_backtrace_%d.php
+ -->
+ <TestClass::bar>
+ </TestClass::bar>
+ </TestClass::{closure}>
+ <TestClass::{closure}>
+ <TestClass::bar>
+ </TestClass::bar>
+ </TestClass::{closure}>
+ </TestClass::foo>
+ </gen>
+ </foo>
+array(2) {
+ [0]=>
+ int(42)
+ [1]=>
+ int(1337)
+}
+</file '%s/observer_backtrace_%d.php'>