Rajout de doctrine/orm
[zf2.biz/galerie.git] / vendor / doctrine / common / lib / Doctrine / Common / Reflection / StaticReflectionParser.php
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 Doctrine\Common\Reflection;
21
22 use ReflectionException;
23 use Doctrine\Common\Annotations\TokenParser;
24
25 /**
26  * Parses a file for namespaces/use/class declarations.
27  *
28  * @author Karoly Negyesi <karoly@negyesi.net>
29  */
30 class StaticReflectionParser implements ReflectionProviderInterface
31 {
32
33     /**
34      * The name of the class.
35      *
36      * @var string
37      */
38     protected $className;
39
40     /**
41      * TRUE if the caller only wants class annotations.
42      *
43      * @var boolean.
44      */
45     protected $classAnnotationOptimize;
46
47     /**
48      * TRUE when the parser has ran.
49      *
50      * @var boolean
51      */
52     protected $parsed = false;
53
54     /**
55      * The namespace of the class
56      *
57      * @var string
58      */
59     protected $namespace = '';
60
61     /**
62      * The use statements of this class.
63      *
64      * @var array
65      */
66     protected $useStatements = array();
67
68     /**
69      * The docComment of the class.
70      *
71      * @var string
72      */
73     protected $docComment = array(
74         'class' => '',
75         'property' => array(),
76         'method' => array(),
77     );
78
79     /**
80      * The name of the class this class extends, if any.
81      *
82      * @var string
83      */
84     protected $parentClassName = '';
85
86     /**
87      * The parent PSR-0 Parser.
88      *
89      * @var \Doctrine\Common\Annotations\StaticReflectionParser
90      */
91     protected $parentStaticReflectionParser;
92
93     /**
94      * Parses a class residing in a PSR-0 hierarchy.
95      *
96      * @param string $class
97      *     The full, namespaced class name.
98      * @param ClassFinder $finder
99      *     A ClassFinder object which finds the class.
100      * @param boolean $classAnnotationOptimize
101      *     Only retrieve the class docComment. Presumes there is only one
102      *     statement per line.
103      */
104     public function __construct($className, $finder, $classAnnotationOptimize = false)
105     {
106         $this->className = ltrim($className, '\\');
107         if ($lastNsPos = strrpos($this->className, '\\')) {
108             $this->namespace = substr($this->className, 0, $lastNsPos);
109         }
110         $this->finder = $finder;
111         $this->classAnnotationOptimize = $classAnnotationOptimize;
112     }
113
114     protected function parse()
115     {
116         if ($this->parsed || !$fileName = $this->finder->findFile($this->className)) {
117             return;
118         }
119         $this->parsed = true;
120         $contents = file_get_contents($fileName);
121         if ($this->classAnnotationOptimize) {
122             if (preg_match("/(\A.*)^\s+(abstract|final)?\s+class\s+$className\s+{/sm", $contents, $matches)) {
123                 $contents = $matches[1];
124             }
125         }
126         $tokenParser = new TokenParser($contents);
127         $docComment = '';
128         while ($token = $tokenParser->next(false)) {
129             if (is_array($token)) {
130                 switch ($token[0]) {
131                     case T_USE:
132                         $this->useStatements = array_merge($this->useStatements, $tokenParser->parseUseStatement());
133                         break;
134                     case T_DOC_COMMENT:
135                         $docComment = $token[1];
136                         break;
137                     case T_CLASS:
138                         $this->docComment['class'] = $docComment;
139                         $docComment = '';
140                         break;
141                     case T_VAR:
142                     case T_PRIVATE:
143                     case T_PROTECTED:
144                     case T_PUBLIC:
145                         $token = $tokenParser->next();
146                         if ($token[0] === T_VARIABLE) {
147                             $propertyName = substr($token[1], 1);
148                             $this->docComment['property'][$propertyName] = $docComment;
149                             continue 2;
150                         }
151                         if ($token[0] !== T_FUNCTION) {
152                             // For example, it can be T_FINAL.
153                             continue 2;
154                         }
155                         // No break.
156                     case T_FUNCTION:
157                         // The next string after function is the name, but
158                         // there can be & before the function name so find the
159                         // string.
160                         while (($token = $tokenParser->next()) && $token[0] !== T_STRING);
161                         $methodName = $token[1];
162                         $this->docComment['method'][$methodName] = $docComment;
163                         $docComment = '';
164                         break;
165                     case T_EXTENDS:
166                         $this->parentClassName = $tokenParser->parseClass();
167                         $nsPos = strpos($this->parentClassName, '\\');
168                         $fullySpecified = false;
169                         if ($nsPos === 0) {
170                             $fullySpecified = true;
171                         } else {
172                             if ($nsPos) {
173                                 $prefix = strtolower(substr($this->parentClassName, 0, $nsPos));
174                                 $postfix = substr($this->parentClassName, $nsPos);
175                             } else {
176                                 $prefix = strtolower($this->parentClassName);
177                                 $postfix = '';
178                             }
179                             foreach ($this->useStatements as $alias => $use) {
180                                 if ($alias == $prefix) {
181                                     $this->parentClassName = '\\' . $use . $postfix;
182                                     $fullySpecified = true;
183                               }
184                             }
185                         }
186                         if (!$fullySpecified) {
187                             $this->parentClassName = '\\' . $this->namespace . '\\' . $this->parentClassName;
188                         }
189                         break;
190                 }
191             }
192         }
193     }
194
195     protected function getParentStaticReflectionParser()
196     {
197         if (empty($this->parentStaticReflectionParser)) {
198             $this->parentStaticReflectionParser = new static($this->parentClassName, $this->finder);
199         }
200
201         return $this->parentStaticReflectionParser;
202     }
203
204     public function getClassName()
205     {
206         return $this->className;
207     }
208
209     public function getNamespaceName()
210     {
211         return $this->namespace;
212     }
213
214     /**
215      * Get the ReflectionClass equivalent for this file / class.
216      */
217     public function getReflectionClass()
218     {
219         return new StaticReflectionClass($this);
220     }
221
222     /**
223      * Get the ReflectionMethod equivalent for the method of this file / class.
224      */
225     public function getReflectionMethod($methodName)
226     {
227         return new StaticReflectionMethod($this, $methodName);
228     }
229
230     /**
231      * Get the ReflectionProperty equivalent for the method of this file / class.
232      */
233     public function getReflectionProperty($propertyName)
234     {
235         return new StaticReflectionProperty($this, $propertyName);
236     }
237
238     /**
239      * Get the use statements from this file.
240      */
241     public function getUseStatements()
242     {
243         $this->parse();
244
245         return $this->useStatements;
246     }
247
248     /**
249      * Get docComment.
250      *
251      * @param string $type class, property or method.
252      * @param string $name Name of the property or method, not needed for class.
253      *
254      * @return string the doc comment or empty string if none.
255      */
256     public function getDocComment($type = 'class', $name = '')
257     {
258         $this->parse();
259
260         return $name ? $this->docComment[$type][$name] : $this->docComment[$type];
261     }
262
263     /**
264      * Get the PSR-0 parser for the declaring class.
265      *
266      * @param string $type property or method.
267      * @param string $name Name of the property or method.
268      *
269      * @return StaticReflectionParser A static reflection parser for the declaring class.
270      */
271     public function getStaticReflectionParserForDeclaringClass($type, $name)
272     {
273         $this->parse();
274         if (isset($this->docComment[$type][$name])) {
275             return $this;
276         }
277         if (!empty($this->parentClassName)) {
278             return $this->getParentStaticReflectionParser()->getStaticReflectionParserForDeclaringClass($type, $name);
279         }
280         throw new ReflectionException('Invalid ' . $type . ' "' . $name . '"');
281     }
282 }