Skip to content

Instantly share code, notes, and snippets.

@maryo
Last active December 14, 2015 17:49
Show Gist options
  • Save maryo/5125089 to your computer and use it in GitHub Desktop.
Save maryo/5125089 to your computer and use it in GitHub Desktop.
Simple function mocker for PHP 5.3
<?php
class FunctionMocker
{
/** @var FunctionMocker[] */
private static $instances = array();
/** @var string */
private $namespace;
/** @var string */
private $function;
/** @var callable $callback */
private $callback;
/** @var int */
private $numberOfCalls = 0;
/**
* @param string $namespace
* @param string $function
*/
private function __construct($namespace, $function)
{
$this->namespace = (string) $namespace;
$this->function = (string) $function;
}
/**
* @param string $namespace
* @param string $function
* @return FunctionMocker
*/
public static function getInstance($namespace, $function)
{
$name = sprintf('%s\%s', $namespace, $function);
if (!isset(self::$instances[$name])) {
self::$instances[$name] = new self($namespace, $function);
}
return self::$instances[$name];
}
/**
* @return int
*/
public function getNumberOfCalls()
{
return $this->numberOfCalls;
}
public function resetNumberOfCalls()
{
$this->numberOfCalls = 0;
}
/**
* @param callable|null $callback
* @throws \InvalidArgumentException
*/
public function mock($callback = null)
{
$this->callback = $callback ?: $this->function;
$function = sprintf('\%s\%s', $this->namespace, $this->function);
if (!is_callable($this->callback, false, $name)) {
throw new \InvalidArgumentException(sprintf('"%s" is not callable', $name));
}
if (function_exists($function)) {
throw new \RuntimeException(sprintf(
'The function "%s" already exists. It can be mocked only once per namespace.',
$function
));
}
eval(sprintf(
'
namespace %s;
function %s()
{
$functionMocker = \%s::getInstance(__NAMESPACE__, "%s");
return $functionMocker->call(func_get_args());
}
',
$this->namespace,
$this->function,
__CLASS__,
$this->function
));
}
/**
* @param array $arguments
* @return mixed
* {@internal}
*/
public function call(array $arguments)
{
$this->numberOfCalls++;
return call_user_func_array($this->callback, $arguments);
}
}
<?php
namespace Test;
$timeMocker = \FunctionMocker::getInstance(__NAMESPACE__, 'time');
$timeMocker->mock(function() {
return '123456';
});
// string(6) "123456" int(1)
var_dump(time(), $timeMocker->getNumberOfCalls());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment