function = ($function === null) ? function (){} : $function; } public function __invoke() { $this->timesCalled++; $this->lastArgs = func_get_args(); return call_user_func_array($this->function, func_get_args()); } public function returns($arg) { $this->function = function () use ($arg) { return $arg; }; return $this; } public function hasBeenCalled() { return !!$this->timesCalled; } public function reset() { $this->timesCalled = 0; $this->lastArgs = null; } public function hasBeenCalledWithArgs() { $newArgs = func_get_args(); $oldArgs = $this->lastArgs; $argumentsMatchAssertion = json_encode($newArgs) === json_encode($oldArgs); return $this->timesCalled && $argumentsMatchAssertion; } } class Mock { public static function stub() { return new Stub; } public static function setStatics($statics) { foreach ($statics as $key => $static) { static::$functionList[$key] = $static; } } public static function __callStatic($key, $arguments) { if (static::$functionList[$key]) { $function = static::$functionList[$key]; return call_user_func_array($function, $arguments); } } public static function get($key) { return static::$functionList[$key]; } public function __construct($arguments = array()) { if (!empty($arguments)) { foreach ($arguments as $property => $argument) { if ($argument instanceOf Closure) { $this->{$property} = self::stub($argument); } else { $this->{$property} = $argument; } } } } public function __set($key, $value){ if ($value instanceOf Closure) { $this->{$key} = self::stub($value); } else { $this->{$key} = $value; } } public function __call($method, $arguments) { if (isset($this->{$method}) && is_callable($this->{$method})) { return call_user_func_array($this->{$method}, $arguments); } else if (!self::__callStatic($method, $arguments)) { throw new Exception("Fatal error: Call to undefined method stdObject::{$method}()"); } } }