PageRenderTime 47ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/aerial/core/amfphp/core/shared/util/MethodTable.php

http://aerial-cms.googlecode.com/
PHP | 554 lines | 397 code | 59 blank | 98 comment | 70 complexity | af91c2359de890c97a2e0cb53011ad8f MD5 | raw file
  1. <?php
  2. /**
  3. * Creates the methodTable for a service class.
  4. *
  5. * @usage $this->methodTable = MethodTable::create($this);
  6. * @author Christophe Herreman
  7. * @since 05/01/2005
  8. * @version $id$
  9. *
  10. * Special contributions by Allessandro Crugnola and Ted Milker
  11. */
  12. if (!defined('T_ML_COMMENT')) {
  13. define('T_ML_COMMENT', T_COMMENT);
  14. } else {
  15. define('T_DOC_COMMENT', T_ML_COMMENT);
  16. }
  17. function strrstr($haystack, $needle)
  18. {
  19. return substr($haystack, 0, strpos($haystack.$needle,$needle));
  20. }
  21. function strstrafter($haystack, $needle)
  22. {
  23. return substr(strstr($haystack, $needle), strlen($needle));
  24. }
  25. class MethodTable
  26. {
  27. /**
  28. * Constructor.
  29. *
  30. * Since this class should only be accessed through the static create() method
  31. * this constructor should be made private. Unfortunately, this is not possible
  32. * in PHP4.
  33. *
  34. * @access private
  35. */
  36. function MethodTable(){
  37. }
  38. /**
  39. * Creates the methodTable for a passed class.
  40. *
  41. * @static
  42. * @access public
  43. * @param $className(String) The name of the service class.
  44. * May also simply be __FILE__
  45. * @param $servicePath(String) The location of the classes (optional)
  46. */
  47. function create($className, $servicePath = NULL, &$classComment){
  48. $methodTable = array();
  49. if(file_exists($className))
  50. {
  51. //The new __FILE__ way of doing things was used
  52. $sourcePath = $className;
  53. $className = str_replace("\\", '/', $className);
  54. $className = substr($className, strrpos($className, '/') + 1);
  55. $className = str_replace('.php', '', $className);
  56. }
  57. else
  58. {
  59. $className = str_replace('.php', '', $className);
  60. $fullPath = str_replace('.', '/', $className);
  61. $className = $fullPath;
  62. if(strpos($fullPath, '/') !== FALSE)
  63. {
  64. $className = substr(strrchr($fullPath, '/'), 1);
  65. }
  66. if($servicePath == NULL)
  67. {
  68. if(isset($GLOBALS['amfphp']['classPath']))
  69. {
  70. $servicePath = $GLOBALS['amfphp']['classPath'];
  71. }
  72. else
  73. {
  74. $servicePath = "../services/";
  75. }
  76. }
  77. $sourcePath = $fullPath . ".php";
  78. }
  79. if(!file_exists($sourcePath))
  80. {
  81. trigger_error("The MethodTable class could not find {" .
  82. $sourcePath . "}",
  83. E_USER_ERROR);
  84. }
  85. if(class_exists('ReflectionClass'))
  86. {
  87. //PHP5
  88. $classMethods = MethodTable::getClassMethodsReflection($sourcePath, $className, $classComment);
  89. // print_r(array($sourcePath, $className, $classComment));
  90. // die();
  91. }
  92. else
  93. {
  94. //PHP4
  95. $classMethods = MethodTable::getClassMethodsTokenizer($sourcePath, $className, $classComment);
  96. }
  97. foreach ($classMethods as $key => $value) {
  98. if($value['name'][0] == '_' || $value['name'] == 'beforeFilter')
  99. {
  100. continue;
  101. }
  102. $methodSignature = $value['args'];
  103. $methodName = $value['name'];
  104. $methodComment = $value['comment'];
  105. $description = MethodTable::getMethodDescription($methodComment) . " " . MethodTable::getMethodCommentAttribute($methodComment, "desc");
  106. $description = trim($description);
  107. $access = MethodTable::getMethodCommentAttributeFirstWord($methodComment, "access");
  108. $roles = MethodTable::getMethodCommentAttributeFirstWord($methodComment, "roles");
  109. $instance = MethodTable::getMethodCommentAttributeFirstWord($methodComment, "instance");
  110. $returns = MethodTable::getMethodCommentAttributeFirstLine($methodComment, "returns");
  111. $pagesize = MethodTable::getMethodCommentAttributeFirstWord($methodComment, "pagesize");
  112. $params = MethodTable::getMethodCommentArguments($methodComment);
  113. //description, arguments, access, [roles, [instance, [returns, [pagesize]]]]
  114. $methodTable[$methodName] = array();
  115. //$methodTable[$methodName]["signature"] = $methodSignature; //debug purposes
  116. $methodTable[$methodName]["description"] = ($description == "") ? "No description given." : $description;
  117. $methodTable[$methodName]["arguments"] = MethodTable::getMethodArguments($methodSignature, $params);
  118. $methodTable[$methodName]["access"] = ($access == "") ? "private" : $access;
  119. if($roles != "") $methodTable[$methodName]["roles"] = $roles;
  120. if($instance != "") $methodTable[$methodName]["instance"] = $instance;
  121. if($returns != "") $methodTable[$methodName]["returns"] = $returns;
  122. if($pagesize != "") $methodTable[$methodName]["pagesize"] = $pagesize;
  123. }
  124. $classComment = trim(str_replace("\r\n", "\n", MethodTable::getMethodDescription($classComment)));
  125. return $methodTable;
  126. }
  127. function getClassMethodsReflection($sourcePath, $className, & $classComment)
  128. {
  129. //Include the class in question
  130. $dir = dirname($sourcePath);
  131. if(!is_dir($dir))
  132. {
  133. return array();
  134. }
  135. chdir($dir);
  136. if(!file_exists($sourcePath))
  137. {
  138. return array();
  139. }
  140. //HACK: eAccelerator
  141. //Check if eAccelator is installed
  142. if( extension_loaded( "eAccelerator" ))
  143. {
  144. //Touch the file so the results of getDocComment will be accurate
  145. touch($sourcePath);
  146. }
  147. $included = include_once($sourcePath);
  148. if($included === FALSE)
  149. {
  150. return array();
  151. }
  152. //Verify that the class exists
  153. if(!class_exists($className))
  154. {
  155. return array();
  156. }
  157. $methodTable = array();
  158. $class = new ReflectionClass($className);
  159. $classComment = $class->getDocComment();
  160. $methods = $class->getMethods();
  161. foreach($methods as $reflectionMethod){
  162. if($reflectionMethod->isPublic() && $method->name[0] != '_' && $method->name != 'beforeFilter')
  163. {
  164. if($reflectionMethod->isConstructor())
  165. {
  166. $classComment .= $reflectionMethod->getDocComment();
  167. }
  168. else
  169. {
  170. $reflectionParameter = $reflectionMethod->getParameters();
  171. $methodTableEntry = array();
  172. $parameters = array();
  173. foreach($reflectionParameter as $parameter){
  174. $parameters[] = $parameter->getName();
  175. }
  176. $methodTableEntry['args'] = '(' . implode(', ', $parameters);
  177. $methodTableEntry['name'] = $reflectionMethod->name;
  178. $methodTableEntry['comment'] = $reflectionMethod->getDocComment();
  179. $methodTable[] = $methodTableEntry;
  180. }
  181. }
  182. }
  183. return $methodTable;
  184. }
  185. function getClassMethodsTokenizer($sourcePath, $className, & $classComment)
  186. {
  187. $source = file_get_contents($sourcePath);
  188. $tokens = token_get_all($source);
  189. $waitingForOpenParenthesis = false;
  190. $waitingForFunction = false;
  191. $waitingForClassName = false;
  192. $bufferingArgs = false;
  193. $argBuffer = "";
  194. $lastFunction = "";
  195. $lastFunctionComment = "";
  196. $lastComment = "";
  197. $classMethods = array();
  198. $realClassName = "";
  199. $openBraces = -10000;
  200. $waitingForEndEncapsedString = false;
  201. foreach($tokens as $token)
  202. {
  203. if (is_string($token)) {
  204. if($token == '{')
  205. {
  206. $openBraces++;
  207. }
  208. if($token == '}')
  209. {
  210. if($waitingForEndEncapsedString)
  211. {
  212. $waitingForEndEncapsedString = false;
  213. }
  214. else
  215. {
  216. $lastComment = '';
  217. $openBraces--;
  218. if($openBraces == 0)
  219. {
  220. //break;
  221. }
  222. }
  223. }
  224. elseif($waitingForOpenParenthesis && $token == '(')
  225. {
  226. $bufferingArgs = true;
  227. $argBuffer = "";
  228. $waitingForOpenParenthesis = false;
  229. }
  230. elseif($bufferingArgs)
  231. {
  232. if($token != ')')
  233. {
  234. $argBuffer .= $token;
  235. }
  236. else
  237. {
  238. if($lastFunction != $realClassName && $lastFunction != "__construct")
  239. {
  240. $classMethods[] = array("name" => $lastFunction,
  241. "comment" => $lastFunctionComment,
  242. "args" => $argBuffer);
  243. }
  244. else
  245. {
  246. $classComment .= "\n\n" . $lastComment;
  247. }
  248. $bufferingArgs = false;
  249. $argBuffer = "";
  250. $lastFunction = "";
  251. $lastFunctionComment = "";
  252. }
  253. }
  254. } else {
  255. // token array
  256. list($id, $text) = $token;
  257. if($bufferingArgs)
  258. {
  259. $argBuffer .= $text;
  260. }
  261. switch ($id)
  262. {
  263. case T_COMMENT:
  264. case T_ML_COMMENT: // we've defined this
  265. case T_DOC_COMMENT: // and this
  266. // no action on comments
  267. $lastComment = $text;
  268. break;
  269. case T_FUNCTION:
  270. if($openBraces >= 1)
  271. {
  272. $waitingForFunction = true;
  273. }
  274. break;
  275. case T_STRING:
  276. if($waitingForFunction)
  277. {
  278. $waitingForFunction = false;
  279. $waitingForOpenParenthesis = true;
  280. $lastFunction = $text;
  281. $lastFunctionComment = $lastComment;
  282. $lastComment = "";
  283. }
  284. if($waitingForClassName)
  285. {
  286. $waitingForClassName = false;
  287. if(strpos(strtolower($className), strtolower($text)) !== FALSE)
  288. {
  289. //Not the class we were looking for
  290. $classComment = $lastComment;
  291. $realClassName = $text;
  292. }
  293. }
  294. break;
  295. case T_CLASS:
  296. $openBraces = 0;
  297. $waitingForClassName = true;
  298. break;
  299. case T_CURLY_OPEN:
  300. case T_DOLLAR_OPEN_CURLY_BRACES:
  301. $waitingForEndEncapsedString = true;
  302. break;
  303. }
  304. }
  305. }
  306. return $classMethods;
  307. }
  308. /**
  309. *
  310. */
  311. function getMethodCommentArguments($comment)
  312. {
  313. $pieces = explode('@param', $comment);
  314. $args = array();
  315. if(is_array($pieces) && count($pieces) > 1)
  316. {
  317. for($i = 0; $i < count($pieces) - 1; $i++)
  318. {
  319. $ps = strrstr($pieces[$i + 1], '@');
  320. $ps = strrstr($ps, '*/');
  321. $args[] = MethodTable::cleanComment($ps);
  322. }
  323. }
  324. return $args;
  325. }
  326. /**
  327. * Returns the description from the comment.
  328. * The description is(are) the first line(s) in the comment.
  329. *
  330. * @static
  331. * @private
  332. * @param $comment(String) The method's comment.
  333. */
  334. function getMethodDescription($comment){
  335. $comment = MethodTable::cleanComment(strrstr($comment, "@"));
  336. return trim($comment);
  337. }
  338. /**
  339. * Returns the value of a comment attribute.
  340. *
  341. * @static
  342. * @private
  343. * @param $comment(String) The method's comment.
  344. * @param $attribute(String) The name of the attribute to get its value from.
  345. */
  346. function getMethodCommentAttribute($comment, $attribute){
  347. $pieces = strstrafter($comment, '@' . $attribute);
  348. if($pieces !== FALSE)
  349. {
  350. $pieces = strrstr($pieces, '@');
  351. $pieces = strrstr($pieces, '*/');
  352. return MethodTable::cleanComment($pieces);
  353. }
  354. return "";
  355. }
  356. /**
  357. * Returns the value of a comment attribute.
  358. *
  359. * @static
  360. * @private
  361. * @param $comment(String) The method's comment.
  362. * @param $attribute(String) The name of the attribute to get its value from.
  363. */
  364. function getMethodCommentAttributeFirstLine($comment, $attribute){
  365. $pieces = strstrafter($comment, '@' . $attribute);
  366. if($pieces !== FALSE)
  367. {
  368. $pieces = strrstr($pieces, '@');
  369. $pieces = strrstr($pieces, "*");
  370. $pieces = strrstr($pieces, "/");
  371. $pieces = strrstr($pieces, "-");
  372. $pieces = strrstr($pieces, "\n");
  373. $pieces = strrstr($pieces, "\r");
  374. $pieces = strrstr($pieces, '*/');
  375. return MethodTable::cleanComment($pieces);
  376. }
  377. return "";
  378. }
  379. function getMethodCommentAttributeFirstWord($comment, $attribute){
  380. $pieces = strstrafter($comment, '@' . $attribute);
  381. if($pieces !== FALSE)
  382. {
  383. $val = MethodTable::cleanComment($pieces);
  384. return trim(strrstr($val, ' '));
  385. }
  386. return "";
  387. }
  388. /**
  389. * Returns an array with the arguments of a method.
  390. *
  391. * @static
  392. * @access private
  393. * @param $methodSignature (String)The method's signatureg;
  394. */
  395. function getMethodArguments($methodSignature, $commentParams){
  396. if(strlen($methodSignature) < 2){
  397. //no arguments, return an empty array
  398. $result = array();
  399. }else{
  400. //clean the arguments before returning them
  401. $result = MethodTable::cleanArguments(explode(",", $methodSignature), $commentParams);
  402. }
  403. return $result;
  404. }
  405. /**
  406. * Cleans the arguments array.
  407. * This method removes all whitespaces and the leading "$" sign from each argument
  408. * in the array.
  409. *
  410. * @static
  411. * @access private
  412. * @param $args(Array) The "dirty" array with arguments.
  413. */
  414. function cleanArguments($args, $commentParams){
  415. $result = array();
  416. foreach($args as $index => $arg){
  417. $arg = strrstr(str_replace('(', '', $arg), '=');
  418. if(!isset($commentParams[$index]))
  419. {
  420. $result[] = trim($arg);
  421. }
  422. else
  423. {
  424. $start = trim($arg);
  425. $end = trim(str_replace('$', '', $commentParams[$index]));
  426. //echo($start);
  427. //echo($end);
  428. if($end != "" && $start != "" && strpos(strtolower($end), strtolower($start)) === 0)
  429. {
  430. $end = substr($end, strlen($start));
  431. }
  432. $result[] = $start . ' - ' . trim($end);
  433. }
  434. }
  435. return $result;
  436. }
  437. /**
  438. * Cleans the comment string by removing all comment start and end characters.
  439. *
  440. * @static
  441. * @private
  442. * @param $comment(String) The method's comment.
  443. */
  444. function cleanComment($comment){
  445. $comment = str_replace("/**", "", $comment);
  446. $comment = str_replace("*/", "", $comment);
  447. $comment = str_replace("*", "", $comment);
  448. $comment = str_replace("\r", "", trim($comment));
  449. $comment = preg_replace("{\n[ \t]+}", "\n", trim($comment));
  450. $comment = str_replace("\n", "\\n", trim($comment));
  451. $comment = preg_replace("{[\t ]+}", " ", trim($comment));
  452. $comment = str_replace("\"", "\\\"", $comment);
  453. return $comment;
  454. }
  455. /**
  456. *
  457. */
  458. function showCode($methodTable){
  459. foreach($methodTable as $methodName=>$methodProps){
  460. $result .= "\n\t\"" . $methodName . "\" => array(";
  461. foreach($methodProps as $key=>$value){
  462. $result .= "\n\t\t\"" . $key . "\" => ";
  463. if($key=="arguments"){
  464. $result .= "array(";
  465. for($i=0; $i<count($value); $i++){
  466. $result .= "\"" . addslashes($value[$i]) . "\"";
  467. if($i<count($value)-1){
  468. $result .= ", ";
  469. }
  470. }
  471. $result .= ")";
  472. }else{
  473. $result .= "\"" . $value . "\"";
  474. }
  475. $result .= ",";
  476. }
  477. $result = substr($result, 0, -1);
  478. $result .= "\n\t),";
  479. }
  480. $result = substr($result, 0, -1);
  481. $result = "\$this->methodTable = array(" . $result;
  482. $result .= "\n);";
  483. return $result;
  484. }
  485. }
  486. ?>