Security update for Core, with self-updated composer
[yaffs-website] / vendor / phpspec / prophecy / src / Prophecy / Doubler / Doubler.php
1 <?php
2
3 /*
4  * This file is part of the Prophecy.
5  * (c) Konstantin Kudryashov <ever.zet@gmail.com>
6  *     Marcello Duarte <marcello.duarte@gmail.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Prophecy\Doubler;
13
14 use Doctrine\Instantiator\Instantiator;
15 use Prophecy\Doubler\ClassPatch\ClassPatchInterface;
16 use Prophecy\Doubler\Generator\ClassMirror;
17 use Prophecy\Doubler\Generator\ClassCreator;
18 use Prophecy\Exception\InvalidArgumentException;
19 use ReflectionClass;
20
21 /**
22  * Cached class doubler.
23  * Prevents mirroring/creation of the same structure twice.
24  *
25  * @author Konstantin Kudryashov <ever.zet@gmail.com>
26  */
27 class Doubler
28 {
29     private $mirror;
30     private $creator;
31     private $namer;
32
33     /**
34      * @var ClassPatchInterface[]
35      */
36     private $patches = array();
37
38     /**
39      * @var \Doctrine\Instantiator\Instantiator
40      */
41     private $instantiator;
42
43     /**
44      * Initializes doubler.
45      *
46      * @param ClassMirror   $mirror
47      * @param ClassCreator  $creator
48      * @param NameGenerator $namer
49      */
50     public function __construct(ClassMirror $mirror = null, ClassCreator $creator = null,
51                                 NameGenerator $namer = null)
52     {
53         $this->mirror  = $mirror  ?: new ClassMirror;
54         $this->creator = $creator ?: new ClassCreator;
55         $this->namer   = $namer   ?: new NameGenerator;
56     }
57
58     /**
59      * Returns list of registered class patches.
60      *
61      * @return ClassPatchInterface[]
62      */
63     public function getClassPatches()
64     {
65         return $this->patches;
66     }
67
68     /**
69      * Registers new class patch.
70      *
71      * @param ClassPatchInterface $patch
72      */
73     public function registerClassPatch(ClassPatchInterface $patch)
74     {
75         $this->patches[] = $patch;
76
77         @usort($this->patches, function (ClassPatchInterface $patch1, ClassPatchInterface $patch2) {
78             return $patch2->getPriority() - $patch1->getPriority();
79         });
80     }
81
82     /**
83      * Creates double from specific class or/and list of interfaces.
84      *
85      * @param ReflectionClass   $class
86      * @param ReflectionClass[] $interfaces Array of ReflectionClass instances
87      * @param array             $args       Constructor arguments
88      *
89      * @return DoubleInterface
90      *
91      * @throws \Prophecy\Exception\InvalidArgumentException
92      */
93     public function double(ReflectionClass $class = null, array $interfaces, array $args = null)
94     {
95         foreach ($interfaces as $interface) {
96             if (!$interface instanceof ReflectionClass) {
97                 throw new InvalidArgumentException(sprintf(
98                     "[ReflectionClass \$interface1 [, ReflectionClass \$interface2]] array expected as\n".
99                     "a second argument to `Doubler::double(...)`, but got %s.",
100                     is_object($interface) ? get_class($interface).' class' : gettype($interface)
101                 ));
102             }
103         }
104
105         $classname  = $this->createDoubleClass($class, $interfaces);
106         $reflection = new ReflectionClass($classname);
107
108         if (null !== $args) {
109             return $reflection->newInstanceArgs($args);
110         }
111         if ((null === $constructor = $reflection->getConstructor())
112             || ($constructor->isPublic() && !$constructor->isFinal())) {
113             return $reflection->newInstance();
114         }
115
116         if (!$this->instantiator) {
117             $this->instantiator = new Instantiator();
118         }
119
120         return $this->instantiator->instantiate($classname);
121     }
122
123     /**
124      * Creates double class and returns its FQN.
125      *
126      * @param ReflectionClass   $class
127      * @param ReflectionClass[] $interfaces
128      *
129      * @return string
130      */
131     protected function createDoubleClass(ReflectionClass $class = null, array $interfaces)
132     {
133         $name = $this->namer->name($class, $interfaces);
134         $node = $this->mirror->reflect($class, $interfaces);
135
136         foreach ($this->patches as $patch) {
137             if ($patch->supports($node)) {
138                 $patch->apply($node);
139             }
140         }
141
142         $this->creator->create($name, $node);
143
144         return $name;
145     }
146 }