PageRenderTime 27ms CodeModel.GetById 54ms RepoModel.GetById 0ms app.codeStats 0ms

/class/lang/aop/AOP.php

https://github.com/JeCat/framework
PHP | 299 lines | 210 code | 43 blank | 46 comment | 17 complexity | b04b167e9feb8f11ec5779f8721dbf00 MD5 | raw file
  1. <?php
  2. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3. // 这个文件是 JeCat PHP框架的一部分,该项目和此文件 均遵循 GNU 自由软件协议
  4. //
  5. // Copyleft 2008-2012 JeCat.cn(http://team.JeCat.cn)
  6. //
  7. //
  8. // JeCat PHP框架 的正式全名是:Jellicle Cat PHP Framework。
  9. // “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》(《Prologue:Jellicle Songs for Jellicle Cats》)。
  10. // JeCat 是一个开源项目,它像音乐剧中的猫一样自由,你可以毫无顾忌地使用JCAT PHP框架。JCAT 由中国团队开发维护。
  11. // 正在使用的这个版本是:0.7.1
  12. //
  13. //
  14. //
  15. // 相关的链接:
  16. // [主页] http://www.JeCat.cn
  17. // [源代码] https://github.com/JeCat/framework
  18. // [下载(http)] https://nodeload.github.com/JeCat/framework/zipball/master
  19. // [下载(git)] git clone git://github.com/JeCat/framework.git jecat
  20. // 不很相关:
  21. // [MP3] http://www.google.com/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
  22. // [VCD/DVD] http://www.google.com/search?q=CAT+Andrew+Lloyd+Webber+video
  23. //
  24. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  25. /*-- Project Introduce --*/
  26. namespace org\jecat\framework\lang\aop ;
  27. use org\jecat\framework\bean\BeanFactory;
  28. use org\jecat\framework\fs\File;
  29. use org\jecat\framework\lang\compile\IStrategySummary;
  30. use org\jecat\framework\fs\FSO;
  31. use org\jecat\framework\lang\Exception;
  32. use org\jecat\framework\lang\oop\Package;
  33. use org\jecat\framework\lang\compile\CompilerFactory;
  34. use org\jecat\framework\lang\oop\ClassLoader;
  35. use org\jecat\framework\pattern\composite\Container;
  36. use org\jecat\framework\lang\Object;
  37. class AOP extends Object implements IStrategySummary, \Serializable
  38. {
  39. /**
  40. * 注册一个 Aspect 类
  41. */
  42. public function register($sAspectClass)
  43. {
  44. trigger_error('请使用 AOP::registerBean() 替代 AOP::register()',E_USER_DEPRECATED ) ;
  45. if( !isset($this->arrAspectClasses[$sAspectClass]) )
  46. {
  47. $this->arrAspectClasses[$sAspectClass] = $sAspectClass ;
  48. $this->parseAspectClass($sAspectClass) ;
  49. $this->aPointcutIterator = null ;
  50. $this->aJointPointIterator = null ;
  51. }
  52. return $this ;
  53. }
  54. /**
  55. * @return AOP
  56. */
  57. public function registerBean(array $arrConfig,$sAspectDefineFile=null)
  58. {
  59. if( empty($arrConfig['class']) )
  60. {
  61. $arrConfig['class'] = 'aspect' ;
  62. }
  63. $aAspect = BeanFactory::singleton()->createBean($arrConfig) ;
  64. if($sAspectDefineFile)
  65. {
  66. $aAspect->setAspectFilepath(FSO::tidyPath($sAspectDefineFile)) ;
  67. }
  68. $this->aspects()->add($aAspect) ;
  69. $this->aPointcutIterator = null ;
  70. $this->aJointPointIterator = null ;
  71. return $this ;
  72. }
  73. public function unregister(Aspect $aAspect)
  74. {
  75. unset( $this->arrAspectClasses[ $aAspect->aspectName() ] ) ;
  76. $this->aspects()->remove($aAspect) ;
  77. }
  78. /**
  79. * @return \Iterator
  80. */
  81. public function aspectIterator()
  82. {
  83. return $this->aAspects? $this->aspects()->iterator(): new \EmptyIterator() ;
  84. }
  85. /**
  86. * @return \Iterator
  87. */
  88. public function jointPointIterator()
  89. {
  90. if(!$this->aJointPointIterator)
  91. {
  92. if( !$this->aAspects )
  93. {
  94. $this->aJointPointIterator = new \EmptyIterator() ;
  95. }
  96. else
  97. {
  98. $this->aJointPointIterator = new \AppendIterator() ;
  99. foreach($this->aspects()->iterator() as $aAspects)
  100. {
  101. foreach ($aAspects->pointcuts()->iterator() as $aPointcut)
  102. {
  103. $this->aJointPointIterator->append($aPointcut->jointPoints()->iterator()) ;
  104. }
  105. }
  106. }
  107. }
  108. return $this->aJointPointIterator ;
  109. }
  110. /**
  111. * @return \Iterator
  112. */
  113. public function pointcutIterator()
  114. {
  115. if(!$this->aPointcutIterator)
  116. {
  117. if( !$this->aAspects )
  118. {
  119. $this->aPointcutIterator = new \EmptyIterator() ;
  120. }
  121. else
  122. {
  123. $this->aPointcutIterator = new \AppendIterator() ;
  124. foreach($this->aspects()->iterator() as $aAspects)
  125. {
  126. $this->aPointcutIterator->append($aAspects->pointcuts()->iterator()) ;
  127. }
  128. }
  129. }
  130. return $this->aPointcutIterator;
  131. }
  132. public function weave()
  133. {
  134. $aClassLoader = ClassLoader::singleton() ;
  135. $arrBeWeavedClasses = array() ;
  136. $aCompiler = null ;
  137. foreach($this->jointPointIterator() as $aJointPoint)
  138. {
  139. $sBeWeavedClass = $aJointPoint->weaveClass() ;
  140. if( !in_array($sBeWeavedClass,$arrBeWeavedClasses) )
  141. {
  142. $sSrcClassFile = $aClassLoader->searchClass($sBeWeavedClass,Package::nocompiled) ;
  143. $sCmpdClassFile = $aClassLoader->searchClass($sBeWeavedClass,Package::compiled) ;
  144. if( !$sSrcClassFile )
  145. {
  146. throw new Exception(
  147. "AOP 无法将目标代码织入到 JointPoint %s 中:没有找到类 %s 的源文件。"
  148. , array($aJointPoint->$sBeWeavedClass,$aJointPoint->name())
  149. ) ;
  150. }
  151. if( !$sCmpdClassFile )
  152. {
  153. throw new Exception(
  154. "AOP 无法将目标代码织入到 JointPoint %s 中:没有找到类 %s 的编译文件。"
  155. , array($aJointPoint->$sBeWeavedClass,$aJointPoint->name())
  156. ) ;
  157. }
  158. if(!$aCompiler)
  159. {
  160. $aCompiler = $this->createClassCompiler() ;
  161. }
  162. $aCompiler->compile( File::createInstance($sSrcClassFile)->openReader(), File::createInstance($sCmpdClassFile)->openWriter() ) ;
  163. $arrBeWeavedClasses[] = $sBeWeavedClass ;
  164. }
  165. }
  166. }
  167. /**
  168. * aspects库 的指纹签名
  169. */
  170. public function strategySummary()
  171. {
  172. if( $this->sAspectLibSignture )
  173. {
  174. return $this->sAspectLibSignture ;
  175. }
  176. if(!$this->arrAspectClasses)
  177. {
  178. return '' ;
  179. }
  180. // 根据注册的 apect 类生成签名
  181. $arrBox = null ;
  182. $aClassLoader = ClassLoader::singleton() ;
  183. foreach($this->arrAspectClasses as $sAspectClass)
  184. {
  185. $arrBox[] = $sAspectClass ;
  186. }
  187. return $this->sAspectLibSignture = md5( serialize($arrBox) ) ;
  188. }
  189. public function createClassCompiler()
  190. {
  191. $aCompiler = CompilerFactory::createInstance()->create() ;
  192. $aCompiler->registerGenerator("org\\jecat\\framework\\lang\\compile\\object\\FunctionDefine","org\\jecat\\framework\\lang\\aop\\compiler\\FunctionDefineGenerator") ;
  193. return $aCompiler ;
  194. }
  195. private function parseAspectClass($sAspectClass)
  196. {
  197. if( !$sClassFile = ClassLoader::singleton()->searchClass($sAspectClass,Package::nocompiled) )
  198. {
  199. throw new Exception("注册到AOP中的Aspace(%s)不存在; Aspace必须是一个有效的类",$sAspectClass) ;
  200. }
  201. $aClassCompiler = CompilerFactory::singleton()->create() ;
  202. $aTokenPool = $aClassCompiler->scan($sClassFile) ;
  203. $aClassCompiler->interpret($aTokenPool) ;
  204. if( !$aClassToken=$aTokenPool->findClass($sAspectClass) )
  205. {
  206. throw new Exception("根据 class path 搜索到class的定义文件:%s,但是该文件中没有定义:%s",
  207. array($sAspectClass,$sClassFile,$sAspectClass)
  208. ) ;
  209. }
  210. $this->aspects()->add(Aspect::createFromToken($aClassToken,$sClassFile)) ;
  211. }
  212. /**
  213. * @return org\jecat\framework\pattern\composite\IContainer
  214. */
  215. public function aspects()
  216. {
  217. if( !$this->aAspects )
  218. {
  219. $this->aAspects = new Container('org\\jecat\\framework\\lang\\aop\\Aspect') ;
  220. }
  221. return $this->aAspects ;
  222. }
  223. public function isValid()
  224. {
  225. foreach( $this->aspectIterator() as $aAspect )
  226. {
  227. if( !$aAspect->isValid() )
  228. {
  229. return false ;
  230. }
  231. }
  232. return true ;
  233. }
  234. public function serialize()
  235. {
  236. $arrData = array(
  237. 'arrAspectClasses' => &$this->arrAspectClasses ,
  238. 'aAspects' => $this->aAspects ,
  239. 'sAspectLibSignture' => &$this->sAspectLibSignture ,
  240. ) ;
  241. return serialize($arrData) ;
  242. }
  243. public function unserialize($serialized)
  244. {
  245. $this->__construct() ;
  246. $arrData = unserialize($serialized) ;
  247. $this->arrAspectClasses =& $arrData['arrAspectClasses'] ;
  248. $this->aAspects =& $arrData['aAspects'] ;
  249. $this->sAspectLibSignture =& $arrData['sAspectLibSignture'] ;
  250. }
  251. private $arrAspectClasses ;
  252. private $aAspects ;
  253. private $aPointcutIterator ;
  254. private $aJointPointIterator ;
  255. private $sAspectLibSignture ;
  256. }