Version 1
[yaffs-website] / vendor / phpspec / prophecy / src / Prophecy / Doubler / Doubler.php
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Doubler.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Doubler.php
new file mode 100644 (file)
index 0000000..a378ae2
--- /dev/null
@@ -0,0 +1,146 @@
+<?php
+
+/*
+ * This file is part of the Prophecy.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *     Marcello Duarte <marcello.duarte@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Prophecy\Doubler;
+
+use Doctrine\Instantiator\Instantiator;
+use Prophecy\Doubler\ClassPatch\ClassPatchInterface;
+use Prophecy\Doubler\Generator\ClassMirror;
+use Prophecy\Doubler\Generator\ClassCreator;
+use Prophecy\Exception\InvalidArgumentException;
+use ReflectionClass;
+
+/**
+ * Cached class doubler.
+ * Prevents mirroring/creation of the same structure twice.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class Doubler
+{
+    private $mirror;
+    private $creator;
+    private $namer;
+
+    /**
+     * @var ClassPatchInterface[]
+     */
+    private $patches = array();
+
+    /**
+     * @var \Doctrine\Instantiator\Instantiator
+     */
+    private $instantiator;
+
+    /**
+     * Initializes doubler.
+     *
+     * @param ClassMirror   $mirror
+     * @param ClassCreator  $creator
+     * @param NameGenerator $namer
+     */
+    public function __construct(ClassMirror $mirror = null, ClassCreator $creator = null,
+                                NameGenerator $namer = null)
+    {
+        $this->mirror  = $mirror  ?: new ClassMirror;
+        $this->creator = $creator ?: new ClassCreator;
+        $this->namer   = $namer   ?: new NameGenerator;
+    }
+
+    /**
+     * Returns list of registered class patches.
+     *
+     * @return ClassPatchInterface[]
+     */
+    public function getClassPatches()
+    {
+        return $this->patches;
+    }
+
+    /**
+     * Registers new class patch.
+     *
+     * @param ClassPatchInterface $patch
+     */
+    public function registerClassPatch(ClassPatchInterface $patch)
+    {
+        $this->patches[] = $patch;
+
+        @usort($this->patches, function (ClassPatchInterface $patch1, ClassPatchInterface $patch2) {
+            return $patch2->getPriority() - $patch1->getPriority();
+        });
+    }
+
+    /**
+     * Creates double from specific class or/and list of interfaces.
+     *
+     * @param ReflectionClass   $class
+     * @param ReflectionClass[] $interfaces Array of ReflectionClass instances
+     * @param array             $args       Constructor arguments
+     *
+     * @return DoubleInterface
+     *
+     * @throws \Prophecy\Exception\InvalidArgumentException
+     */
+    public function double(ReflectionClass $class = null, array $interfaces, array $args = null)
+    {
+        foreach ($interfaces as $interface) {
+            if (!$interface instanceof ReflectionClass) {
+                throw new InvalidArgumentException(sprintf(
+                    "[ReflectionClass \$interface1 [, ReflectionClass \$interface2]] array expected as\n".
+                    "a second argument to `Doubler::double(...)`, but got %s.",
+                    is_object($interface) ? get_class($interface).' class' : gettype($interface)
+                ));
+            }
+        }
+
+        $classname  = $this->createDoubleClass($class, $interfaces);
+        $reflection = new ReflectionClass($classname);
+
+        if (null !== $args) {
+            return $reflection->newInstanceArgs($args);
+        }
+        if ((null === $constructor = $reflection->getConstructor())
+            || ($constructor->isPublic() && !$constructor->isFinal())) {
+            return $reflection->newInstance();
+        }
+
+        if (!$this->instantiator) {
+            $this->instantiator = new Instantiator();
+        }
+
+        return $this->instantiator->instantiate($classname);
+    }
+
+    /**
+     * Creates double class and returns its FQN.
+     *
+     * @param ReflectionClass   $class
+     * @param ReflectionClass[] $interfaces
+     *
+     * @return string
+     */
+    protected function createDoubleClass(ReflectionClass $class = null, array $interfaces)
+    {
+        $name = $this->namer->name($class, $interfaces);
+        $node = $this->mirror->reflect($class, $interfaces);
+
+        foreach ($this->patches as $patch) {
+            if ($patch->supports($node)) {
+                $patch->apply($node);
+            }
+        }
+
+        $this->creator->create($name, $node);
+
+        return $name;
+    }
+}