在
PHP中可以使用等效的.NET方法属性,还是以某种方式模拟这些?
上下文
我们有一个我们喜欢的内部URL路由类.它今天工作的方式是,我们首先必须使用中央路由管理员注册所有的路由,如下所示:
$oRouteManager->RegisterRoute('admin/test/',array('CAdmin','SomeMethod')); $oRouteManager->RegisterRoute('admin/foo/','SomeOtherMethod')); $oRouteManager->RegisterRoute('test/',array('CTest','SomeMethod'));
每当遇到路由时,调用回调方法(在上述情况下都是静态类方法).但是,这样做将路由与方法分开,至少在代码中.
<Route Path="admin/test/"> public static void SomeMethod() { /* implementation */ }
我现在看到的选项是要创建一些PHPDoc扩展,让我能够这样:
/** * @route admin/test/ */ public static function SomeMethod() { /* implementation */ }
但是,这将需要编写/重用PHPDoc的解析器,并且很可能会相当缓慢.
另一个选择是将每个路由分成自己的类,并具有如下所示的方法:
class CAdminTest extends CRoute { public static function Invoke() { /* implementation */ } public static function GetRoute() { return "admin/test/"; } }
这就是我最终解决这个问题.
article provided by Kevin是一个巨大的帮助.通过使用ReflectionClass和ReflectionMethod :: getDocComment,我可以轻松地浏览PHPDoc注释.一个小的正则表达式找到任何@route,并注册到该方法.
反思不是那么快(在我们的情况下,在一个单独的函数中对于RegiserRoute进行硬编码调用的速度是慢2.5倍),而且由于我们有很多路由,所以我们不得不将完成的路由列表缓存Memcached,所以在每一页的加载上都不需要反射.总的来说,我们最终在缓存时平均花了7ms将路由注册为1,7ms(平均每个页面的反射使用了18ms).
public static function RegisterRoutes() { $sClass = get_called_class(); // unavailable in PHP < 5.3.0 $rflClass = new ReflectionClass($sClass); foreach ($rflClass->getMethods() as $rflMethod) { $sComment = $rflMethod->getDocComment(); if (preg_match_all('%^\s*\*\s*@route\s+(?P<route>/?(?:[a-z0-9]+/?)+)\s*$%im',$sComment,$result,PREG_PATTERN_ORDER)) { foreach ($result[1] as $sRoute) { $sMethod = $rflMethod->GetName(); $oRouteManager->RegisterRoute($sRoute,array($sClass,$sMethod)); } } } }
感谢大家指出我正确的方向,这里有很多好的建议!我们采用这种方法,只是因为它允许我们保持路由接近它调用的代码:
class CSomeRoutable extends CRoutable { /** * @route /foo/bar * @route /for/baz */ public static function SomeRoute($SomeUnsafeParameter) { // this is accessible through two different routes echo (int)$SomeUnsafeParameter; } }