Mockery::setContainer()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * Mockery
4
 *
5
 * LICENSE
6
 *
7
 * This source file is subject to the new BSD license that is bundled
8
 * with this package in the file LICENSE.txt.
9
 * It is also available through the world-wide-web at this URL:
10
 * http://github.com/padraic/mockery/blob/master/LICENSE
11
 * If you did not receive a copy of the license and are unable to
12
 * obtain it through the world-wide-web, please send an email
13
 * to [email protected] so we can send you a copy immediately.
14
 *
15
 * @category   Mockery
16
 * @package    Mockery
17
 * @copyright  Copyright (c) 2010 Pádraic Brady (http://blog.astrumfutura.com)
18
 * @license    http://github.com/padraic/mockery/blob/master/LICENSE New BSD License
19
 */
20
21
use Mockery\ExpectationInterface;
22
use Mockery\Generator\CachingGenerator;
23
use Mockery\Generator\Generator;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Generator.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
24
use Mockery\Generator\MockConfigurationBuilder;
25
use Mockery\Generator\StringManipulationGenerator;
26
use Mockery\Loader\EvalLoader;
27
use Mockery\Loader\Loader;
28
use Mockery\Matcher\MatcherAbstract;
29
30
class Mockery
31
{
32
    const BLOCKS = 'Mockery_Forward_Blocks';
33
34
    /**
35
     * Global container to hold all mocks for the current unit test running.
36
     *
37
     * @var \Mockery\Container
38
     */
39
    protected static $_container = null;
40
41
    /**
42
     * Global configuration handler containing configuration options.
43
     *
44
     * @var \Mockery\Configuration
45
     */
46
    protected static $_config = null;
47
48
    /**
49
     * @var \Mockery\Generator\Generator
50
     */
51
    protected static $_generator;
52
53
    /**
54
     * @var \Mockery\Loader\Loader
55
     */
56
    protected static $_loader;
57
58
    /**
59
     * @var array
60
     */
61
    private static $_filesToCleanUp = [];
62
63
    /**
64
     * Defines the global helper functions
65
     * 
66
     * @return void
67
     */
68 3
    public static function globalHelpers()
69
    {
70 3
        require_once __DIR__.'/helpers.php';
71 3
    }
72
73
    /**
74
     * Static shortcut to \Mockery\Container::mock().
75
     *
76
     * @param array $args
77
     *
78
     * @return \Mockery\MockInterface
79
     */
80 38
    public static function mock(...$args)
81
    {
82 38
        return call_user_func_array(array(self::getContainer(), 'mock'), $args);
83
    }
84
85
    /**
86
     * Static and semantic shortcut for getting a mock from the container
87
     * and applying the spy's expected behavior into it.
88
     *
89
     * @param array $args
90
     *
91
     * @return \Mockery\MockInterface
92
     */
93 9
    public static function spy(...$args)
94
    {
95 9
        return call_user_func_array(array(self::getContainer(), 'mock'), $args)->shouldIgnoreMissing();
96
    }
97
98
    /**
99
     * Static and Semantic shortcut to \Mockery\Container::mock().
100
     *
101
     * @param array $args
102
     *
103
     * @return \Mockery\MockInterface
104
     */
105
    public static function instanceMock(...$args)
106
    {
107
        return call_user_func_array(array(self::getContainer(), 'mock'), $args);
108
    }
109
110
    /**
111
     * Static shortcut to \Mockery\Container::mock(), first argument names the mock.
112
     *
113
     * @param array $args
114
     *
115
     * @return \Mockery\MockInterface
116
     */
117 5
    public static function namedMock(...$args)
118
    {
119 5
        $name = array_shift($args);
120
121 5
        $builder = new MockConfigurationBuilder();
122 5
        $builder->setName($name);
123
124 5
        array_unshift($args, $builder);
125
126 5
        return call_user_func_array(array(self::getContainer(), 'mock'), $args);
127
    }
128
129
    /**
130
     * Static shortcut to \Mockery\Container::self().
131
     *
132
     * @throws LogicException
133
     *
134
     * @return \Mockery\MockInterface
135
     */
136 2
    public static function self()
137
    {
138 2
        if (is_null(self::$_container)) {
139 1
            throw new \LogicException('You have not declared any mocks yet');
140
        }
141
142 1
        return self::$_container->self();
143
    }
144
145
    /**
146
     * Static shortcut to closing up and verifying all mocks in the global
147
     * container, and resetting the container static variable to null.
148
     *
149
     * @return void
150
     */
151 414
    public static function close()
152
    {
153 414
        foreach (self::$_filesToCleanUp as $fileName) {
154 18
            @unlink($fileName);
155 414
        }
156 414
        self::$_filesToCleanUp = [];
157
158 414
        if (is_null(self::$_container)) {
159
            return;
160
        }
161
162 414
        self::$_container->mockery_teardown();
163 412
        self::$_container->mockery_close();
164 412
        self::$_container = null;
165 412
    }
166
167
    /**
168
     * Static fetching of a mock associated with a name or explicit class poser.
169
     *
170
     * @param $name
171
     *
172
     * @return \Mockery\Mock
173
     */
174 11
    public static function fetchMock($name)
175
    {
176 11
        return self::$_container->fetchMock($name);
177
    }
178
179
    /**
180
     * Lazy loader and getter for
181
     * the container property.
182
     *
183
     * @return Mockery\Container
184
     */
185 438
    public static function getContainer()
186
    {
187 438
        if (is_null(self::$_container)) {
188 407
            self::$_container = new Mockery\Container(self::getGenerator(), self::getLoader());
189 407
        }
190
191 438
        return self::$_container;
192
    }
193
194
    /**
195
     * Setter for the $_generator static propery.
196
     *
197
     * @param \Mockery\Generator\Generator $generator
198
     */
199
    public static function setGenerator(Generator $generator)
200
    {
201
        self::$_generator = $generator;
202
    }
203
204
    /**
205
     * Lazy loader method and getter for
206
     * the generator property.
207
     *
208
     * @return Generator
209
     */
210 407
    public static function getGenerator()
211
    {
212 407
        if (is_null(self::$_generator)) {
213 1
            self::$_generator = self::getDefaultGenerator();
214 1
        }
215
216 407
        return self::$_generator;
217
    }
218
219
    /**
220
     * Creates and returns a default generator
221
     * used inside this class.
222
     *
223
     * @return CachingGenerator
224
     */
225 400
    public static function getDefaultGenerator()
226
    {
227 400
        return new CachingGenerator(StringManipulationGenerator::withDefaultPasses());
228
    }
229
230
    /**
231
     * Setter for the $_loader static property.
232
     *
233
     * @param Loader $loader
234
     */
235
    public static function setLoader(Loader $loader)
236
    {
237
        self::$_loader = $loader;
238
    }
239
240
    /**
241
     * Lazy loader method and getter for
242
     * the $_loader property.
243
     *
244
     * @return Loader
245
     */
246 407
    public static function getLoader()
247
    {
248 407
        if (is_null(self::$_loader)) {
249 1
            self::$_loader = self::getDefaultLoader();
250 1
        }
251
252 407
        return self::$_loader;
253
    }
254
255
    /**
256
     * Gets an EvalLoader to be used as default.
257
     *
258
     * @return EvalLoader
259
     */
260 274
    public static function getDefaultLoader()
261
    {
262 274
        return new EvalLoader();
263
    }
264
265
    /**
266
     * Set the container.
267
     *
268
     * @param \Mockery\Container $container
269
     *
270
     * @return \Mockery\Container
271
     */
272 18
    public static function setContainer(Mockery\Container $container)
273
    {
274 18
        return self::$_container = $container;
275
    }
276
277
    /**
278
     * Reset the container to null.
279
     *
280
     * @return void
281
     */
282 15
    public static function resetContainer()
283
    {
284 15
        self::$_container = null;
285 15
    }
286
287
    /**
288
     * Return instance of ANY matcher.
289
     *
290
     * @return \Mockery\Matcher\Any
291
     */
292 5
    public static function any()
293
    {
294 5
        return new \Mockery\Matcher\Any();
295
    }
296
297
    /**
298
     * Return instance of TYPE matcher.
299
     *
300
     * @param $expected
301
     *
302
     * @return \Mockery\Matcher\Type
303
     */
304 48
    public static function type($expected)
305
    {
306 48
        return new \Mockery\Matcher\Type($expected);
307
    }
308
309
    /**
310
     * Return instance of DUCKTYPE matcher.
311
     *
312
     * @param array $args
313
     *
314
     * @return \Mockery\Matcher\Ducktype
315
     */
316 3
    public static function ducktype(...$args)
317
    {
318 3
        return new \Mockery\Matcher\Ducktype($args);
319
    }
320
321
    /**
322
     * Return instance of SUBSET matcher.
323
     *
324
     * @param array $part
325
     * @param bool $strict - (Optional) True for strict comparison, false for loose
326
     *
327
     * @return \Mockery\Matcher\Subset
328
     */
329 3
    public static function subset(array $part, $strict = true)
330
    {
331 3
        return new \Mockery\Matcher\Subset($part, $strict);
332
    }
333
334
    /**
335
     * Return instance of CONTAINS matcher.
336
     *
337
     * @param array $args
338
     *
339
     * @return \Mockery\Matcher\Contains
340
     */
341 3
    public static function contains(...$args)
342
    {
343 3
        return new \Mockery\Matcher\Contains($args);
344
    }
345
346
    /**
347
     * Return instance of HASKEY matcher.
348
     *
349
     * @param $key
350
     *
351
     * @return \Mockery\Matcher\HasKey
352
     */
353 4
    public static function hasKey($key)
354
    {
355 4
        return new \Mockery\Matcher\HasKey($key);
356
    }
357
358
    /**
359
     * Return instance of HASVALUE matcher.
360
     *
361
     * @param $val
362
     *
363
     * @return \Mockery\Matcher\HasValue
364
     */
365 3
    public static function hasValue($val)
366
    {
367 3
        return new \Mockery\Matcher\HasValue($val);
368
    }
369
370
    /**
371
     * Return instance of CLOSURE matcher.
372
     *
373
     * @param $closure
374
     *
375
     * @return \Mockery\Matcher\Closure
376
     */
377 7
    public static function on($closure)
378
    {
379 7
        return new \Mockery\Matcher\Closure($closure);
380
    }
381
382
    /**
383
     * Return instance of MUSTBE matcher.
384
     *
385
     * @param $expected
386
     *
387
     * @return \Mockery\Matcher\MustBe
388
     */
389 6
    public static function mustBe($expected)
390
    {
391 6
        return new \Mockery\Matcher\MustBe($expected);
0 ignored issues
show
Deprecated Code introduced by
The class Mockery\Matcher\MustBe has been deprecated with message: 2.0 Due to ambiguity, use Hamcrest or PHPUnit equivalents

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
392
    }
393
394
    /**
395
     * Return instance of NOT matcher.
396
     *
397
     * @param $expected
398
     *
399
     * @return \Mockery\Matcher\Not
400
     */
401 3
    public static function not($expected)
402
    {
403 3
        return new \Mockery\Matcher\Not($expected);
404
    }
405
406
    /**
407
     * Return instance of ANYOF matcher.
408
     *
409
     * @param array $args
410
     *
411
     * @return \Mockery\Matcher\AnyOf
412
     */
413 3
    public static function anyOf(...$args)
414
    {
415 3
        return new \Mockery\Matcher\AnyOf($args);
416
    }
417
418
    /**
419
     * Return instance of NOTANYOF matcher.
420
     *
421
     * @param array $args
422
     *
423
     * @return \Mockery\Matcher\NotAnyOf
424
     */
425 3
    public static function notAnyOf(...$args)
426
    {
427 3
        return new \Mockery\Matcher\NotAnyOf($args);
428
    }
429
430
    /**
431
     * Lazy loader and Getter for the global
432
     * configuration container.
433
     *
434
     * @return \Mockery\Configuration
435
     */
436 426
    public static function getConfiguration()
437
    {
438 426
        if (is_null(self::$_config)) {
439 1
            self::$_config = new \Mockery\Configuration();
440 1
        }
441
442 426
        return self::$_config;
443
    }
444
445
    /**
446
     * Utility method to format method name and arguments into a string.
447
     *
448
     * @param string $method
449
     * @param array $arguments
450
     *
451
     * @return string
452
     */
453 93
    public static function formatArgs($method, array $arguments = null)
454
    {
455 93
        if (is_null($arguments)) {
456
            return $method . '()';
457
        }
458
459 93
        $formattedArguments = array();
460 93
        foreach ($arguments as $argument) {
461 92
            $formattedArguments[] = self::formatArgument($argument);
462 93
        }
463
464 93
        return $method . '(' . implode(', ', $formattedArguments) . ')';
465
    }
466
467
    /**
468
     * Gets the string representation
469
     * of any passed argument.
470
     *
471
     * @param $argument
472
     * @param $depth
473
     *
474
     * @return string
475
     */
476 92
    private static function formatArgument($argument, $depth = 0)
477
    {
478 92
        if ($argument instanceOf MatcherAbstract) {
479 35
            return (string) $argument;
480
        }
481
482 57
        if (is_object($argument)) {
483 7
            return 'object(' . get_class($argument) . ')';
484
        }
485
486 54
        if (is_int($argument) || is_float($argument)) {
487 37
            return $argument;
488
        }
489
490 26
        if (is_array($argument)) {
491 13
            if ($depth === 1) {
492 2
                $argument = '[...]';
493 2
            } else {
494 13
                $sample = array();
495 13
                foreach ($argument as $key => $value) {
496 12
                    $key = is_int($key) ? $key : "'$key'";
497 12
                    $value = self::formatArgument($value, $depth + 1);
498 12
                    $sample[] = "$key => $value";
499 13
                }
500
501 13
                $argument = "[".implode(", ", $sample)."]";
502
            }
503
504 13
            return ((strlen($argument) > 1000) ? substr($argument, 0, 1000).'...]' : $argument);
505
        }
506
507 17
        if (is_bool($argument)) {
508 1
            return $argument ? 'true' : 'false';
509
        }
510
511 16
        if (is_resource($argument)) {
512 2
            return 'resource(...)';
513
        }
514
515 14
        if (is_null($argument)) {
516 1
            return 'NULL';
517
        }
518
519 13
        return "'".(string) $argument."'";
520
    }
521
522
    /**
523
     * Utility function to format objects to printable arrays.
524
     *
525
     * @param array $objects
526
     *
527
     * @return string
528
     */
529 52
    public static function formatObjects(array $objects = null)
530
    {
531 52
        static $formatting;
532
533 52
        if ($formatting) {
534 1
            return '[Recursion]';
535
        }
536
537 52
        if (is_null($objects)) {
538
            return '';
539
        }
540
541 52
        $objects = array_filter($objects, 'is_object');
542 52
        if (empty($objects)) {
543 45
            return '';
544
        }
545
546 7
        $formatting = true;
547 7
        $parts = array();
548
549 7
        foreach ($objects as $object) {
550 7
            $parts[get_class($object)] = self::objectToArray($object);
551 7
        }
552
553 7
        $formatting = false;
554
555 7
        return 'Objects: ( ' . var_export($parts, true) . ')';
556
    }
557
558
    /**
559
     * Utility function to turn public properties and public get* and is* method values into an array.
560
     *
561
     * @param     $object
562
     * @param int $nesting
563
     *
564
     * @return array
565
     */
566 7
    private static function objectToArray($object, $nesting = 3)
567
    {
568 7
        if ($nesting == 0) {
569
            return array('...');
570
        }
571
572
        return array(
573 7
            'class' => get_class($object),
574 7
            'properties' => self::extractInstancePublicProperties($object, $nesting),
575 7
            'getters' => self::extractGetters($object, $nesting)
576 7
        );
577
    }
578
579
    /**
580
     * Returns all public instance properties.
581
     *
582
     * @param $object
583
     * @param $nesting
584
     *
585
     * @return array
586
     */
587 7
    private static function extractInstancePublicProperties($object, $nesting)
588
    {
589 7
        $reflection = new \ReflectionClass(get_class($object));
590 7
        $properties = $reflection->getProperties(\ReflectionProperty::IS_PUBLIC);
591 7
        $cleanedProperties = array();
592
593 7
        foreach ($properties as $publicProperty) {
594 1
            if (!$publicProperty->isStatic()) {
595
                $name = $publicProperty->getName();
596
                $cleanedProperties[$name] = self::cleanupNesting($object->$name, $nesting);
597
            }
598 7
        }
599
600 7
        return $cleanedProperties;
601
    }
602
603
    /**
604
     * Returns all object getters.
605
     *
606
     * @param $object
607
     * @param $nesting
608
     *
609
     * @return array
610
     */
611 7
    private static function extractGetters($object, $nesting)
612
    {
613 7
        $reflection = new \ReflectionClass(get_class($object));
614 7
        $publicMethods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
615 7
        $getters = array();
616
617 7
        foreach ($publicMethods as $publicMethod) {
618 5
            $name = $publicMethod->getName();
0 ignored issues
show
Bug introduced by
Consider using $publicMethod->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
619 5
            $irrelevantName = (substr($name, 0, 3) !== 'get' && substr($name, 0, 2) !== 'is');
620 5
            $isStatic = $publicMethod->isStatic();
621 5
            $numberOfParameters = $publicMethod->getNumberOfParameters();
622
623 5
            if ($irrelevantName || $numberOfParameters != 0 || $isStatic) {
624 5
                continue;
625
            }
626
627
            try {
628 2
                $getters[$name] = self::cleanupNesting($object->$name(), $nesting);
629 2
            } catch (\Exception $e) {
630 1
                $getters[$name] = '!! ' . get_class($e) . ': ' . $e->getMessage() . ' !!';
631
            }
632 7
        }
633
634 7
        return $getters;
635
    }
636
637
    /**
638
     * Utility method used for recursively generating
639
     * an object or array representation.
640
     *
641
     * @param $argument
642
     * @param $nesting
643
     *
644
     * @return mixed
645
     */
646 1
    private static function cleanupNesting($argument, $nesting)
647
    {
648 1
        if (is_object($argument)) {
649
            $object = self::objectToArray($argument, $nesting - 1);
650
            $object['class'] = get_class($argument);
651
652
            return $object;
653
        }
654
655 1
        if (is_array($argument)) {
656 1
            return self::cleanupArray($argument, $nesting - 1);
657
        }
658
659 1
        return $argument;
660
    }
661
662
    /**
663
     * Utility method for recursively
664
     * gerating a representation
665
     * of the given array.
666
     *
667
     * @param array $argument
668
     * @param int $nesting
669
     *
670
     * @return mixed
671
     */
672 1
    private static function cleanupArray($argument, $nesting = 3)
673
    {
674 1
        if ($nesting == 0) {
675 1
            return '...';
676
        }
677
678 1
        foreach ($argument as $key => $value) {
679 1
            if (is_array($value)) {
680 1
                $argument[$key] = self::cleanupArray($value, $nesting - 1);
681 1
            } elseif (is_object($value)) {
682
                $argument[$key] = self::objectToArray($value, $nesting - 1);
683
            }
684 1
        }
685
686 1
        return $argument;
687
    }
688
689
    /**
690
     * Utility function to parse shouldReceive() arguments and generate
691
     * expectations from such as needed.
692
     *
693
     * @param Mockery\MockInterface $mock
694
     * @param array $args
695
     * @param callable $add
696
     * @return \Mockery\CompositeExpectation
697
     */
698 308
    public static function parseShouldReturnArgs(\Mockery\MockInterface $mock, $args, $add)
699
    {
700 308
        $composite = new \Mockery\CompositeExpectation();
701
702 308
        foreach ($args as $arg) {
703 308
            if (is_array($arg)) {
704 18
                foreach ($arg as $k => $v) {
705 18
                    $expectation = self::buildDemeterChain($mock, $k, $add)->andReturn($v);
0 ignored issues
show
Unused Code introduced by
The call to ExpectationInterface::andReturn() has too many arguments starting with $v.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
706 18
                    $composite->add($expectation);
0 ignored issues
show
Documentation introduced by
$expectation is of type object<Mockery\ExpectationInterface>, but the function expects a object<Mockery\Expectati...y\CompositeExpectation>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
707 18
                }
708 308
            } elseif (is_string($arg)) {
709 294
                $expectation = self::buildDemeterChain($mock, $arg, $add);
710 288
                $composite->add($expectation);
0 ignored issues
show
Documentation introduced by
$expectation is of type object<Mockery\ExpectationInterface>, but the function expects a object<Mockery\Expectati...y\CompositeExpectation>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
711 288
            }
712 302
        }
713
714 302
        return $composite;
715
    }
716
717
    /**
718
     * Sets up expectations on the members of the CompositeExpectation and
719
     * builds up any demeter chain that was passed to shouldReceive.
720
     *
721
     * @param \Mockery\MockInterface $mock
722
     * @param string $arg
723
     * @param callable $add
724
     * @throws Mockery\Exception
725
     * @return \Mockery\ExpectationInterface
726
     */
727 308
    protected static function buildDemeterChain(\Mockery\MockInterface $mock, $arg, $add)
728
    {
729
        /** @var Mockery\Container $container */
730 308
        $container = $mock->mockery_getContainer();
731 308
        $methodNames = explode('->', $arg);
732 308
        reset($methodNames);
733
734 308
        if (!\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed()
735 308
            && !$mock->mockery_isAnonymous()
736 308
            && !in_array(current($methodNames), $mock->mockery_getMockableMethods())
737 308
        ) {
738 4
            throw new \Mockery\Exception(
739
                'Mockery\'s configuration currently forbids mocking the method '
740 4
                . current($methodNames) . ' as it does not exist on the class or object '
741 4
                . 'being mocked'
742 4
            );
743
        }
744
745
        /** @var ExpectationInterface|null $expectations */
746 304
        $expectations = null;
747
748
        /** @var Callable $nextExp */
749
        $nextExp = function ($method) use ($add) {
750 304
            return $add($method);
751 304
        };
752
753 304
        while (true) {
754 304
            $method = array_shift($methodNames);
755 304
            $expectations = $mock->mockery_getExpectationsFor($method);
756
757 304
            if (is_null($expectations) || self::noMoreElementsInChain($methodNames)) {
758 304
                $expectations = $nextExp($method);
759 302
                if (self::noMoreElementsInChain($methodNames)) {
760 302
                    break;
761
                }
762
763 11
                $mock = self::getNewDemeterMock($container, $method, $expectations);
764 11
            } else {
765 5
                $demeterMockKey = $container->getKeyOfDemeterMockFor($method);
766 5
                if ($demeterMockKey) {
767 5
                    $mock = self::getExistingDemeterMock($container, $demeterMockKey);
768 5
                }
769
            }
770
771 11
            $nextExp = function ($n) use ($mock) {
772 11
                return $mock->shouldReceive($n);
773 11
            };
774 11
        }
775
776 302
        return $expectations;
777
    }
778
779
    /**
780
     * Gets a new demeter configured
781
     * mock from the container.
782
     *
783
     * @param \Mockery\Container $container
784
     * @param string $method
785
     * @param Mockery\ExpectationInterface $exp
786
     *
787
     * @return \Mockery\Mock
788
     */
789 11
    private static function getNewDemeterMock(
790
        Mockery\Container $container,
791
        $method,
792
        Mockery\ExpectationInterface $exp
793
    ) {
794 11
        $mock = $container->mock('demeter_' . $method);
795 11
        $exp->andReturn($mock);
796
797 11
        return $mock;
798
    }
799
800
    /**
801
     * Gets an specific demeter mock from
802
     * the ones kept by the container.
803
     *
804
     * @param \Mockery\Container $container
805
     * @param string $demeterMockKey
806
     *
807
     * @return mixed
808
     */
809 5
    private static function getExistingDemeterMock(
810
        Mockery\Container $container,
811
        $demeterMockKey
812
    ) {
813 5
        $mocks = $container->getMocks();
814 5
        $mock = $mocks[$demeterMockKey];
815
816 5
        return $mock;
817
    }
818
819
    /**
820
     * Checks if the passed array representing a demeter
821
     * chain with the method names is empty.
822
     *
823
     * @param array $methodNames
824
     *
825
     * @return bool
826
     */
827 302
    private static function noMoreElementsInChain(array $methodNames)
828
    {
829 302
        return empty($methodNames);
830
    }
831
832 17
    public static function declareClass($fqn)
833
    {
834 17
        return static::declareType($fqn, "class");
0 ignored issues
show
Bug introduced by
Since declareType() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of declareType() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
835
    }
836
837 2
    public static function declareInterface($fqn)
838
    {
839 2
        return static::declareType($fqn, "interface");
0 ignored issues
show
Bug introduced by
Since declareType() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of declareType() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
840
    }
841
842 18
    private static function declareType($fqn, $type)
843
    {
844 18
        $targetCode = "<?php ";
845 18
        $shortName = $fqn;
846
847 18
        if (strpos($fqn, "\\")) {
848 4
            $parts = explode("\\", $fqn);
849
850 4
            $shortName = trim(array_pop($parts));
851 4
            $namespace = implode("\\", $parts);
852
853 4
            $targetCode.= "namespace $namespace;\n";
854 4
        }
855
856 18
        $targetCode.= "$type $shortName {} ";
857
858
        /*
859
         * We could eval here, but it doesn't play well with the way
860
         * PHPUnit tries to backup global state and the require definition
861
         * loader
862
         */
863 18
        $tmpfname = tempnam(sys_get_temp_dir(), "Mockery");
864 18
        file_put_contents($tmpfname, $targetCode);
865 18
        require $tmpfname;
866 18
        \Mockery::registerFileForCleanUp($tmpfname);
867 18
    }
868
869
    /**
870
     * Register a file to be deleted on tearDown.
871
     *
872
     * @param string $fileName
873
     */
874 18
    public static function registerFileForCleanUp($fileName)
875
    {
876 18
        self::$_filesToCleanUp[] = $fileName;
877 18
    }
878
}
879