PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/core/src/main/php/lang/reflect/Package.class.php

http://github.com/xp-framework/xp-framework
PHP | 306 lines | 134 code | 31 blank | 141 comment | 27 complexity | 5623907cbdaa9f145f325ae229fb38e0 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /* This class is part of the XP framework
  3. *
  4. * $Id$
  5. */
  6. /**
  7. * Represents a package
  8. *
  9. * @test xp://net.xp_framework.unittest.reflection.PackageTest
  10. * @see http://news.xp-framework.net/article/187/2007/05/12/
  11. * @purpose Reflection
  12. */
  13. class Package extends Object {
  14. protected
  15. $name= '';
  16. /**
  17. * Gets the fully qualified package name
  18. *
  19. * @return string
  20. */
  21. public function getName() {
  22. return $this->name;
  23. }
  24. /**
  25. * Returns simple name
  26. *
  27. * @return string
  28. */
  29. public function getSimpleName() {
  30. return substr($this->name, strrpos($this->name, '.')+ 1);
  31. }
  32. /**
  33. * Checks if a specific class is provided by this package
  34. *
  35. * @param string name
  36. * @return bool
  37. */
  38. public function providesClass($name) {
  39. return ClassLoader::getDefault()->providesClass($this->name.'.'.$name);
  40. }
  41. /**
  42. * Checks if a specific subpackage is provided by this package
  43. *
  44. * @param string name
  45. * @return bool
  46. */
  47. public function providesPackage($name) {
  48. return ClassLoader::getDefault()->providesPackage($this->name.'.'.$name);
  49. }
  50. /**
  51. * Checks if a specific resource is provided by this package
  52. *
  53. * @param string name
  54. * @return bool
  55. */
  56. public function providesResource($name) {
  57. return ClassLoader::getDefault()->providesResource(strtr($this->name, '.', '/').'/'.$name);
  58. }
  59. /**
  60. * Get all classes in this package. Loads classes if not already
  61. * loaded.
  62. *
  63. * @return lang.XPClass[]
  64. */
  65. public function getClasses() {
  66. return array_map(array(xp::reflect('lang.XPClass'), 'forName'), $this->getClassNames());
  67. }
  68. /**
  69. * Get the names of classes in this package, not loading them.
  70. *
  71. * @return string[]
  72. */
  73. public function getClassNames() {
  74. $classes= array();
  75. foreach (ClassLoader::getDefault()->packageContents($this->name) as $file) {
  76. if (xp::CLASS_FILE_EXT == substr($file, -10)) $classes[]= ltrim($this->name.'.'.substr($file, 0, -10), '.');
  77. }
  78. return $classes;
  79. }
  80. /**
  81. * Load a specific class by its name, which may be either locally
  82. * qualified (without dots) or fully qualified (with dots).
  83. *
  84. * @param string name
  85. * @return lang.XPClass
  86. * @throws lang.IllegalArgumentException
  87. */
  88. public function loadClass($name) {
  89. // Handle fully qualified names
  90. if (FALSE !== ($p= strrpos($name, '.'))) {
  91. if (substr($name, 0, $p) != $this->name) {
  92. throw new IllegalArgumentException('Class '.$name.' is not in '.$this->name);
  93. }
  94. $name= substr($name, $p+ 1);
  95. }
  96. return XPClass::forName($this->name.'.'.$name);
  97. }
  98. /**
  99. * Returns a list of subpackages in this package.
  100. *
  101. * @return lang.reflect.Package[]
  102. */
  103. public function getPackages() {
  104. return array_map(array(xp::reflect('lang.reflect.Package'), 'forName'), $this->getPackageNames());
  105. }
  106. /**
  107. * Returns a list of subpackages in this package.
  108. *
  109. * @return string[]
  110. */
  111. public function getPackageNames() {
  112. $packages= array();
  113. foreach (ClassLoader::getDefault()->packageContents($this->name) as $file) {
  114. if ('/' == substr($file, -1)) $packages[]= ltrim($this->name.'.'.substr($file, 0, -1), '.');
  115. }
  116. return $packages;
  117. }
  118. /**
  119. * Returns a list of resources in this package.
  120. *
  121. * @return string[]
  122. */
  123. public function getResources() {
  124. $resources= array();
  125. foreach (ClassLoader::getDefault()->packageContents($this->name) as $file) {
  126. if ('/' == substr($file, -1) || xp::CLASS_FILE_EXT == substr($file, -10)) continue;
  127. $resources[]= strtr($this->name, '.', '/').'/'.$file;
  128. }
  129. return $resources;
  130. }
  131. /**
  132. * Get a specific subpackage of this package by its name, which
  133. * may be either locally qualified (without dots) or fully
  134. * qualified (with dots).
  135. *
  136. * @param string name
  137. * @return lang.reflect.Package
  138. * @throws lang.IllegalArgumentException
  139. */
  140. public function getPackage($name) {
  141. // Handle fully qualified names
  142. if (FALSE !== ($p= strrpos($name, '.'))) {
  143. if (substr($name, 0, $p) != $this->name) {
  144. throw new IllegalArgumentException('Package '.$name.' is not in '.$this->name);
  145. }
  146. $name= substr($name, $p+ 1);
  147. }
  148. return self::forName($this->name.'.'.$name);
  149. }
  150. /**
  151. * Returns a Package object for a given fully qualified name.
  152. *
  153. * @param string name
  154. * @return lang.reflect.Package
  155. * @throws lang.ElementNotFoundException
  156. */
  157. public static function forName($name) {
  158. $p= new self();
  159. $p->name= rtrim($name, '.'); // Normalize
  160. if (!ClassLoader::getDefault()->providesPackage($p->name)) {
  161. raise('lang.ElementNotFoundException', 'No classloaders provide '.$name);
  162. }
  163. return $p;
  164. }
  165. /**
  166. * Loads a resource.
  167. *
  168. * @param string filename name of resource
  169. * @return string
  170. * @throws lang.ElementNotFoundException in case the resource cannot be found
  171. */
  172. public function getResource($filename) {
  173. // Handle fully qualified names
  174. if (FALSE !== ($p= strrpos($filename, '/'))) {
  175. if (substr($filename, 0, $p) != strtr($this->name, '.', '/')) {
  176. throw new IllegalArgumentException('Resource '.$filename.' is not in '.$this->name);
  177. }
  178. $filename= substr($filename, $p+ 1);
  179. }
  180. return ClassLoader::getDefault()->getResource(strtr($this->name, '.', '/').'/'.$filename);
  181. }
  182. /**
  183. * Retrieve a stream to the resource
  184. *
  185. * @param string filename name of resource
  186. * @return io.File
  187. * @throws lang.ElementNotFoundException in case the resource cannot be found
  188. */
  189. public function getResourceAsStream($filename) {
  190. // Handle fully qualified names
  191. if (FALSE !== ($p= strrpos($filename, '/'))) {
  192. if (substr($filename, 0, $p) != strtr($this->name, '.', '/')) {
  193. throw new IllegalArgumentException('Resource '.$filename.' is not in '.$this->name);
  194. }
  195. $filename= substr($filename, $p+ 1);
  196. }
  197. return ClassLoader::getDefault()->getResourceAsStream(strtr($this->name, '.', '/').'/'.$filename);
  198. }
  199. /**
  200. * Returns details for a given package. Note: Results from this method
  201. * are cached.
  202. *
  203. * @param string package
  204. * @return [:var] details or NULL
  205. */
  206. public static function detailsForPackage($package) {
  207. if (!isset(xp::$meta[$package])) {
  208. $cl= ClassLoader::getDefault();
  209. $info= strtr($package, '.', '/').'/package-info.xp';
  210. if (!$cl->providesResource($info)) return NULL;
  211. $tokens= token_get_all($cl->getResource($info));
  212. $details= array();
  213. $comment= NULL;
  214. for ($i= 0, $s= sizeof($tokens); $i < $s; $i++) {
  215. switch ($tokens[$i][0]) {
  216. case T_DOC_COMMENT:
  217. $comment= $tokens[$i][1];
  218. break;
  219. case T_STRING:
  220. if ('package' === $tokens[$i][1]) {
  221. $details[DETAIL_COMMENT]= trim(preg_replace('/\n \* ?/', "\n", "\n".substr(
  222. $comment,
  223. 4, // "/**\n"
  224. strpos($comment, '* @')- 2 // position of first details token
  225. )));
  226. }
  227. break;
  228. }
  229. }
  230. xp::$meta[$package]= $details;
  231. }
  232. return xp::$meta[$package];
  233. }
  234. /**
  235. * Gets package comment from package-info.xp. Returns NULL if no such
  236. * file exists inside this package
  237. *
  238. * @return string
  239. */
  240. public function getComment() {
  241. $details= self::detailsForPackage($this->name);
  242. return NULL === $details ? NULL : $details[DETAIL_COMMENT];
  243. }
  244. /**
  245. * Creates a string representation of this package
  246. *
  247. * Example:
  248. * <pre>
  249. * lang.reflect.Package<fully.qualified.package.Name>
  250. * </pre>
  251. *
  252. * @return string
  253. */
  254. public function toString() {
  255. return $this->getClassName().'<'.$this->name.'>';
  256. }
  257. /**
  258. * Checks whether a given object is equal to this Package instance.
  259. *
  260. * @param lang.Generic cmp
  261. * @return bool
  262. */
  263. public function equals($cmp) {
  264. return $cmp instanceof self && $this->name === $cmp->name;
  265. }
  266. /**
  267. * Creates a hashcode for this package
  268. *
  269. * @return string
  270. */
  271. public function hashCode() {
  272. return 'P['.$this->name;
  273. }
  274. }
  275. ?>