PageRenderTime 32ms CodeModel.GetById 18ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/framework/vendor/zend/Zend/Reflection/File.php

http://zoop.googlecode.com/
PHP | 412 lines | 201 code | 44 blank | 167 comment | 30 complexity | 7c3e433e08d59c6f9a10f7adf18a92b4 MD5 | raw file
  1<?php
  2/**
  3 * Zend Framework
  4 *
  5 * LICENSE
  6 *
  7 * This source file is subject to the new BSD license that is bundled
  8 * with this package in the file LICENSE.txt.
  9 * It is also available through the world-wide-web at this URL:
 10 * http://framework.zend.com/license/new-bsd
 11 * If you did not receive a copy of the license and are unable to
 12 * obtain it through the world-wide-web, please send an email
 13 * to license@zend.com so we can send you a copy immediately.
 14 *
 15 * @category   Zend
 16 * @package    Zend_Reflection
 17 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
 18 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 19 * @version    $Id: File.php 20903 2010-02-04 16:16:47Z matthew $
 20 */
 21
 22/**
 23 * @see Zend_Reflection_Class
 24 */
 25require_once 'Zend/Reflection/Class.php';
 26
 27/**
 28 * @see Zend_Reflection_Function
 29 */
 30require_once 'Zend/Reflection/Function.php';
 31
 32/**
 33 * @category   Zend
 34 * @package    Zend_Reflection
 35 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
 36 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 37 */
 38class Zend_Reflection_File implements Reflector
 39{
 40    /**
 41     * @var string
 42     */
 43    protected $_filepath        = null;
 44
 45    /**
 46     * @var string
 47     */
 48    protected $_docComment      = null;
 49
 50    /**
 51     * @var int
 52     */
 53    protected $_startLine       = 1;
 54
 55    /**
 56     * @var int
 57     */
 58    protected $_endLine         = null;
 59
 60    /**
 61     * @var string[]
 62     */
 63    protected $_requiredFiles   = array();
 64
 65    /**
 66     * @var Zend_Reflection_Class[]
 67     */
 68    protected $_classes         = array();
 69
 70    /**
 71     * @var Zend_Reflection_Function[]
 72     */
 73    protected $_functions       = array();
 74
 75    /**
 76     * @var string
 77     */
 78    protected $_contents        = null;
 79
 80    /**
 81     * Constructor
 82     *
 83     * @param  string $file
 84     * @return void
 85     */
 86    public function __construct($file)
 87    {
 88        $fileName = $file;
 89
 90        if (($fileRealpath = realpath($fileName)) === false) {
 91            $fileRealpath = self::findRealpathInIncludePath($file);
 92        }
 93
 94        if (!$fileRealpath || !in_array($fileRealpath, get_included_files())) {
 95            require_once 'Zend/Reflection/Exception.php';
 96            throw new Zend_Reflection_Exception('File ' . $file . ' must be required before it can be reflected');
 97        }
 98
 99        $this->_fileName = $fileRealpath;
100        $this->_contents = file_get_contents($this->_fileName);
101        $this->_reflect();
102    }
103
104    /**
105     * Find realpath of file based on include_path
106     *
107     * @param  string $fileName
108     * @return string
109     */
110    public static function findRealpathInIncludePath($fileName)
111    {
112        require_once 'Zend/Loader.php';
113        $includePaths = Zend_Loader::explodeIncludePath();
114        while (count($includePaths) > 0) {
115            $filePath = array_shift($includePaths) . DIRECTORY_SEPARATOR . $fileName;
116
117            if ( ($foundRealpath = realpath($filePath)) !== false) {
118                break;
119            }
120        }
121
122        return $foundRealpath;
123    }
124
125    /**
126     * Export
127     *
128     * Required by the Reflector interface.
129     *
130     * @todo   What should this do?
131     * @return null
132     */
133    public static function export()
134    {
135        return null;
136    }
137
138    /**
139     * Return the file name of the reflected file
140     *
141     * @return string
142     */
143    public function getFileName()
144    {
145        return $this->_fileName;
146    }
147
148    /**
149     * Get the start line - Always 1, staying consistent with the Reflection API
150     *
151     * @return int
152     */
153    public function getStartLine()
154    {
155        return $this->_startLine;
156    }
157
158    /**
159     * Get the end line / number of lines
160     *
161     * @return int
162     */
163    public function getEndLine()
164    {
165        return $this->_endLine;
166    }
167
168    /**
169     * Return the doc comment
170     *
171     * @return string
172     */
173    public function getDocComment()
174    {
175        return $this->_docComment;
176    }
177
178    /**
179     * Return the docblock
180     *
181     * @param  string $reflectionClass Reflection class to use
182     * @return Zend_Reflection_Docblock
183     */
184    public function getDocblock($reflectionClass = 'Zend_Reflection_Docblock')
185    {
186        $instance = new $reflectionClass($this);
187        if (!$instance instanceof Zend_Reflection_Docblock) {
188            require_once 'Zend/Reflection/Exception.php';
189            throw new Zend_Reflection_Exception('Invalid reflection class specified; must extend Zend_Reflection_Docblock');
190        }
191        return $instance;
192    }
193
194    /**
195     * Return the reflection classes of the classes found inside this file
196     *
197     * @param  string $reflectionClass Name of reflection class to use for instances
198     * @return array Array of Zend_Reflection_Class instances
199     */
200    public function getClasses($reflectionClass = 'Zend_Reflection_Class')
201    {
202        $classes = array();
203        foreach ($this->_classes as $class) {
204            $instance = new $reflectionClass($class);
205            if (!$instance instanceof Zend_Reflection_Class) {
206                require_once 'Zend/Reflection/Exception.php';
207                throw new Zend_Reflection_Exception('Invalid reflection class provided; must extend Zend_Reflection_Class');
208            }
209            $classes[] = $instance;
210        }
211        return $classes;
212    }
213
214    /**
215     * Return the reflection functions of the functions found inside this file
216     *
217     * @param  string $reflectionClass Name of reflection class to use for instances
218     * @return array Array of Zend_Reflection_Functions
219     */
220    public function getFunctions($reflectionClass = 'Zend_Reflection_Function')
221    {
222        $functions = array();
223        foreach ($this->_functions as $function) {
224            $instance = new $reflectionClass($function);
225            if (!$instance instanceof Zend_Reflection_Function) {
226                require_once 'Zend/Reflection/Exception.php';
227                throw new Zend_Reflection_Exception('Invalid reflection class provided; must extend Zend_Reflection_Function');
228            }
229            $functions[] = $instance;
230        }
231        return $functions;
232    }
233
234    /**
235     * Retrieve the reflection class of a given class found in this file
236     *
237     * @param  null|string $name
238     * @param  string $reflectionClass Reflection class to use when creating reflection instance
239     * @return Zend_Reflection_Class
240     * @throws Zend_Reflection_Exception for invalid class name or invalid reflection class
241     */
242    public function getClass($name = null, $reflectionClass = 'Zend_Reflection_Class')
243    {
244        if ($name === null) {
245            reset($this->_classes);
246            $selected = current($this->_classes);
247            $instance = new $reflectionClass($selected);
248            if (!$instance instanceof Zend_Reflection_Class) {
249                require_once 'Zend/Reflection/Exception.php';
250                throw new Zend_Reflection_Exception('Invalid reflection class given; must extend Zend_Reflection_Class');
251            }
252            return $instance;
253        }
254
255        if (in_array($name, $this->_classes)) {
256            $instance = new $reflectionClass($name);
257            if (!$instance instanceof Zend_Reflection_Class) {
258                require_once 'Zend/Reflection/Exception.php';
259                throw new Zend_Reflection_Exception('Invalid reflection class given; must extend Zend_Reflection_Class');
260            }
261            return $instance;
262        }
263
264        require_once 'Zend/Reflection/Exception.php';
265        throw new Zend_Reflection_Exception('Class by name ' . $name . ' not found.');
266    }
267
268    /**
269     * Return the full contents of file
270     *
271     * @return string
272     */
273    public function getContents()
274    {
275        return $this->_contents;
276    }
277
278    /**
279     * Serialize to string
280     *
281     * Required by the Reflector interface
282     *
283     * @todo   What should this serialization look like?
284     * @return string
285     */
286    public function __toString()
287    {
288        return '';
289    }
290
291    /**
292     * This method does the work of "reflecting" the file
293     *
294     * Uses PHP's tokenizer to perform file reflection.
295     *
296     * @return void
297     */
298    protected function _reflect()
299    {
300        $contents = $this->_contents;
301        $tokens   = token_get_all($contents);
302
303        $functionTrapped = false;
304        $classTrapped    = false;
305        $requireTrapped  = false;
306        $openBraces      = 0;
307
308        $this->_checkFileDocBlock($tokens);
309
310        foreach ($tokens as $token) {
311            /*
312             * Tokens are characters representing symbols or arrays
313             * representing strings. The keys/values in the arrays are
314             *
315             * - 0 => token id,
316             * - 1 => string,
317             * - 2 => line number
318             *
319             * Token ID's are explained here:
320             * http://www.php.net/manual/en/tokens.php.
321             */
322
323            if (is_array($token)) {
324                $type    = $token[0];
325                $value   = $token[1];
326                $lineNum = $token[2];
327            } else {
328                // It's a symbol
329                // Maintain the count of open braces
330                if ($token == '{') {
331                    $openBraces++;
332                } else if ($token == '}') {
333                    $openBraces--;
334                }
335
336                continue;
337            }
338
339            switch ($type) {
340                // Name of something
341                case T_STRING:
342                    if ($functionTrapped) {
343                        $this->_functions[] = $value;
344                        $functionTrapped = false;
345                    } elseif ($classTrapped) {
346                        $this->_classes[] = $value;
347                        $classTrapped = false;
348                    }
349                    continue;
350
351                // Required file names are T_CONSTANT_ENCAPSED_STRING
352                case T_CONSTANT_ENCAPSED_STRING:
353                    if ($requireTrapped) {
354                        $this->_requiredFiles[] = $value ."\n";
355                        $requireTrapped = false;
356                    }
357                    continue;
358
359                // Functions
360                case T_FUNCTION:
361                    if ($openBraces == 0) {
362                        $functionTrapped = true;
363                    }
364                    break;
365
366                // Classes
367                case T_CLASS:
368                case T_INTERFACE:
369                    $classTrapped = true;
370                    break;
371
372                // All types of requires
373                case T_REQUIRE:
374                case T_REQUIRE_ONCE:
375                case T_INCLUDE:
376                case T_INCLUDE_ONCE:
377                    $requireTrapped = true;
378                    break;
379
380                // Default case: do nothing
381                default:
382                    break;
383            }
384        }
385
386        $this->_endLine = count(explode("\n", $this->_contents));
387    }
388
389    /**
390     * Validate / check a file level docblock
391     *
392     * @param  array $tokens Array of tokenizer tokens
393     * @return void
394     */
395    protected function _checkFileDocBlock($tokens) {
396        foreach ($tokens as $token) {
397            $type    = $token[0];
398            $value   = $token[1];
399            $lineNum = $token[2];
400            if(($type == T_OPEN_TAG) || ($type == T_WHITESPACE)) {
401                continue;
402            } elseif ($type == T_DOC_COMMENT) {
403                $this->_docComment = $value;
404                $this->_startLine  = $lineNum + substr_count($value, "\n") + 1;
405                return;
406            } else {
407                // Only whitespace is allowed before file docblocks
408                return;
409            }
410        }
411    }
412}