Skip to content

Commit 93cb539

Browse files
committed
Extend zend_test to allow hooks to be executed while observing the end of a function
Add a test verifying we can modify return values
1 parent 4123cc3 commit 93cb539

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

ext/zend_test/observer.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,46 @@ static void observer_end(zend_execute_data *execute_data, zval *retval)
119119
if (EG(exception)) {
120120
php_printf("%*s<!-- Exception: %s -->\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(EG(exception)->ce->name));
121121
}
122+
123+
if(ZT_G(observer_observe_end_call_function_name) && strlen(ZT_G(observer_observe_end_call_function_name)) > 0) {
124+
zend_fcall_info fci = empty_fcall_info;
125+
zend_fcall_info_cache fcc = empty_fcall_info_cache;
126+
127+
zval function_name = {.u1.type_info = IS_UNDEF};
128+
129+
// Initialize the zval with the zend_string value
130+
ZVAL_STRING(&function_name, ZT_G(observer_observe_end_call_function_name));
131+
132+
char* error = 0;
133+
if (zend_fcall_info_init(&function_name, 0, &fci, &fcc, NULL, &error) != SUCCESS) {
134+
135+
php_printf("<!-- Hook (%s) not found: %s-->\n", Z_STRVAL(function_name), error);
136+
efree(error);
137+
} else {
138+
139+
zval ret = {.u1.type_info = IS_UNDEF};
140+
fci.param_count = 0;
141+
fci.params = NULL;
142+
fci.named_params = NULL;
143+
fci.retval = &ret;
144+
145+
if (zend_call_function(&fci, &fcc) == SUCCESS) {
146+
if (!Z_ISUNDEF(ret) &&
147+
(fcc.function_handler->op_array.fn_flags &
148+
ZEND_ACC_HAS_RETURN_TYPE) &&
149+
!(ZEND_TYPE_PURE_MASK(
150+
fcc.function_handler->common.arg_info[-1].type) &
151+
MAY_BE_VOID)) {
152+
if (execute_data->return_value) {
153+
zval_ptr_dtor(execute_data->return_value);
154+
ZVAL_COPY(execute_data->return_value, &ret);
155+
ZVAL_UNDEF(&ret);
156+
}
157+
}
158+
}
159+
}
160+
zval_ptr_dtor(&function_name);
161+
}
122162
observer_show_opcode(execute_data);
123163
ZT_G(observer_nesting_depth)--;
124164
if (execute_data->func && execute_data->func->common.function_name) {
@@ -304,6 +344,7 @@ PHP_INI_BEGIN()
304344
STD_PHP_INI_BOOLEAN("zend_test.observer.observe_includes", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_observe_includes, zend_zend_test_globals, zend_test_globals)
305345
STD_PHP_INI_BOOLEAN("zend_test.observer.observe_functions", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_observe_functions, zend_zend_test_globals, zend_test_globals)
306346
STD_PHP_INI_ENTRY("zend_test.observer.observe_function_names", "", PHP_INI_SYSTEM, zend_test_observer_OnUpdateCommaList, observer_observe_function_names, zend_zend_test_globals, zend_test_globals)
347+
STD_PHP_INI_ENTRY("zend_test.observer.observe_end_call_function_name", "", PHP_INI_ALL, OnUpdateString, observer_observe_end_call_function_name, zend_zend_test_globals, zend_test_globals)
307348
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)
308349
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)
309350
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)

ext/zend_test/php_test.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
3939
int observer_observe_includes;
4040
int observer_observe_functions;
4141
zend_array *observer_observe_function_names;
42+
const char *observer_observe_end_call_function_name;
4243
int observer_show_return_type;
4344
int observer_show_return_value;
4445
int observer_show_init_backtrace;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Observer: Function return values are modifiable by observers
3+
--EXTENSIONS--
4+
zend_test
5+
--INI--
6+
zend_test.observer.enabled=1
7+
zend_test.observer.show_output=1
8+
zend_test.observer.show_return_value=1
9+
zend_test.observer.observe_function_names=foo
10+
zend_test.observer.observe_end_call_function_name=hook
11+
--FILE--
12+
<?php
13+
function foo(string $pin): string {
14+
15+
return 'original return value';
16+
}
17+
18+
function hook(): string {
19+
return 'hook value';
20+
}
21+
22+
$res = foo('some value'); // Retval used
23+
var_dump($res);
24+
echo 'Done' . PHP_EOL;
25+
?>
26+
--EXPECTF--
27+
<!-- init '%s/observer_retval_alter_%d.php' -->
28+
<!-- init foo() -->
29+
<foo>
30+
<!-- init hook() -->
31+
</foo:'original return value'>
32+
string(10) "hook value"
33+
Done

0 commit comments

Comments
 (0)