Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
 
20
namespace Mockery;
21
 
22
use Closure;
23
use ReflectionClass;
24
use UnexpectedValueException;
25
use InvalidArgumentException;
26
 
27
/**
28
 * This is a trimmed down version of https://github.com/doctrine/instantiator,
29
 * basically without the caching
30
 *
31
 * @author Marco Pivetta <ocramius@gmail.com>
32
 */
33
final class Instantiator
34
{
35
    /**
36
     * {@inheritDoc}
37
     */
38
    public function instantiate($className)
39
    {
40
        $factory    = $this->buildFactory($className);
41
        $instance   = $factory();
42
 
43
        return $instance;
44
    }
45
 
46
    /**
47
     * Builds a {@see \Closure} capable of instantiating the given $className without
48
     * invoking its constructor.
49
     *
50
     * @param string $className
51
     *
52
     * @return Closure
53
     */
54
    private function buildFactory($className)
55
    {
56
        $reflectionClass = $this->getReflectionClass($className);
57
 
58
        if ($this->isInstantiableViaReflection($reflectionClass)) {
59
            return function () use ($reflectionClass) {
60
                return $reflectionClass->newInstanceWithoutConstructor();
61
            };
62
        }
63
 
64
        $serializedString = sprintf(
65
            'O:%d:"%s":0:{}',
66
            strlen($className),
67
            $className
68
        );
69
 
70
        $this->attemptInstantiationViaUnSerialization($reflectionClass, $serializedString);
71
 
72
        return function () use ($serializedString) {
73
            return unserialize($serializedString);
74
        };
75
    }
76
 
77
    /**
78
     * @param string $className
79
     *
80
     * @return ReflectionClass
81
     *
82
     * @throws InvalidArgumentException
83
     */
84
    private function getReflectionClass($className)
85
    {
86
        if (! class_exists($className)) {
87
            throw new InvalidArgumentException("Class:$className does not exist");
88
        }
89
 
90
        $reflection = new ReflectionClass($className);
91
 
92
        if ($reflection->isAbstract()) {
93
            throw new InvalidArgumentException("Class:$className is an abstract class");
94
        }
95
 
96
        return $reflection;
97
    }
98
 
99
    /**
100
     * @param ReflectionClass $reflectionClass
101
     * @param string          $serializedString
102
     *
103
     * @throws UnexpectedValueException
104
     *
105
     * @return void
106
     */
107
    private function attemptInstantiationViaUnSerialization(ReflectionClass $reflectionClass, $serializedString)
108
    {
109
        set_error_handler(function ($code, $message, $file, $line) use ($reflectionClass, & $error) {
110
            $msg = sprintf(
111
                'Could not produce an instance of "%s" via un-serialization, since an error was triggered in file "%s" at line "%d"',
112
                $reflectionClass->getName(),
113
                $file,
114
                $line
115
            );
116
 
117
            $error = new UnexpectedValueException($msg, 0, new \Exception($message, $code));
118
        });
119
 
120
        try {
121
            unserialize($serializedString);
122
        } catch (\Exception $exception) {
123
            restore_error_handler();
124
 
125
            throw new UnexpectedValueException("An exception was raised while trying to instantiate an instance of \"{$reflectionClass->getName()}\" via un-serialization", 0, $exception);
126
        }
127
 
128
        restore_error_handler();
129
 
130
        if ($error) {
131
            throw $error;
132
        }
133
    }
134
 
135
    /**
136
     * @param ReflectionClass $reflectionClass
137
     *
138
     * @return bool
139
     */
140
    private function isInstantiableViaReflection(ReflectionClass $reflectionClass)
141
    {
142
        return ! ($reflectionClass->isInternal() && $reflectionClass->isFinal());
143
    }
144
 
145
    /**
146
     * Verifies whether the given class is to be considered internal
147
     *
148
     * @param ReflectionClass $reflectionClass
149
     *
150
     * @return bool
151
     */
152
    private function hasInternalAncestors(ReflectionClass $reflectionClass)
153
    {
154
        do {
155
            if ($reflectionClass->isInternal()) {
156
                return true;
157
            }
158
        } while ($reflectionClass = $reflectionClass->getParentClass());
159
 
160
        return false;
161
    }
162
}