public function method($path, $closure = null)
{
if ($this->_needToBePatched) {
$layer = Double::classname();
Monkey::patch($this->_reference, $layer);
$this->_needToBePatched = false;
$this->_reference = $layer;
}
$reference = $this->_reference;
if (!$path) {
throw new InvalidArgumentException("Method name can't be empty.");
}
$names = is_array($path) ? $path : [$path];
$this->_chain = [];
$total = count($names);
foreach ($names as $index => $name) {
if (preg_match('/^::.*/', $name)) {
$reference = is_object($reference) ? get_class($reference) : $reference;
}
$hash = Suite::hash($reference);
if (!isset(static::$_registered[$hash])) {
static::$_registered[$hash] = new static($reference);
}
$instance = static::$_registered[$hash];
if (is_object($reference)) {
Suite::register(get_class($reference));
} else {
Suite::register($reference);
}
if (!isset($instance->_methods[$name])) {
$instance->_methods[$name] = [];
$instance->_stubs[$name] = Double::instance();
}
$method = new Method(['parent' => $this, 'reference' => $reference, 'name' => $name]);
$this->_chain[$name] = $method;
array_unshift($instance->_methods[$name], $method);
if ($index < $total - 1) {
$reference = $instance->_stubs[$name];
$method->andReturn($instance->_stubs[$name]);
}
}
$method = end($this->_chain);
if ($closure) {
$method->andRun($closure);
}
return $method;
}