class CallCenter
Calls receiver & manager.
@author Konstantin Kudryashov <ever.zet@gmail.com>
Hierarchy
- class \Prophecy\Call\CallCenter
Expanded class hierarchy of CallCenter
2 files declare their use of CallCenter
- ObjectProphecy.php in vendor/
phpspec/ prophecy/ src/ Prophecy/ Prophecy/ ObjectProphecy.php - Prophet.php in vendor/
phpspec/ prophecy/ src/ Prophecy/ Prophet.php
File
-
vendor/
phpspec/ prophecy/ src/ Prophecy/ Call/ CallCenter.php, line 27
Namespace
Prophecy\CallView source
class CallCenter {
private $util;
/**
* @var Call[]
*/
private $recordedCalls = array();
/**
* @var SplObjectStorage<Call, ObjectProphecy<object>>
*/
private $unexpectedCalls;
/**
* Initializes call center.
*
* @param StringUtil $util
*/
public function __construct(?StringUtil $util = null) {
$this->util = $util ?: new StringUtil();
$this->unexpectedCalls = new SplObjectStorage();
}
/**
* Makes and records specific method call for object prophecy.
*
* @param ObjectProphecy<object> $prophecy
* @param string $methodName
* @param array<mixed> $arguments
*
* @return mixed Returns null if no promise for prophecy found or promise return value.
*
* @throws \Prophecy\Exception\Call\UnexpectedCallException If no appropriate method prophecy found
*/
public function makeCall(ObjectProphecy $prophecy, $methodName, array $arguments) {
// For efficiency exclude 'args' from the generated backtrace
// Limit backtrace to last 3 calls as we don't use the rest
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
$file = $line = null;
if (isset($backtrace[2]) && isset($backtrace[2]['file']) && isset($backtrace[2]['line'])) {
$file = $backtrace[2]['file'];
$line = $backtrace[2]['line'];
}
// If no method prophecies defined, then it's a dummy, so we'll just return null
if ('__destruct' === strtolower($methodName) || 0 == count($prophecy->getMethodProphecies())) {
$this->recordedCalls[] = new Call($methodName, $arguments, null, null, $file, $line);
return null;
}
// There are method prophecies, so it's a fake/stub. Searching prophecy for this call
$matches = $this->findMethodProphecies($prophecy, $methodName, $arguments);
// If fake/stub doesn't have method prophecy for this call - throw exception
if (!count($matches)) {
$this->unexpectedCalls
->attach(new Call($methodName, $arguments, null, null, $file, $line), $prophecy);
$this->recordedCalls[] = new Call($methodName, $arguments, null, null, $file, $line);
return null;
}
// Sort matches by their score value
@usort($matches, function ($match1, $match2) {
return $match2[0] - $match1[0];
});
$score = $matches[0][0];
// If Highest rated method prophecy has a promise - execute it or return null instead
$methodProphecy = $matches[0][1];
$returnValue = null;
$exception = null;
if ($promise = $methodProphecy->getPromise()) {
try {
$returnValue = $promise->execute($arguments, $prophecy, $methodProphecy);
} catch (\Exception $e) {
$exception = $e;
}
}
if ($methodProphecy->hasReturnVoid() && $returnValue !== null) {
throw new MethodProphecyException("The method \"{$methodName}\" has a void return type, but the promise returned a value", $methodProphecy);
}
$this->recordedCalls[] = $call = new Call($methodName, $arguments, $returnValue, $exception, $file, $line);
$call->addScore($methodProphecy->getArgumentsWildcard(), $score);
if (null !== $exception) {
throw $exception;
}
return $returnValue;
}
/**
* Searches for calls by method name & arguments wildcard.
*
* @param string $methodName
* @param ArgumentsWildcard $wildcard
*
* @return list<Call>
*/
public function findCalls($methodName, ArgumentsWildcard $wildcard) {
$methodName = strtolower($methodName);
return array_values(array_filter($this->recordedCalls, function (Call $call) use ($methodName, $wildcard) {
return $methodName === strtolower($call->getMethodName()) && 0 < $call->getScore($wildcard);
}));
}
/**
* @return void
* @throws UnexpectedCallException
*/
public function checkUnexpectedCalls() {
foreach ($this->unexpectedCalls as $call) {
$prophecy = $this->unexpectedCalls[$call];
// If fake/stub doesn't have method prophecy for this call - throw exception
if (!count($this->findMethodProphecies($prophecy, $call->getMethodName(), $call->getArguments()))) {
throw $this->createUnexpectedCallException($prophecy, $call->getMethodName(), $call->getArguments());
}
}
}
/**
* @param ObjectProphecy<object> $prophecy
* @param string $methodName
* @param array<mixed> $arguments
*
* @return UnexpectedCallException
*/
private function createUnexpectedCallException(ObjectProphecy $prophecy, $methodName, array $arguments) {
$classname = get_class($prophecy->reveal());
$indentationLength = 8;
// looks good
$argstring = implode(",\n", $this->indentArguments(array_map(array(
$this->util,
'stringify',
), $arguments), $indentationLength));
$expected = array();
foreach (array_merge(...array_values($prophecy->getMethodProphecies())) as $methodProphecy) {
$expected[] = sprintf(" - %s(\n" . "%s\n" . " )", $methodProphecy->getMethodName(), implode(",\n", $this->indentArguments(array_map('strval', $methodProphecy->getArgumentsWildcard()
->getTokens()), $indentationLength)));
}
return new UnexpectedCallException(sprintf("Unexpected method call on %s:\n" . " - %s(\n" . "%s\n" . " )\n" . "expected calls were:\n" . "%s", $classname, $methodName, $argstring, implode("\n", $expected)), $prophecy, $methodName, $arguments);
}
/**
* @param string[] $arguments
* @param int $indentationLength
*
* @return string[]
*/
private function indentArguments(array $arguments, $indentationLength) {
return preg_replace_callback('/^/m', function () use ($indentationLength) {
return str_repeat(' ', $indentationLength);
}, $arguments);
}
/**
* @param ObjectProphecy<object> $prophecy
* @param string $methodName
* @param array<mixed> $arguments
*
* @return array
*
* @phpstan-return list<array{int, MethodProphecy}>
*/
private function findMethodProphecies(ObjectProphecy $prophecy, $methodName, array $arguments) {
$matches = array();
foreach ($prophecy->getMethodProphecies($methodName) as $methodProphecy) {
if (0 < ($score = $methodProphecy->getArgumentsWildcard()
->scoreArguments($arguments))) {
$matches[] = array(
$score,
$methodProphecy,
);
}
}
return $matches;
}
}
Members
Title Sort descending | Modifiers | Object type | Summary |
---|---|---|---|
CallCenter::$recordedCalls | private | property | |
CallCenter::$unexpectedCalls | private | property | |
CallCenter::$util | private | property | |
CallCenter::checkUnexpectedCalls | public | function | |
CallCenter::createUnexpectedCallException | private | function | |
CallCenter::findCalls | public | function | Searches for calls by method name & arguments wildcard. |
CallCenter::findMethodProphecies | private | function | @phpstan-return list<array{int, MethodProphecy}> |
CallCenter::indentArguments | private | function | |
CallCenter::makeCall | public | function | Makes and records specific method call for object prophecy. |
CallCenter::__construct | public | function | Initializes call center. |