php实现annotation,PHP的Annotations

Annotation是什么?

好吧,名字确实有点陌生,但是直白一点Annotation就是每天与我们经常打交道的注释。 何为注释?一种独特的有说明性的注解,在代码中就是注释咯。Annotation是相关代码的元数据(metadata:用来描述数据的数据)。有些编程语言中它仅仅是一种描述性的东西,并不会直接影响我们的代码运行情况,比如PHP;而在另外一些编程语言中,则会产生影响,比如Java、C#等。 但是说白了,今天讨论的Annotation没什么高大上的,它还是注释。但我想今天讨论了Annotation之后,你心中的注释的范围或者注释的功能将会变得不同。

先预个热,假如我们之前谈到的注释叫Comment的话,那么Annotation将是Comment的超集,也就是说Annotation = {Comment, DocBlock, …}。 你可能发现了DocBlock这样的概念。

DocBlock是什么,和传统的Comment有什么区别?

Comment:// this is a comment

/* this is a multiline comment */

Docblock:/**

* this is a docblock

*/

还有一个区别:Comment将会被Opcache忽略,而Docblock将会被Opcache缓存。

Annotation有什么好处?

姑且说我们已经可以写得一屏好注释(Comment)了,所以我们今天将只讨论Annotation的DocBlock部分。

先来一个Annotation的例子,前面说到Comment本身无法为我们的代码带来什么好处,而是会带来一些提高可读性的好处,如下:class Foo

{

/**

* @var integer

* @range(0, 100)

*/

public $bar;

}告诉我们$bar期望是一个整数

告诉我们$bar期望的范围是0-100

除了告诉我们之外,也告诉IDE Foo实例的$bar属性是整数

基本的Annotation例子就是这样,而且我敢保证这样的例子你也并不陌生,标准的Annotation就是类似于以 @ 开头的,比如@var @param等,它们的语法格式为:@var {type} {description}

@param {type} {$name} {description}

如果是PHP程序员的话,对@var会比较陌生,因为IDE经常会为我们自动生成@param这样的Annotation。

PHPDocument?

看到这样的语法,如果接触过PHPDocument或者Javadoc的同学可能会相对会熟悉一些,比如我们可以通过PHPDocument生成代码的文档,而且可以在线浏览。而如果我们今天只讨论这种文档级别的内容或许就没什么意思了,看一下下面这个例子。public class Customer

{

[Required]

[StringLength(50)]

public string Prename(String name){}

看到上面的代码,我们猜猜Prename()函数上面的[Required]和[StringLength(50)]有什么作用?实际上这个可以理解为C#的Annotation,而这两行就是用于控制name参数一定要存在并且长度不超过50个字符。那么是否真的可以控制?或者说如果真的超过50个字符后程序会有什么表现呢?难道还能抛出异常还是什么呢?

把上面的代码翻译成PHP版本的,大概是下面这个样子:class Customer

{

/**

* required

* NameLength(50)

*/

public function Prename($name){}

然而,然而,然而,这Annotation是写在/** */里面的,从学任何一门编程语言的第一天起就知道,这是不会执行的,对吧?那Annotation貌似好像并没有什么卵用。

PHP官方对Annotation的支持程度?

2000:PHPDocument创立

2005:PHP5.1的Reflection支持getDoccomments()<?php

/**

* * A test class

* *

* * @param foo bar

* * @return baz

* */

class TestClass { }

$rc = new ReflectionClass('TestClass');

var_dump($rc->getDocComment());

?>

2008:Doctrine2 也是PHP的Annotation引擎

2010:PHP Rfc讨论了关于Annotations内容rfc/annotations,But没有通过投票。

2011:PHP Rfc讨论了DocBlockrfc/annotations-in-docblock

2013:再一次讨论

没下文了。。。

是的,实际上真的没有下文了,不过如果今天的讨论到此为止,那我猜你得想打死我~然而PHP官方确实没有对此进行过强有力的支持,但即便如此,有许多优秀的框架/库还是花费了不懈的努力去实现并享受着Annotation带来的好处。

Annotation的实际项目Symfony

Doctrine

PHPUnit

ZendFramework

Annotation可以用来做什么?

测试

PHPUnit的一个例子,通过为测试方法定义一些Annotation,比如此例子中定义InvalidArgumentException参数指定异常实例。class DataTest extends PHPUnit_Framework_TestCase

{

/**

* @dataProvider provider

*

* @expectedException InvalidArgumentException

* @expectedExceptionMessage Right Message

*/

public function testAdd($a, $b, $c)

{

/* Test code */

}

钩子/回调/参数验证/**

* @Route("/myaction/{id}", name="myaction")

* @Method("POST")

*

* @Template("MyBundle:MyController:my.html.twig") *

* @param int $id *

* @return array

*/

public function myAction($id)

{

/* Controller Logic */

return array('data' => $data);

}

看上面这个Symfony的例子,通过定义为myAction定义了@Route @Method @Template等Annotation,不仅对myAction()一目了然,并且Symfony通过解析@Template则可以做一些类似于回调的东西,可以在框架层次将内容解析到模板中,此过程大概类似于如下

index.php路由到myAction -> $rc->getDocComment()得到myAction()的Annotation -> 解析Annotation得到myAction()的模板 -> 框架得到myAction()返回的数据 -> 将数据渲染到模板

过程其实还是很清晰的,同时在此过程中也可以很容易的做一些参数验证的工作,比如$id的类型啊,大小啊什么的。

filterclass Foo

{

/**

* @My\Annotation("name", nullable=true)

*/

public funciton myAction($name)

{

从上面的例子上看,实现参数过滤当然也是可能的啦,而在Symfony2中还存在了这样一个bundle以达到通过Annotatios功能的rdohms/DMS。

综上

PHP对Annotation的支持一直表现的很拘谨,不过好在在反射中还对此做出了点贡献,不然今天的PHP届Annotation真心不太好玩。不过感谢那么多大牛和前辈将Annotation吸收到了非常有名的框架中,让更多的PHPer知道。

当然Annotation也不是一个特别流行的语言特性,目前貌似只有c#和Java存在,虽然Annotation有比较多的用途,但是具体使用还是要综合考量。

延伸阅读

如果读者感兴趣,可以研究下Doctrine的Annotation Parser

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值