Complex classes like Expectation often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Expectation, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 23 | class Expectation implements ExpectationInterface |
||
| 24 | { |
||
| 25 | /** |
||
| 26 | * Mock object to which this expectation belongs |
||
| 27 | * |
||
| 28 | * @var object |
||
| 29 | */ |
||
| 30 | protected $_mock = null; |
||
| 31 | |||
| 32 | /** |
||
| 33 | * Method name |
||
| 34 | * |
||
| 35 | * @var string |
||
| 36 | */ |
||
| 37 | protected $_name = null; |
||
| 38 | |||
| 39 | /** |
||
| 40 | * Arguments expected by this expectation |
||
| 41 | * |
||
| 42 | * @var array |
||
| 43 | */ |
||
| 44 | protected $_expectedArgs = array(); |
||
| 45 | |||
| 46 | /** |
||
| 47 | * Count validator store |
||
| 48 | * |
||
| 49 | * @var array |
||
| 50 | */ |
||
| 51 | protected $_countValidators = array(); |
||
| 52 | |||
| 53 | /** |
||
| 54 | * The count validator class to use |
||
| 55 | * |
||
| 56 | * @var string |
||
| 57 | */ |
||
| 58 | protected $_countValidatorClass = 'Mockery\CountValidator\Exact'; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * Actual count of calls to this expectation |
||
| 62 | * |
||
| 63 | * @var int |
||
| 64 | */ |
||
| 65 | protected $_actualCount = 0; |
||
| 66 | |||
| 67 | /** |
||
| 68 | * Value to return from this expectation |
||
| 69 | * |
||
| 70 | * @var mixed |
||
| 71 | */ |
||
| 72 | protected $_returnValue = null; |
||
| 73 | |||
| 74 | /** |
||
| 75 | * Array of return values as a queue for multiple return sequence |
||
| 76 | * |
||
| 77 | * @var array |
||
| 78 | */ |
||
| 79 | protected $_returnQueue = array(); |
||
| 80 | |||
| 81 | /** |
||
| 82 | * Array of closures executed with given arguments to generate a result |
||
| 83 | * to be returned |
||
| 84 | * |
||
| 85 | * @var array |
||
| 86 | */ |
||
| 87 | protected $_closureQueue = array(); |
||
| 88 | |||
| 89 | /** |
||
| 90 | * Array of values to be set when this expectation matches |
||
| 91 | * |
||
| 92 | * @var array |
||
| 93 | */ |
||
| 94 | protected $_setQueue = array(); |
||
| 95 | |||
| 96 | /** |
||
| 97 | * Integer representing the call order of this expectation |
||
| 98 | * |
||
| 99 | * @var int |
||
| 100 | */ |
||
| 101 | protected $_orderNumber = null; |
||
| 102 | |||
| 103 | /** |
||
| 104 | * Integer representing the call order of this expectation on a global basis |
||
| 105 | * |
||
| 106 | * @var int |
||
| 107 | */ |
||
| 108 | protected $_globalOrderNumber = null; |
||
| 109 | |||
| 110 | /** |
||
| 111 | * Flag indicating that an exception is expected to be throw (not returned) |
||
| 112 | * |
||
| 113 | * @var bool |
||
| 114 | */ |
||
| 115 | protected $_throw = false; |
||
| 116 | |||
| 117 | /** |
||
| 118 | * Flag indicating whether the order of calling is determined locally or |
||
| 119 | * globally |
||
| 120 | * |
||
| 121 | * @var bool |
||
| 122 | */ |
||
| 123 | protected $_globally = false; |
||
| 124 | |||
| 125 | /** |
||
| 126 | * Flag indicating we expect no arguments |
||
| 127 | * |
||
| 128 | * @var bool |
||
| 129 | */ |
||
| 130 | protected $_noArgsExpectation = false; |
||
| 131 | |||
| 132 | /** |
||
| 133 | * Flag indicating if the return value should be obtained from the original |
||
| 134 | * class method instead of returning predefined values from the return queue |
||
| 135 | * |
||
| 136 | * @var bool |
||
| 137 | */ |
||
| 138 | protected $_passthru = false; |
||
| 139 | |||
| 140 | /** |
||
| 141 | * Constructor |
||
| 142 | * |
||
| 143 | * @param \Mockery\MockInterface $mock |
||
| 144 | * @param string $name |
||
| 145 | */ |
||
| 146 | 301 | public function __construct(\Mockery\MockInterface $mock, $name) |
|
| 147 | { |
||
| 148 | 301 | $this->_mock = $mock; |
|
| 149 | 301 | $this->_name = $name; |
|
| 150 | 301 | } |
|
| 151 | |||
| 152 | /** |
||
| 153 | * Return a string with the method name and arguments formatted |
||
| 154 | * |
||
| 155 | * @param string $name Name of the expected method |
||
| 156 | * @param array $args List of arguments to the method |
||
| 157 | * @return string |
||
| 158 | */ |
||
| 159 | 45 | public function __toString() |
|
| 163 | |||
| 164 | /** |
||
| 165 | * Verify the current call, i.e. that the given arguments match those |
||
| 166 | * of this expectation |
||
| 167 | * |
||
| 168 | * @param array $args |
||
| 169 | * @return mixed |
||
| 170 | */ |
||
| 171 | 231 | public function verifyCall(array $args) |
|
| 185 | |||
| 186 | /** |
||
| 187 | * Sets public properties with queued values to the mock object |
||
| 188 | * |
||
| 189 | * @param array $args |
||
| 190 | * @return mixed |
||
| 191 | */ |
||
| 192 | 224 | protected function _setValues() |
|
| 193 | { |
||
| 194 | 224 | foreach ($this->_setQueue as $name => &$values) { |
|
| 195 | 8 | if (count($values) > 0) { |
|
| 196 | 8 | $value = array_shift($values); |
|
| 197 | 8 | $this->_mock->{$name} = $value; |
|
| 198 | 8 | } |
|
| 199 | 224 | } |
|
| 200 | 224 | } |
|
| 201 | |||
| 202 | /** |
||
| 203 | * Fetch the return value for the matching args |
||
| 204 | * |
||
| 205 | * @param array $args |
||
| 206 | * @return mixed |
||
| 207 | */ |
||
| 208 | 229 | protected function _getReturnValue(array $args) |
|
| 209 | { |
||
| 210 | 229 | if (count($this->_closureQueue) > 1) { |
|
| 211 | return call_user_func_array(array_shift($this->_closureQueue), $args); |
||
| 212 | 229 | } elseif (count($this->_closureQueue) > 0) { |
|
| 213 | 1 | return call_user_func_array(current($this->_closureQueue), $args); |
|
| 214 | 228 | } elseif (count($this->_returnQueue) > 1) { |
|
| 215 | 5 | return array_shift($this->_returnQueue); |
|
| 216 | 227 | } elseif (count($this->_returnQueue) > 0) { |
|
| 217 | 93 | return current($this->_returnQueue); |
|
| 218 | } |
||
| 219 | |||
| 220 | 134 | return $this->_mock->mockery_returnValueForMethod($this->_name); |
|
| 221 | } |
||
| 222 | |||
| 223 | /** |
||
| 224 | * Checks if this expectation is eligible for additional calls |
||
| 225 | * |
||
| 226 | * @return bool |
||
| 227 | */ |
||
| 228 | 272 | public function isEligible() |
|
| 229 | { |
||
| 230 | 272 | foreach ($this->_countValidators as $validator) { |
|
| 231 | 137 | if (!$validator->isEligible($this->_actualCount)) { |
|
| 232 | 22 | return false; |
|
| 233 | } |
||
| 234 | 269 | } |
|
| 235 | 269 | return true; |
|
| 236 | } |
||
| 237 | |||
| 238 | /** |
||
| 239 | * Check if there is a constraint on call count |
||
| 240 | * |
||
| 241 | * @return bool |
||
| 242 | */ |
||
| 243 | public function isCallCountConstrained() |
||
| 247 | |||
| 248 | /** |
||
| 249 | * Verify call order |
||
| 250 | * |
||
| 251 | * @return void |
||
| 252 | */ |
||
| 253 | 231 | public function validateOrder() |
|
| 263 | |||
| 264 | /** |
||
| 265 | * Verify this expectation |
||
| 266 | * |
||
| 267 | * @return bool |
||
| 268 | */ |
||
| 269 | 142 | public function verify() |
|
| 275 | |||
| 276 | /** |
||
| 277 | * Check if passed arguments match an argument expectation |
||
| 278 | * |
||
| 279 | * @param array $args |
||
| 280 | * @return bool |
||
| 281 | */ |
||
| 282 | 277 | public function matchArgs(array $args) |
|
| 307 | |||
| 308 | /** |
||
| 309 | * Check if passed argument matches an argument expectation |
||
| 310 | * |
||
| 311 | * @param array $args |
||
| 312 | * @return bool |
||
| 313 | */ |
||
| 314 | 112 | protected function _matchArg($expected, &$actual) |
|
| 346 | |||
| 347 | /** |
||
| 348 | * Expected argument setter for the expectation |
||
| 349 | * |
||
| 350 | * @param mixed ... |
||
| 351 | * @return self |
||
| 352 | */ |
||
| 353 | 137 | public function with() |
|
| 357 | |||
| 358 | /** |
||
| 359 | * Expected arguments for the expectation passed as an array |
||
| 360 | * |
||
| 361 | * @param array|\Closure $argsOrClosure |
||
| 362 | * @return self |
||
| 363 | */ |
||
| 364 | 149 | public function withArgs($argsOrClosure) |
|
| 380 | |||
| 381 | /** |
||
| 382 | * Set with() as no arguments expected |
||
| 383 | * |
||
| 384 | * @return self |
||
| 385 | */ |
||
| 386 | 10 | public function withNoArgs() |
|
| 392 | |||
| 393 | /** |
||
| 394 | * Set expectation that any arguments are acceptable |
||
| 395 | * |
||
| 396 | * @return self |
||
| 397 | */ |
||
| 398 | 2 | public function withAnyArgs() |
|
| 403 | |||
| 404 | /** |
||
| 405 | * Set a return value, or sequential queue of return values |
||
| 406 | * |
||
| 407 | * @param mixed ... |
||
| 408 | * @return self |
||
| 409 | */ |
||
| 410 | 108 | public function andReturn() |
|
| 415 | |||
| 416 | /** |
||
| 417 | * Return this mock, like a fluent interface |
||
| 418 | * |
||
| 419 | * @return self |
||
| 420 | */ |
||
| 421 | 1 | public function andReturnSelf() |
|
| 425 | |||
| 426 | /** |
||
| 427 | * Set a sequential queue of return values with an array |
||
| 428 | * |
||
| 429 | * @param array $values |
||
| 430 | * @return self |
||
| 431 | */ |
||
| 432 | 2 | public function andReturnValues(array $values) |
|
| 437 | |||
| 438 | /** |
||
| 439 | * Set a closure or sequence of closures with which to generate return |
||
| 440 | * values. The arguments passed to the expected method are passed to the |
||
| 441 | * closures as parameters. |
||
| 442 | * |
||
| 443 | * @param callable ... |
||
| 444 | * @return self |
||
| 445 | */ |
||
| 446 | 1 | public function andReturnUsing() |
|
| 451 | |||
| 452 | /** |
||
| 453 | * Return a self-returning black hole object. |
||
| 454 | * |
||
| 455 | * @return self |
||
| 456 | */ |
||
| 457 | 1 | public function andReturnUndefined() |
|
| 462 | |||
| 463 | /** |
||
| 464 | * Return null. This is merely a language construct for Mock describing. |
||
| 465 | * |
||
| 466 | * @return self |
||
| 467 | */ |
||
| 468 | 1 | public function andReturnNull() |
|
| 472 | |||
| 473 | 1 | public function andReturnFalse() |
|
| 477 | |||
| 478 | 1 | public function andReturnTrue() |
|
| 482 | |||
| 483 | /** |
||
| 484 | * Set Exception class and arguments to that class to be thrown |
||
| 485 | * |
||
| 486 | * @param string|\Exception $exception |
||
| 487 | * @param string $message |
||
| 488 | * @param int $code |
||
| 489 | * @param \Exception $previous |
||
| 490 | * @return self |
||
| 491 | */ |
||
| 492 | 4 | public function andThrow($exception, $message = '', $code = 0, \Exception $previous = null) |
|
| 502 | |||
| 503 | /** |
||
| 504 | * Set Exception classes to be thrown |
||
| 505 | * |
||
| 506 | * @param array $exceptions |
||
| 507 | * @return self |
||
| 508 | */ |
||
| 509 | 2 | public function andThrowExceptions(array $exceptions) |
|
| 519 | |||
| 520 | /** |
||
| 521 | * Register values to be set to a public property each time this expectation occurs |
||
| 522 | * |
||
| 523 | * @param string $name |
||
| 524 | * @param mixed $value |
||
| 525 | * @return self |
||
| 526 | */ |
||
| 527 | 8 | public function andSet($name, $value) |
|
| 534 | |||
| 535 | /** |
||
| 536 | * Alias to andSet(). Allows the natural English construct |
||
| 537 | * - set('foo', 'bar')->andReturn('bar') |
||
| 538 | * |
||
| 539 | * @param string $name |
||
| 540 | * @param mixed $value |
||
| 541 | * @return self |
||
| 542 | */ |
||
| 543 | 3 | public function set($name, $value) |
|
| 547 | |||
| 548 | /** |
||
| 549 | * Indicates this expectation should occur zero or more times |
||
| 550 | * |
||
| 551 | * @return self |
||
| 552 | */ |
||
| 553 | 2 | public function zeroOrMoreTimes() |
|
| 557 | |||
| 558 | /** |
||
| 559 | * Indicates the number of times this expectation should occur |
||
| 560 | * |
||
| 561 | * @param int $limit |
||
| 562 | * @return self |
||
| 563 | */ |
||
| 564 | 152 | public function times($limit = null) |
|
| 573 | |||
| 574 | /** |
||
| 575 | * Indicates that this expectation is never expected to be called |
||
| 576 | * |
||
| 577 | * @return self |
||
| 578 | */ |
||
| 579 | 37 | public function never() |
|
| 583 | |||
| 584 | /** |
||
| 585 | * Indicates that this expectation is expected exactly once |
||
| 586 | * |
||
| 587 | * @return self |
||
| 588 | */ |
||
| 589 | 104 | public function once() |
|
| 593 | |||
| 594 | /** |
||
| 595 | * Indicates that this expectation is expected exactly twice |
||
| 596 | * |
||
| 597 | * @return self |
||
| 598 | */ |
||
| 599 | 18 | public function twice() |
|
| 603 | |||
| 604 | /** |
||
| 605 | * Sets next count validator to the AtLeast instance |
||
| 606 | * |
||
| 607 | * @return self |
||
| 608 | */ |
||
| 609 | 13 | public function atLeast() |
|
| 614 | |||
| 615 | /** |
||
| 616 | * Sets next count validator to the AtMost instance |
||
| 617 | * |
||
| 618 | * @return self |
||
| 619 | */ |
||
| 620 | 7 | public function atMost() |
|
| 625 | |||
| 626 | /** |
||
| 627 | * Shorthand for setting minimum and maximum constraints on call counts |
||
| 628 | * |
||
| 629 | * @param int $minimum |
||
| 630 | * @param int $maximum |
||
| 631 | */ |
||
| 632 | public function between($minimum, $maximum) |
||
| 636 | |||
| 637 | /** |
||
| 638 | * Indicates that this expectation must be called in a specific given order |
||
| 639 | * |
||
| 640 | * @param string $group Name of the ordered group |
||
| 641 | * @return self |
||
| 642 | */ |
||
| 643 | 20 | public function ordered($group = null) |
|
| 653 | |||
| 654 | /** |
||
| 655 | * Indicates call order should apply globally |
||
| 656 | * |
||
| 657 | * @return self |
||
| 658 | */ |
||
| 659 | 1 | public function globally() |
|
| 664 | |||
| 665 | /** |
||
| 666 | * Setup the ordering tracking on the mock or mock container |
||
| 667 | * |
||
| 668 | * @param string $group |
||
| 669 | * @param object $ordering |
||
| 670 | * @return int |
||
| 671 | */ |
||
| 672 | 20 | protected function _defineOrdered($group, $ordering) |
|
| 685 | |||
| 686 | /** |
||
| 687 | * Return order number |
||
| 688 | * |
||
| 689 | * @return int |
||
| 690 | */ |
||
| 691 | 1 | public function getOrderNumber() |
|
| 695 | |||
| 696 | /** |
||
| 697 | * Mark this expectation as being a default |
||
| 698 | * |
||
| 699 | * @return self |
||
| 700 | */ |
||
| 701 | 24 | public function byDefault() |
|
| 709 | |||
| 710 | /** |
||
| 711 | * Return the parent mock of the expectation |
||
| 712 | * |
||
| 713 | * @return \Mockery\MockInterface |
||
| 714 | */ |
||
| 715 | 27 | public function getMock() |
|
| 719 | |||
| 720 | /** |
||
| 721 | * Flag this expectation as calling the original class method with the |
||
| 722 | * any provided arguments instead of using a return value queue. |
||
| 723 | * |
||
| 724 | * @return self |
||
| 725 | */ |
||
| 726 | 3 | public function passthru() |
|
| 737 | |||
| 738 | /** |
||
| 739 | * Cloning logic |
||
| 740 | * |
||
| 741 | */ |
||
| 742 | 8 | public function __clone() |
|
| 751 | |||
| 752 | 5 | public function getName() |
|
| 756 | } |
||
| 757 |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.jsonfile (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.jsonto be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
requireorrequire-devsection?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceofchecks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.