source: pro-violet-viettel/sourcecode/application/libraries/Doctrine/Common/Annotations/PhpParser.php @ 354

Last change on this file since 354 was 345, checked in by quyenla, 11 years ago

collaborator page

File size: 6.0 KB
Line 
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 LGPL. For more information, see
17 * <http://www.doctrine-project.org>.
18 */
19
20namespace Doctrine\Common\Annotations;
21
22use SplFileObject;
23
24/**
25 * Parses a file for namespaces/use/class declarations.
26 *
27 * @author Fabien Potencier <fabien@symfony.com>
28 * @author Christian Kaps <christian.kaps@mohiva.com>
29 */
30final class PhpParser
31{
32    /**
33     * The token list.
34     *
35     * @var array
36     */
37    private $tokens;
38
39    /**
40     * The number of tokens.
41     *
42     * @var int
43     */
44    private $numTokens = 0;
45
46    /**
47     * The current array pointer.
48     *
49     * @var int
50     */
51    private $pointer = 0;
52
53    /**
54     * Parses a class.
55     *
56     * @param \ReflectionClass $class A <code>ReflectionClass</code> object.
57     * @return array A list with use statements in the form (Alias => FQN).
58     */
59    public function parseClass(\ReflectionClass $class)
60    {
61        if (false === $filename = $class->getFilename()) {
62            return array();
63        }
64
65        $content = $this->getFileContent($filename, $class->getStartLine());
66        $namespace = str_replace('\\', '\\\\', $class->getNamespaceName());
67        $content = preg_replace('/^.*?(\bnamespace\s+' . $namespace . '\s*[;{].*)$/s', '\\1', $content);
68        $this->tokens = token_get_all('<?php ' . $content);
69        $this->numTokens = count($this->tokens);
70        $this->pointer = 0;
71
72        $statements = $this->parseUseStatements($class->getNamespaceName());
73
74        return $statements;
75    }
76
77    /**
78     * Get the content of the file right up to the given line number.
79     *
80     * @param string $filename The name of the file to load.
81     * @param int $lineNumber The number of lines to read from file.
82     * @return string The content of the file.
83     */
84    private function getFileContent($filename, $lineNumber)
85    {
86        $content = '';
87        $lineCnt = 0;
88        $file = new SplFileObject($filename);
89        while(!$file->eof()) {
90            if ($lineCnt++ == $lineNumber) {
91                break;
92            }
93
94            $content .= $file->fgets();
95        }
96
97        return $content;
98    }
99
100    /**
101     * Gets the next non whitespace and non comment token.
102     *
103     * @return array The token if exists, null otherwise.
104     */
105    private function next()
106    {
107        for ($i = $this->pointer; $i < $this->numTokens; $i++) {
108            $this->pointer++;
109            if ($this->tokens[$i][0] === T_WHITESPACE ||
110                $this->tokens[$i][0] === T_COMMENT ||
111                $this->tokens[$i][0] === T_DOC_COMMENT) {
112
113                continue;
114            }
115
116            return $this->tokens[$i];
117        }
118
119        return null;
120    }
121
122    /**
123     * Get all use statements.
124     *
125     * @param string $namespaceName The namespace name of the reflected class.
126     * @return array A list with all found use statements.
127     */
128    private function parseUseStatements($namespaceName)
129    {
130        $statements = array();
131        while (($token = $this->next())) {
132            if ($token[0] === T_USE) {
133                $statements = array_merge($statements, $this->parseUseStatement());
134                continue;
135            } else if ($token[0] !== T_NAMESPACE || $this->parseNamespace() != $namespaceName) {
136                continue;
137            }
138
139            // Get fresh array for new namespace. This is to prevent the parser to collect the use statements
140            // for a previous namespace with the same name. This is the case if a namespace is defined twice
141            // or if a namespace with the same name is commented out.
142            $statements = array();
143        }
144
145        return $statements;
146    }
147
148    /**
149     * Get the namespace name.
150     *
151     * @return string The found namespace name.
152     */
153    private function parseNamespace()
154    {
155        $namespace = '';
156        while (($token = $this->next())){
157            if ($token[0] === T_STRING || $token[0] === T_NS_SEPARATOR) {
158                $namespace .= $token[1];
159            } else {
160                break;
161            }
162        }
163
164        return $namespace;
165    }
166
167    /**
168     * Parse a single use statement.
169     *
170     * @return array A list with all found class names for a use statement.
171     */
172    private function parseUseStatement()
173    {
174        $class = '';
175        $alias = '';
176        $statements = array();
177        $explicitAlias = false;
178        while (($token = $this->next())) {
179            $isNameToken = $token[0] === T_STRING || $token[0] === T_NS_SEPARATOR;
180            if (!$explicitAlias && $isNameToken) {
181                $class .= $token[1];
182                $alias = $token[1];
183            } else if ($explicitAlias && $isNameToken) {
184                $alias .= $token[1];
185            } else if ($token[0] === T_AS) {
186                $explicitAlias = true;
187                $alias = '';
188            } else if ($token === ',') {
189                $statements[strtolower($alias)] = $class;
190                $class = '';
191                $alias = '';
192                $explicitAlias = false;
193            } else if ($token === ';') {
194                $statements[strtolower($alias)] = $class;
195                break;
196            } else {
197                break;
198            }
199        }
200
201        return $statements;
202    }
203}
Note: See TracBrowser for help on using the repository browser.