uopz icon indicating copy to clipboard operation
uopz copied to clipboard

Cannot replace global functions if there's a class with the same name

Open Nebual opened this issue 1 year ago • 1 comments

I encountered an issue when trying to use uopz via clock-mock, which tries to use

uopz_set_return('date', self::mock_date(), true);

The odd error I got said:

failed to set return for Date::date, the method does not exist

I traced this down to our legacy codebase containing a \Date class, which seemingly causes uopz_set_return('date', $fn, true) to be misinterpreted as uopz_set_return(\Date::class, 'date', $fn, true). This seems to be true for any class named like a function - it prevents the function from being replaced.

We're going to work around it by renaming our class, but it was pretty confusing to discover, and I couldn't find any discussions about it, so I wanted to report it in case anyone else runs into something similar.

Nebual avatar Nov 18 '22 00:11 Nebual

Indeed, this is due to the overloaded uopz_set_return():

https://github.com/krakjoe/uopz/blob/6db6be8d646296d10bfab641cd9d283a6909a51f/uopz.c#L199-L200

If the first ZPP fails, clazz might be assigned, but is not changed afterwards. That looks like a bug to me. One option would be to swap the ZPPs (possibly BC breaking?). Another might be the following hack:

 uopz.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/uopz.c b/uopz.c
index 2862125..d81ad39 100644
--- a/uopz.c
+++ b/uopz.c
@@ -197,6 +197,7 @@ static PHP_FUNCTION(uopz_set_return)
 	uopz_disabled_guard();
 
 	if (uopz_parse_parameters("CSz|b", &clazz, &function, &variable, &execute) != SUCCESS &&
+		!(clazz = NULL) &&
 		uopz_parse_parameters("Sz|b", &function, &variable, &execute) != SUCCESS) {
 		uopz_refuse_parameters(
 				"unexpected parameter combination, expected (class, function, variable [, execute]) or (function, variable [, execute])");

Other functions such as uopz_unset_return() appear to be affected by this issue, too.

cmb69 avatar Nov 18 '22 12:11 cmb69