Completed
Pull Request — master (#668)
by Dave
02:39
created

Mockery::objectToArray()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2.0116

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
ccs 6
cts 7
cp 0.8571
rs 9.4285
cc 2
eloc 7
nc 2
nop 2
crap 2.0116
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\StringManipulation\Pass\RemoveDestructorPass;
26
use Mockery\Generator\StringManipulationGenerator;
27
use Mockery\Generator\StringManipulation\Pass\CallTypeHintPass;
28
use Mockery\Generator\StringManipulation\Pass\MagicMethodTypeHintsPass;
29
use Mockery\Generator\StringManipulation\Pass\ClassNamePass;
30
use Mockery\Generator\StringManipulation\Pass\ClassPass;
31
use Mockery\Generator\StringManipulation\Pass\InstanceMockPass;
32
use Mockery\Generator\StringManipulation\Pass\InterfacePass;
33
use Mockery\Generator\StringManipulation\Pass\MethodDefinitionPass;
34
use Mockery\Generator\StringManipulation\Pass\RemoveBuiltinMethodsThatAreFinalPass;
35
use Mockery\Generator\StringManipulation\Pass\RemoveUnserializeForInternalSerializableClassesPass;
36
use Mockery\Generator\StringManipulation\Pass\AvoidMethodClashPass;
37
use Mockery\Loader\EvalLoader;
38
use Mockery\Loader\Loader;
39
40
class Mockery
41
{
42
    const BLOCKS = 'Mockery_Forward_Blocks';
43
44
    /**
45
     * Global container to hold all mocks for the current unit test running.
46
     *
47
     * @var \Mockery\Container
48
     */
49
    protected static $_container = null;
50
51
    /**
52
     * Global configuration handler containing configuration options.
53
     *
54
     * @var \Mockery\Configuration
55
     */
56
    protected static $_config = null;
57
58
    /**
59
     * @var \Mockery\Generator\Generator
60
     */
61
    protected static $_generator;
62
63
    /**
64
     * @var \Mockery\Loader\Loader
65
     */
66
    protected static $_loader;
67
68
    /**
69
     * @var array
70
     */
71
    private static $_filesToCleanUp = [];
72
73
    /**
74
     * Static shortcut to \Mockery\Container::mock().
75
     *
76
     * @return \Mockery\MockInterface
77
     */
78 33
    public static function mock()
79
    {
80 33
        $args = func_get_args();
81
82 33
        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
     * @return \Mockery\MockInterface
90
     */
91 7
    public static function spy()
92
    {
93 7
        $args = func_get_args();
94 7
        return call_user_func_array(array(self::getContainer(), 'mock'), $args)->shouldIgnoreMissing();
95
    }
96
97
    /**
98
     * Static and Semantic shortcut to \Mockery\Container::mock().
99
     *
100
     * @return \Mockery\MockInterface
101
     */
102
    public static function instanceMock()
103
    {
104
        $args = func_get_args();
105
106
        return call_user_func_array(array(self::getContainer(), 'mock'), $args);
107
    }
108
109
    /**
110
     * Static shortcut to \Mockery\Container::mock(), first argument names the mock.
111
     *
112
     * @return \Mockery\MockInterface
113
     */
114 4
    public static function namedMock()
115
    {
116 4
        $args = func_get_args();
117 4
        $name = array_shift($args);
118
119 4
        $builder = new MockConfigurationBuilder();
120 4
        $builder->setName($name);
121
122 4
        array_unshift($args, $builder);
123
124 4
        return call_user_func_array(array(self::getContainer(), 'mock'), $args);
125
    }
126
127
    /**
128
     * Static shortcut to \Mockery\Container::self().
129
     *
130
     * @throws LogicException
131
     *
132
     * @return \Mockery\MockInterface
133
     */
134 2
    public static function self()
135
    {
136 2
        if (is_null(self::$_container)) {
137 1
            throw new \LogicException('You have not declared any mocks yet');
138
        }
139
140 1
        return self::$_container->self();
141
    }
142
143
    /**
144
     * Static shortcut to closing up and verifying all mocks in the global
145
     * container, and resetting the container static variable to null.
146
     *
147
     * @return void
148
     */
149 405
    public static function close()
150
    {
151 405
        foreach (self::$_filesToCleanUp as $fileName) {
152 18
            @unlink($fileName);
153 405
        }
154 405
        self::$_filesToCleanUp = [];
155
156 405
        if (is_null(self::$_container)) {
157
            return;
158
        }
159
160 405
        self::$_container->mockery_teardown();
161 403
        self::$_container->mockery_close();
162 403
        self::$_container = null;
163 403
    }
164
165
    /**
166
     * Static fetching of a mock associated with a name or explicit class poser.
167
     *
168
     * @param $name
169
     *
170
     * @return \Mockery\Mock
171
     */
172 11
    public static function fetchMock($name)
173
    {
174 11
        return self::$_container->fetchMock($name);
175
    }
176
177
    /**
178
     * Lazy loader and getter for
179
     * the container property.
180
     *
181
     * @return Mockery\Container
182
     */
183 425
    public static function getContainer()
184
    {
185 425
        if (is_null(self::$_container)) {
186 398
            self::$_container = new Mockery\Container(self::getGenerator(), self::getLoader());
187 398
        }
188
189 425
        return self::$_container;
190
    }
191
192
    /**
193
     * Setter for the $_generator static propery.
194
     *
195
     * @param \Mockery\Generator\Generator $generator
196
     */
197
    public static function setGenerator(Generator $generator)
198
    {
199
        self::$_generator = $generator;
200
    }
201
202
    /**
203
     * Lazy loader method and getter for
204
     * the generator property.
205
     *
206
     * @return Generator
207
     */
208 398
    public static function getGenerator()
209
    {
210 398
        if (is_null(self::$_generator)) {
211 1
            self::$_generator = self::getDefaultGenerator();
212 1
        }
213
214 398
        return self::$_generator;
215
    }
216
217
    /**
218
     * Creates and returns a default generator
219
     * used inside this class.
220
     *
221
     * @return CachingGenerator
222
     */
223 398
    public static function getDefaultGenerator()
224
    {
225 398
        return new CachingGenerator(StringManipulationGenerator::withDefaultPasses());
226
    }
227
228
    /**
229
     * Setter for the $_loader static property.
230
     *
231
     * @param Loader $loader
232
     */
233
    public static function setLoader(Loader $loader)
234
    {
235
        self::$_loader = $loader;
236
    }
237
238
    /**
239
     * Lazy loader method and getter for
240
     * the $_loader property.
241
     *
242
     * @return Loader
243
     */
244 398
    public static function getLoader()
245
    {
246 398
        if (is_null(self::$_loader)) {
247 1
            self::$_loader = self::getDefaultLoader();
248 1
        }
249
250 398
        return self::$_loader;
251
    }
252
253
    /**
254
     * Gets an EvalLoader to be used as default.
255
     *
256
     * @return EvalLoader
257
     */
258 272
    public static function getDefaultLoader()
259
    {
260 272
        return new EvalLoader();
261
    }
262
263
    /**
264
     * Set the container.
265
     *
266
     * @param \Mockery\Container $container
267
     *
268
     * @return \Mockery\Container
269
     */
270 18
    public static function setContainer(Mockery\Container $container)
271
    {
272 18
        return self::$_container = $container;
273
    }
274
275
    /**
276
     * Reset the container to null.
277
     *
278
     * @return void
279
     */
280 15
    public static function resetContainer()
281
    {
282 15
        self::$_container = null;
283 15
    }
284
285
    /**
286
     * Return instance of ANY matcher.
287
     *
288
     * @return \Mockery\Matcher\Any
289
     */
290 5
    public static function any()
291
    {
292 5
        return new \Mockery\Matcher\Any();
293
    }
294
295
    /**
296
     * Return instance of TYPE matcher.
297
     *
298
     * @param $expected
299
     *
300
     * @return \Mockery\Matcher\Type
301
     */
302 48
    public static function type($expected)
303
    {
304 48
        return new \Mockery\Matcher\Type($expected);
305
    }
306
307
    /**
308
     * Return instance of DUCKTYPE matcher.
309
     *
310
     * @return \Mockery\Matcher\Ducktype
311
     */
312 3
    public static function ducktype()
313
    {
314 3
        return new \Mockery\Matcher\Ducktype(func_get_args());
315
    }
316
317
    /**
318
     * Return instance of SUBSET matcher.
319
     *
320
     * @param array $part
321
     *
322
     * @return \Mockery\Matcher\Subset
323
     */
324 3
    public static function subset(array $part)
325
    {
326 3
        return new \Mockery\Matcher\Subset($part);
327
    }
328
329
    /**
330
     * Return instance of CONTAINS matcher.
331
     *
332
     * @return \Mockery\Matcher\Contains
333
     */
334 3
    public static function contains()
335
    {
336 3
        return new \Mockery\Matcher\Contains(func_get_args());
337
    }
338
339
    /**
340
     * Return instance of HASKEY matcher.
341
     *
342
     * @param $key
343
     *
344
     * @return \Mockery\Matcher\HasKey
345
     */
346 3
    public static function hasKey($key)
347
    {
348 3
        return new \Mockery\Matcher\HasKey($key);
349
    }
350
351
    /**
352
     * Return instance of HASVALUE matcher.
353
     *
354
     * @param $val
355
     *
356
     * @return \Mockery\Matcher\HasValue
357
     */
358 3
    public static function hasValue($val)
359
    {
360 3
        return new \Mockery\Matcher\HasValue($val);
361
    }
362
363
    /**
364
     * Return instance of CLOSURE matcher.
365
     *
366
     * @param $closure
367
     *
368
     * @return \Mockery\Matcher\Closure
369
     */
370 7
    public static function on($closure)
371
    {
372 7
        return new \Mockery\Matcher\Closure($closure);
373
    }
374
375
    /**
376
     * Return instance of MUSTBE matcher.
377
     *
378
     * @param $expected
379
     *
380
     * @return \Mockery\Matcher\MustBe
381
     */
382 6
    public static function mustBe($expected)
383
    {
384 6
        return new \Mockery\Matcher\MustBe($expected);
385
    }
386
387
    /**
388
     * Return instance of NOT matcher.
389
     *
390
     * @param $expected
391
     *
392
     * @return \Mockery\Matcher\Not
393
     */
394 3
    public static function not($expected)
395
    {
396 3
        return new \Mockery\Matcher\Not($expected);
397
    }
398
399
    /**
400
     * Return instance of ANYOF matcher.
401
     *
402
     * @return \Mockery\Matcher\AnyOf
403
     */
404 3
    public static function anyOf()
405
    {
406 3
        return new \Mockery\Matcher\AnyOf(func_get_args());
407
    }
408
409
    /**
410
     * Return instance of NOTANYOF matcher.
411
     *
412
     * @return \Mockery\Matcher\NotAnyOf
413
     */
414 3
    public static function notAnyOf()
415
    {
416 3
        return new \Mockery\Matcher\NotAnyOf(func_get_args());
417
    }
418
419
    /**
420
     * Lazy loader and Getter for the global
421
     * configuration container.
422
     *
423
     * @return \Mockery\Configuration
424
     */
425 418
    public static function getConfiguration()
426
    {
427 418
        if (is_null(self::$_config)) {
428 1
            self::$_config = new \Mockery\Configuration();
429 1
        }
430
431 418
        return self::$_config;
432
    }
433
434
    /**
435
     * Utility method to format method name and arguments into a string.
436
     *
437
     * @param string $method
438
     * @param array $arguments
439
     *
440
     * @return string
441
     */
442 92
    public static function formatArgs($method, array $arguments = null)
443
    {
444 92
        if (is_null($arguments)) {
445
            return $method . '()';
446
        }
447
448 92
        $formattedArguments = array();
449 92
        foreach ($arguments as $argument) {
450 58
            $formattedArguments[] = self::formatArgument($argument);
451 92
        }
452
453 92
        return $method . '(' . implode(', ', $formattedArguments) . ')';
454
    }
455
456
    /**
457
     * Gets the string representation
458
     * of any passed argument.
459
     *
460
     * @param $argument
461
     * @param $depth
462
     *
463
     * @return string
464
     */
465 58
    private static function formatArgument($argument, $depth = 0)
466
    {
467 58
        if (is_object($argument)) {
468 8
            return 'object(' . get_class($argument) . ')';
469
        }
470
471 54
        if (is_int($argument) || is_float($argument)) {
472 37
            return $argument;
473
        }
474
475 26
        if (is_array($argument)) {
476 13
            if ($depth === 1) {
477 2
                $argument = '[...]';
478 2
            } else {
479 13
                $sample = array();
480 13
                foreach ($argument as $key => $value) {
481 12
                    $key = is_int($key) ? $key : "'$key'";
482 12
                    $value = self::formatArgument($value, $depth + 1);
483 12
                    $sample[] = "$key => $value";
484 13
                }
485
486 13
                $argument = "[".implode(", ", $sample)."]";
487
            }
488
489 13
            return ((strlen($argument) > 1000) ? substr($argument, 0, 1000).'...]' : $argument);
490
        }
491
492 17
        if (is_bool($argument)) {
493 1
            return $argument ? 'true' : 'false';
494
        }
495
496 16
        if (is_resource($argument)) {
497 2
            return 'resource(...)';
498
        }
499
500 14
        if (is_null($argument)) {
501 1
            return 'NULL';
502
        }
503
504 13
        return "'".(string) $argument."'";
505
    }
506
507
    /**
508
     * Utility function to format objects to printable arrays.
509
     *
510
     * @param array $objects
511
     *
512
     * @return string
513
     */
514 52
    public static function formatObjects(array $objects = null)
515
    {
516 52
        static $formatting;
517
518 52
        if ($formatting) {
519 1
            return '[Recursion]';
520
        }
521
522 52
        if (is_null($objects)) {
523
            return '';
524
        }
525
526 52
        $objects = array_filter($objects, 'is_object');
527 52
        if (empty($objects)) {
528 45
            return '';
529
        }
530
531 7
        $formatting = true;
532 7
        $parts = array();
533
534 7
        foreach ($objects as $object) {
535 7
            $parts[get_class($object)] = self::objectToArray($object);
536 7
        }
537
538 7
        $formatting = false;
539
540 7
        return 'Objects: ( ' . var_export($parts, true) . ')';
541
    }
542
543
    /**
544
     * Utility function to turn public properties and public get* and is* method values into an array.
545
     *
546
     * @param     $object
547
     * @param int $nesting
548
     *
549
     * @return array
550
     */
551 7
    private static function objectToArray($object, $nesting = 3)
552
    {
553 7
        if ($nesting == 0) {
554
            return array('...');
555
        }
556
557
        return array(
558 7
            'class' => get_class($object),
559 7
            'properties' => self::extractInstancePublicProperties($object, $nesting),
560 7
            'getters' => self::extractGetters($object, $nesting)
561 7
        );
562
    }
563
564
    /**
565
     * Returns all public instance properties.
566
     *
567
     * @param $object
568
     * @param $nesting
569
     *
570
     * @return array
571
     */
572 7
    private static function extractInstancePublicProperties($object, $nesting)
573
    {
574 7
        $reflection = new \ReflectionClass(get_class($object));
575 7
        $properties = $reflection->getProperties(\ReflectionProperty::IS_PUBLIC);
576 7
        $cleanedProperties = array();
577
578 7
        foreach ($properties as $publicProperty) {
579 1
            if (!$publicProperty->isStatic()) {
580
                $name = $publicProperty->getName();
581
                $cleanedProperties[$name] = self::cleanupNesting($object->$name, $nesting);
582
            }
583 7
        }
584
585 7
        return $cleanedProperties;
586
    }
587
588
    /**
589
     * Returns all object getters.
590
     *
591
     * @param $object
592
     * @param $nesting
593
     *
594
     * @return array
595
     */
596 7
    private static function extractGetters($object, $nesting)
597
    {
598 7
        $reflection = new \ReflectionClass(get_class($object));
599 7
        $publicMethods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
600 7
        $getters = array();
601
602 7
        foreach ($publicMethods as $publicMethod) {
603 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...
604 5
            $irrelevantName = (substr($name, 0, 3) !== 'get' && substr($name, 0, 2) !== 'is');
605 5
            $isStatic = $publicMethod->isStatic();
606 5
            $numberOfParameters = $publicMethod->getNumberOfParameters();
607
608 5
            if ($irrelevantName || $numberOfParameters != 0 || $isStatic) {
609 5
                continue;
610
            }
611
612
            try {
613 2
                $getters[$name] = self::cleanupNesting($object->$name(), $nesting);
614 2
            } catch (\Exception $e) {
615 1
                $getters[$name] = '!! ' . get_class($e) . ': ' . $e->getMessage() . ' !!';
616
            }
617 7
        }
618
619 7
        return $getters;
620
    }
621
622
    /**
623
     * Utility method used for recursively generating
624
     * an object or array representation.
625
     *
626
     * @param $argument
627
     * @param $nesting
628
     *
629
     * @return mixed
630
     */
631 1
    private static function cleanupNesting($argument, $nesting)
632
    {
633 1
        if (is_object($argument)) {
634
            $object = self::objectToArray($argument, $nesting - 1);
635
            $object['class'] = get_class($argument);
636
637
            return $object;
638
        }
639
640 1
        if (is_array($argument)) {
641 1
            return self::cleanupArray($argument, $nesting - 1);
642
        }
643
644 1
        return $argument;
645
    }
646
647
    /**
648
     * Utility method for recursively
649
     * gerating a representation
650
     * of the given array.
651
     *
652
     * @param array $argument
653
     * @param int $nesting
654
     *
655
     * @return mixed
656
     */
657 1
    private static function cleanupArray($argument, $nesting = 3)
658
    {
659 1
        if ($nesting == 0) {
660 1
            return '...';
661
        }
662
663 1
        foreach ($argument as $key => $value) {
664 1
            if (is_array($value)) {
665 1
                $argument[$key] = self::cleanupArray($value, $nesting - 1);
666 1
            } elseif (is_object($value)) {
667
                $argument[$key] = self::objectToArray($value, $nesting - 1);
668
            }
669 1
        }
670
671 1
        return $argument;
672
    }
673
674
    /**
675
     * Utility function to parse shouldReceive() arguments and generate
676
     * expectations from such as needed.
677
     *
678
     * @param Mockery\MockInterface $mock
679
     * @param array $args
680
     * @param callable $add
681
     * @return \Mockery\CompositeExpectation
682
     */
683 305
    public static function parseShouldReturnArgs(\Mockery\MockInterface $mock, $args, $add)
684
    {
685 305
        $composite = new \Mockery\CompositeExpectation();
686
687 305
        foreach ($args as $arg) {
688 305
            if (is_array($arg)) {
689 16
                foreach ($arg as $k => $v) {
690 16
                    $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...
691 16
                    $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...
692 16
                }
693 305
            } elseif (is_string($arg)) {
694 293
                $expectation = self::buildDemeterChain($mock, $arg, $add);
695 287
                $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...
696 287
            }
697 299
        }
698
699 299
        return $composite;
700
    }
701
702
    /**
703
     * Sets up expectations on the members of the CompositeExpectation and
704
     * builds up any demeter chain that was passed to shouldReceive.
705
     *
706
     * @param \Mockery\MockInterface $mock
707
     * @param string $arg
708
     * @param callable $add
709
     * @throws Mockery\Exception
710
     * @return \Mockery\ExpectationInterface
711
     */
712 305
    protected static function buildDemeterChain(\Mockery\MockInterface $mock, $arg, $add)
713
    {
714
        /** @var Mockery\Container $container */
715 305
        $container = $mock->mockery_getContainer();
716 305
        $methodNames = explode('->', $arg);
717 305
        reset($methodNames);
718
719 305
        if (!\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed()
720 305
            && !$mock->mockery_isAnonymous()
721 305
            && !in_array(current($methodNames), $mock->mockery_getMockableMethods())
722 305
        ) {
723 4
            throw new \Mockery\Exception(
724
                'Mockery\'s configuration currently forbids mocking the method '
725 4
                . current($methodNames) . ' as it does not exist on the class or object '
726 4
                . 'being mocked'
727 4
            );
728
        }
729
730
        /** @var ExpectationInterface|null $expectations */
731 301
        $expectations = null;
732
733
        /** @var Callable $nextExp */
734
        $nextExp = function ($method) use ($add) {
735 301
            return $add($method);
736 301
        };
737
738 301
        while (true) {
739 301
            $method = array_shift($methodNames);
740 301
            $expectations = $mock->mockery_getExpectationsFor($method);
741
742 301
            if (is_null($expectations) || self::noMoreElementsInChain($methodNames)) {
743 301
                $expectations = $nextExp($method);
744 299
                if (self::noMoreElementsInChain($methodNames)) {
745 299
                    break;
746
                }
747
748 11
                $mock = self::getNewDemeterMock($container, $method, $expectations);
749 11
            } else {
750 5
                $demeterMockKey = $container->getKeyOfDemeterMockFor($method);
751 5
                if ($demeterMockKey) {
752 5
                    $mock = self::getExistingDemeterMock($container, $demeterMockKey);
753 5
                }
754
            }
755
756 11
            $nextExp = function ($n) use ($mock) {
757 11
                return $mock->shouldReceive($n);
758 11
            };
759 11
        }
760
761 299
        return $expectations;
762
    }
763
764
    /**
765
     * Gets a new demeter configured
766
     * mock from the container.
767
     *
768
     * @param \Mockery\Container $container
769
     * @param string $method
770
     * @param Mockery\ExpectationInterface $exp
771
     *
772
     * @return \Mockery\Mock
773
     */
774 11
    private static function getNewDemeterMock(
775
        Mockery\Container $container,
776
        $method,
777
        Mockery\ExpectationInterface $exp
778
    ) {
779 11
        $mock = $container->mock('demeter_' . $method);
780 11
        $exp->andReturn($mock);
781
782 11
        return $mock;
783
    }
784
785
    /**
786
     * Gets an specific demeter mock from
787
     * the ones kept by the container.
788
     *
789
     * @param \Mockery\Container $container
790
     * @param string $demeterMockKey
791
     *
792
     * @return mixed
793
     */
794 5
    private static function getExistingDemeterMock(
795
        Mockery\Container $container,
796
        $demeterMockKey
797
    ) {
798 5
        $mocks = $container->getMocks();
799 5
        $mock = $mocks[$demeterMockKey];
800
801 5
        return $mock;
802
    }
803
804
    /**
805
     * Checks if the passed array representing a demeter
806
     * chain with the method names is empty.
807
     *
808
     * @param array $methodNames
809
     *
810
     * @return bool
811
     */
812 299
    private static function noMoreElementsInChain(array $methodNames)
813
    {
814 299
        return empty($methodNames);
815
    }
816
817 17
    public static function declareClass($fqn)
818
    {
819 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...
820
    }
821
822 2
    public static function declareInterface($fqn)
823
    {
824 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...
825
    }
826
827 18
    private static function declareType($fqn, $type)
828
    {
829 18
        $targetCode = "<?php ";
830 18
        $shortName = $fqn;
831
832 18
        if (strpos($fqn, "\\")) {
833 4
            $parts = explode("\\", $fqn);
834
835 4
            $shortName = trim(array_pop($parts));
836 4
            $namespace = implode("\\", $parts);
837
838 4
            $targetCode.= "namespace $namespace;\n";
839 4
        }
840
841 18
        $targetCode.= "$type $shortName {} ";
842
843
        /*
844
         * We could eval here, but it doesn't play well with the way
845
         * PHPUnit tries to backup global state and the require definition
846
         * loader
847
         */
848 18
        $tmpfname = tempnam(sys_get_temp_dir(), "Mockery");
849 18
        file_put_contents($tmpfname, $targetCode);
850 18
        require $tmpfname;
851 18
        \Mockery::registerFileForCleanUp($tmpfname);
852 18
    }
853
854
    /**
855
     * Register a file to be deleted on tearDown.
856
     *
857
     * @param string $fileName
858
     */
859 18
    public static function registerFileForCleanUp($fileName)
860
    {
861 18
        self::$_filesToCleanUp[] = $fileName;
862 18
    }
863
}
864