web/lib/Zend/Reflection/File.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     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 20904 2010-02-04 16:18:18Z matthew $
       
    20  */
       
    21 
       
    22 /**
       
    23  * @see Zend_Reflection_Class
       
    24  */
       
    25 require_once 'Zend/Reflection/Class.php';
       
    26 
       
    27 /**
       
    28  * @see Zend_Reflection_Function
       
    29  */
       
    30 require_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  */
       
    38 class 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 }