Here's something that you could do using built-in PHP functionality.
Warning
This is a bit awkward (and might not work in every situation), therefore I wouldn't recommend this unless you can't use any of the stuff rightfully recommended in the comments (although I'm not familiar with them, so I can't be sure).
It should however do the job, despite how ugly it looks (yes, it does make use of the universally hated eval
, but since it's for testing purposes, it should never deal with non-controlled input anyway).
Stuff that you only need to define once (and should be in its own file)
Now that this is out of the way, here it is. You add the following code somewhere, which defines the fake
function and then all the (actual) fake functions you want (such as file
), under a specific namespace:
namespace Fake\BuiltIn\Functions;
/**
* Executes the given statements using fake built-in functions.
*
* @param callable $statements Statements to execute.
* @return mixed Whatever $statements returns.
* @throws \ReflectionException
*/
function fake(callable $statements)
{
$function = new \ReflectionFunction($statements);
$start_line = $function->getStartLine();
$end_line = $function->getEndLine();
$function_source = implode('',
array_slice(file($function->getFileName()), $start_line - 1, $end_line - $start_line + 1));
if (preg_match('/(?<={).*(?=})/s', $function_source, $matches)) {
$function_body = $matches[0];
$namespace = __NAMESPACE__;
return eval("
namespace $namespace;
$function_body
");
}
throw new \RuntimeException('Failed to execute statements.');
}
// Below are all the fake functions
function strlen($string) {
return 'fake result';
}
Usage
Then, whenever you need to call a chunk of code using the fake functions, you replace:
function myTestFunction() {
// some code
$length = strlen($mystring);
// some code
}
with:
use function Fake\BuiltIn\Functions\fake;
function myTestFunction() {
fake(function () {
// some code
$length = strlen($mystring);
// some code
});
}
In short, you just add fake function () {
before the chunk and close it with }
below. This requires minimal editing as requested.
Explanation
Basically, eval
appears to be the only built-in way of evaluating, at runtime, a specific chunk of code in the context of a given namespace (unless you can call that chunk within its own namespace to begin with, obviously).
The fake
function:
- receives a
callable
(the statements to execute),
- uses reflection to retrieve the statements' code,
- uses
eval
s to evaluate these statements under the fake namespace.
Demo
https://3v4l.org/LriLW