[ Index ]

PHP Cross Reference of Akelos Framework

title

Body

[close]

/ -> AkReflection.php (source)

   1  <?php
   2  
   3  
   4  class AkReflection
   5  {
   6       
   7      var $definitions = array();
   8      var $requires = array();
   9      var $tokens;
  10       
  11      var $symbols;
  12      
  13      
  14  
  15      function _parse($source)
  16      {
  17          if (!function_exists('token_get_all')) {
  18              trigger_error('Function "token_get_all" is not defined');
  19              return false;
  20          }
  21          $source = @preg_match('/<\?php.*'.$source.'.*\?>/', $source)?$source:"<?php ".$source." ?>";
  22          $this->tokens = token_get_all($source);
  23          $this->definitions = array();
  24          reset($this->tokens);
  25          $previous = array();
  26          $visibility = false;
  27          $static = false;
  28          $byReference = false;
  29          $functionIndent = '';
  30          $docBlock='';
  31          while ($t = current($this->tokens)) {
  32              
  33              if (is_array($t)) {
  34                  if ($t[0] == T_CLASS || (defined('T_INTERFACE')? $t[0] == T_INTERFACE:false) || $t[0] == T_FUNCTION) {
  35                      $previous = array_reverse($previous);
  36                      foreach($previous as $prev) {
  37                          if ($prev[0] == T_STATIC) {
  38                              $static = true;
  39                          } else if ($prev[0] == T_STRING && in_array($prev[1],array('private','public','protected'))) {
  40                              $visibility = $prev[1];
  41                          } else if ($prev[0] == T_PAAMAYIM_NEKUDOTAYIM) {
  42                              $byReference = true;
  43                          } else if (((defined('T_DOC_COMMENT')?$prev[0] == T_DOC_COMMENT:false) || T_COMMENT) && !@preg_match('/<\?php.*/',$prev[1]) && @preg_match('/\/\*/',$prev[1])) {
  44                              $docBlock = isset($prev[1])?$prev[1]:null;
  45                              break;
  46                          } else if (isset($prev[1]) && in_array($prev[1],array('private','public','protected'))){
  47                              $visibility = $prev[1];
  48                          }
  49                      }
  50                      $indent='';
  51                      if(!empty($docBlock)) {
  52                          $doclines = split("\n",$docBlock);
  53                          $lastLine = $doclines[count($doclines)-1];
  54                          if (preg_match('/(\s*)?\*/',$lastLine,$matches)) {
  55                              
  56                              $indent = substr($matches[1],0,strlen($matches[1])-1);
  57  
  58                              $doclines[0]=$indent.$doclines[0];
  59                              foreach($doclines as $idx=>$line) {
  60                                  $pre = '';
  61                                  if ($idx>0) {
  62                                      $pre = ' ';
  63                                  }
  64                                  $doclines[$idx] = $pre.trim($line);
  65                              }
  66                              $docBlock=implode("\n",$doclines);
  67                          }
  68                      } else {
  69                          $indent = $functionIndent;
  70                      }
  71                      $docBlock = str_replace('<?php','',$docBlock);
  72                      $string = (!empty($docBlock)?$docBlock."\n":'').($visibility?$visibility.' ':'').($static?' static ':'');
  73                      $this->readDefinition($static, $visibility, $byReference, $docBlock,$string, $indent);
  74                      $previous = array();
  75                      $docBlock = '';
  76                      $static = false;
  77                      $visibility = false;
  78                      $byReference = false;
  79                      $functionIndent = '';
  80                      $indent = '';
  81                      continue;
  82                  } else if ($t[0] == T_REQUIRE || $t[0] == T_REQUIRE_ONCE || $t[0] == T_INCLUDE || $t[0] == T_INCLUDE_ONCE) {
  83                      if (!isset($this->requires[$t[1]])) {
  84                          $this->requires[$t[1]] = array();
  85                      }
  86                      $org = $t;
  87                      $type= $t[1];
  88                      $val='';
  89                      next($this->tokens);
  90                      $t = current($this->tokens);
  91                      while ($t != '(') {
  92                          next($this->tokens);
  93                          $t = current($this->tokens);
  94                      }
  95                      next($this->tokens);
  96                      $t = current($this->tokens);
  97                      while ($t != ')') {
  98                          next($this->tokens);
  99                          if (is_array($t)) {
 100                              $val.=$t[1];
 101                          } else {
 102                              $val.=$t;
 103                          }
 104                          $t = current($this->tokens);
 105                      }
 106                      $this->requires[$type][]=$val;
 107                      $t = $org;
 108                  }
 109              }
 110              if ($t[0] != T_WHITESPACE) {
 111                  $previous[] = $t;
 112              } else if ($t[0] == T_WHITESPACE){
 113                  $functionIndent.=$t[1];
 114              }
 115               
 116              next($this->tokens);
 117          }
 118          $this->definitions = array_merge($this->definitions,$this->requires);
 119      }
 120      function _parseTag(&$tags, $tempTag)
 121      {
 122          switch($tempTag[0]) {
 123              case 'param':
 124                  if (preg_match('/\$([a-zA-Z0-9_]+)\s+(.*)/s',$tempTag[1],$pmatches)) {
 125                      if (!isset($tags['params'])) {
 126                          $tags['params'] = array(); 
 127                      } else if (!is_array($tags['params'])) {
 128                          $currentValue = $tags['params'];
 129                          $tags['params'] = array($currentValue); 
 130                      }
 131                      $tags['params'][$pmatches[1]] = trim($pmatches[2]);
 132                  } else {
 133                      
 134                      $tags['_unmatched_'][] = array($tempTag[0],$tempTag[1]);
 135                  }
 136                  break;
 137              default:
 138                  if(!empty($tags[$tempTag[0]])) {
 139                      if(!is_array($tags[$tempTag[0]])) {
 140                          
 141                          $currentValue = $tags[$tempTag[0]];
 142                          $tags[$tempTag[0]] = array($currentValue);
 143                      }
 144                      $tags[$tempTag[0]][]=trim($tempTag[1]);
 145                  } else {
 146                      $tags[$tempTag[0]]=trim($tempTag[1]);
 147                  }
 148                  
 149          }
 150      }
 151      function _parseDocBlock($string)
 152      {
 153          preg_match_all('/\/\*\*\n(\s*\*([^\n]+?\n)+)+.*?\*\//',$string,$matches);
 154          $docBlockStructure = array('comment'=>null);
 155          if (isset($matches[1][0])) {
 156              $docPart = $matches[1][0];
 157              $docPart = preg_replace('/\s*\*\s*/',"\n",$docPart);
 158              $docPart = trim($docPart);
 159              $commentLines = array();
 160              $tags = array('_unmatched_'=>array());
 161              $docLines = split("\n",$docPart);
 162              $inComment = true;
 163              $tempTag=array();
 164              foreach ($docLines as $line) {
 165                   if (preg_match('/^@([a-zA-Z0-9_]+)\s+(.+)$/',$line, $matches)) {
 166                      if (!empty($tempTag)) {
 167                          $this->_parseTag(&$tags, $tempTag);
 168                      }
 169                      $inComment = false;
 170                      $tempTag = array($matches[1],$matches[2]);
 171                  } else if ($inComment) {
 172                      $commentLines[] = $line;
 173                  } else {
 174                      $tempTag[1].="\n".$line;
 175                  }
 176              }
 177              if (!empty($tempTag)) {
 178                  $this->_parseTag(&$tags, $tempTag);
 179              }
 180              $docBlockStructure['comment'] = trim(implode("\n",$commentLines));
 181              $docBlockStructure['tags'] = $tags;
 182          }
 183          return $docBlockStructure;
 184      }
 185      
 186      function readDefinition($static = false, $visibility = 'public', $byReference = false, $docBlock = '', $string = '', $indent)
 187      {
 188          $t = current($this->tokens);
 189          $definitionType = $t[1];
 190  
 191          // move past the class/interface/function token
 192           
 193          next($this->tokens);
 194          $string.=$definitionType;
 195          $string.=$this->skipWhiteAndComments();
 196           
 197          $t = current($this->tokens);
 198          if (!isset($t[1])) {
 199              while(!isset($t[1])) {
 200                  if ($t=='&') {
 201                      
 202                      $string.=$t;
 203                      $byReference = true;
 204                      next($this->tokens);
 205                      $t = current($this->tokens);
 206                      
 207                  }
 208              }
 209              //$definitionType = $t[1];
 210              $string.=$t[1];
 211              
 212          } else {
 213              $string.=$t[1];
 214          }
 215  
 216          $definitionName = $t[1];
 217           
 218          $this->definitions[] = array(
 219            'type' => $definitionType,
 220            'name' => $definitionName,
 221            'visibility'=>$visibility==false?(substr($definitionName,0,2)=='__')?'private':(substr($definitionName,0,1)=='_'?'protected':false):$visibility,
 222            'static'=>$static,
 223            'returnByReference'=>$byReference,
 224            'docBlock' => $docBlock,
 225            'toString' => $string
 226          );
 227          
 228          // move past the name identifier
 229          next($this->tokens);
 230          
 231          list($params,$block,$pre,$post) = $this->getCodeBlock();
 232          $default_options = false;
 233          $available_options = false;
 234          if (preg_match('/\$default_options.*?=.*?(array\(.*?\)).*?;/s',$block,$default_option_matches)) {
 235              $default_options_string=$default_option_matches[1];
 236              $default_options_string = preg_replace_callback('/\$([A-Za-z0-9_\->])+/',array(&$this,'_replaceVariablesInsideOptions'),$default_options_string);
 237             @eval('$default_options = '.$default_options_string.';');
 238          }
 239          if (preg_match('/\$available_options.*?=.*?(array\(.*?\)).*?;/s',$block,$available_option_matches)) {
 240              $available_options_string=$available_option_matches[1];
 241              $available_options_string = preg_replace_callback('/\$([A-Za-z0-9_\->])+/',array(&$this,'_replaceVariablesInsideOptions'),$available_options_string);
 242             @eval('$available_options = '.$available_options_string.';');
 243          }
 244          $string.=$pre.$block.$post;
 245          $this->definitions[count($this->definitions)-1]['code'] = $block;
 246          $this->definitions[count($this->definitions)-1]['params'] = $params;
 247          $this->definitions[count($this->definitions)-1]['toString'] = $string;
 248          $this->definitions[count($this->definitions)-1]['default_options'] = $default_options;
 249          $this->definitions[count($this->definitions)-1]['available_options'] = $available_options;
 250          $strlines = split("\n",$string);
 251          foreach ($strlines as $idx=>$line) {
 252              $first = substr($line,0,strlen($indent));
 253              if ($first == $indent) {
 254                  $line = substr($line,strlen($first));
 255                  $strlines[$idx] = $line;
 256              }
 257          }
 258          $doclines = split("\n",$docBlock);
 259          foreach ($doclines as $idx=>$line) {
 260              $first = substr($line,0,strlen($indent));
 261              if ($first == $indent) {
 262                  $line = substr($line,strlen($first));
 263                  $doclines[$idx] = $line;
 264              }
 265          }
 266          $this->definitions[count($this->definitions)-1]['toString'] = implode("\n",$strlines);
 267          $this->definitions[count($this->definitions)-1]['docBlock'] = implode("\n",$doclines);
 268      }
 269      function _replaceVariablesInsideOptions($matches)
 270      {
 271          $name = $matches[0];
 272          return '"'.str_replace('$','\$',$name).'"';
 273      }
 274      function skipWhiteAndComments()
 275      {
 276          $string = '';
 277          while ($t = current($this->tokens)) {
 278              if (is_array($t) && ($t[0] == T_WHITESPACE || (defined('T_DOC_COMMENT')?$t[0] == T_DOC_COMMENT:false) || $t[0] == T_COMMENT)) {
 279                  next($this->tokens);
 280                  $string.=$t[1];
 281              } else {
 282                  return $string;
 283              }
 284          }
 285      }
 286  
 287      function skipCodeBlock()
 288      {
 289           
 290          // we go forward until we find the first "{" token
 291           
 292          while(($t = current($this->tokens)) && $t != '{') {
 293              next($this->tokens);
 294          }
 295          // we're about to enter the top level block
 296          // which is our class/interface/function definition body
 297          $nestingLevel = 0;
 298  
 299          // we go forward keeping the $nestingLevel up-to-date
 300          // until we get out of the definition body block
 301          while($t = current($this->tokens)) {
 302              if ($t == '{') {
 303                  $nestingLevel++;
 304              }
 305               
 306              if ($t == '}') {
 307                  $nestingLevel--;
 308              }
 309               
 310              next($this->tokens);
 311               
 312              if ($nestingLevel == 0) return;
 313          }
 314      }
 315      function getCodeBlock()
 316      {
 317          $prestring = '';
 318          $poststring = '';
 319          $codeblock = '';
 320          // we go forward until we find the first "{" token
 321          $params = array();
 322          $preParam = '';
 323          while(($t = current($this->tokens)) && $t != '{') {
 324              if (is_array($t)) {
 325                  switch ($t[0]) {
 326                      case T_VARIABLE:
 327                          $params[]=$preParam.$t[1];
 328                          $preParam = '';
 329                          break;
 330                  }
 331                  $prestring.=$t[1];
 332              } else if (!in_array($t,array(',','(',')'))) {
 333                  $preParam.=$t;
 334                  $prestring.=$t;
 335              } else {
 336                  $prestring.=$t;
 337              }
 338              next($this->tokens);
 339               
 340          }
 341          
 342          // we're about to enter the top level block
 343           
 344          // which is our class/interface/function definition body
 345          $nestingLevel = 0;
 346           
 347          // we go forward keeping the $nestingLevel up-to-date
 348          // until we get out of the definition body block
 349          while($t = current($this->tokens)) {
 350              if ($t == '{') {
 351                  $nestingLevel++;
 352              }
 353              
 354              if ($t == '}') {
 355                  $nestingLevel--;
 356              }
 357              
 358              next($this->tokens);
 359              
 360              
 361              if ($nestingLevel == 0) {
 362                  $poststring.=$t;
 363                  return array($params,$codeblock,$prestring,$poststring);
 364              } else {
 365                  if ($t == '{' && $nestingLevel==1) {
 366                      $prestring.=$t;
 367                      continue;
 368                  }
 369                  $codeblock.=is_array($t)?$t[1]:$t;
 370              }
 371          }
 372      }
 373      
 374      function getDefinitions()
 375      {
 376          return $this->definitions;
 377      }
 378  }
 379  ?>


Generated: Mon Oct 27 12:43:49 2008 Cross-referenced by PHPXref 0.6