zend framework

从理论上来说,PHP是一种通用的动态语言,它可以替代Perl实现通用的脚本,甚至可以创建客户端GUI程序(通过GTK+)。但是,在实际应用中,PHP在绝大多数情况下都被用来开发Web应用。即使在Java和.NET这样有软件业界巨头支持的重量级竞争对手面前,出身草莽的PHP也毫不逊色,尤其是在应用最为广泛的轻量级web开发领域,PHP一直牢牢占据着领先的位置。在这一领域参与竞争的其他语言,例如Python和Perl,虽然各具特色,但是仍然无法撼动PHP的地位。PHP是当之无愧的“Web开发第一语言”,而且似乎没有什么能对它构成挑战。随着web应用在软件界的地位越来越重要,PHP也逐渐从脚本小子手中的玩具,转变成重要的工业语言,并获得了IBM这样的巨人的支持。 

        但是,就在近两三年,一种新的Web开发解决方案的迅速崛起,震动了整个业界,让PHP开始感到王座不稳。这个解决方案,当然就是Ruby on Rails。 

        本文无意对PHP和Ruby这两种语言进行全面的比较(虽然这的确是一个非常有意思的话题)。无论读者对Ruby和ROR持什么看法,有一点却是不争的事实:Ruby作为一种新的语言,虽然极具特色,但是并没有得到业界的普遍接受;只有在ROR诞生以后,以其惊人的生产力征服了无数开发者,Ruby这才一飞冲天。也就是说,Ruby至于在很大程度上是依靠ROR这个框架,才能起迅速崛起。 

        对于感到严重威胁的PHP社区,如果要对Ruby进行有效的反击,这似乎是一条可行的道路:基于PHP语言,实现一个新的web开发框架,能够达到甚至超过ROR那样的生产力。这既是对Ruby的反击,其实也是PHP自身发展的必然结果。因为PHP在其发展过程中,早已经出现了数十个各种各样的框架,只是尚没有一个能具有ROR那样的生产力和影响力。 
        但是,实现这样一个框架,也面临着不少的问题: 
   
        PHP语言本身能否完成这一任务?PHP原本只是用于快速解决web应用的简单脚本,虽然经过不断的发展,已经具有了许多高级的语言特征,但是是否能够实现象ROR那样精巧和强大的框架,能够达到ROR那样的生产力? 

       PHP社群能否接受这样一个框架?PHP的使用者,大多数是脚本小子出身,习惯于快速、敏捷、直观的开发方式,对于重量级的框架,未必能够普遍认同。 

       无论这些问题的答案如何,重要的是,有人这么做了。Zend Framework就是这一思路的结果。 

       如上所述,Zend Framework就是这样一个完全基于PHP语言的、向ROR学习的、针对web应用开发的框架。与其它同类的框架相比,Zend Framework有两个特点让它显得与众不同: 
       Zend Framework由Zend公司开发,因此它是一个“官方的”框架。众所周知, Zend公司是PHP编译器的维护者,也是Zend Optimizer、Zend Studio等一系列PHP相关产品的拥有者。由于这一关系,Zend Framework虽然没有被内置到PHP发行包中,但也算得上PHP的官方解决方案了。(顺便说句题外话,Zend公司最近发布了Zend Studio for Eclipse的beta版本,有兴趣的读者不妨尝试一下。) 

       Zend Framework跟ROR实在太象了。和ROR一样,Zend Framework使用了同样的Front Controller模式,同样的Model/Controller/View模型,同样的ORM思路,甚至连命名规则都十分相似。当然了,Zend Framework跟ROR的不同之处还是很多的,至于底层的实现细节,肯定区别更大。但是,不管是有意还是无意(好吧,我承认“无意”绝对不可能做成这样),Zend Framework的实现思路和ROR是非常相似的。 

       这是一个典型的Zend Framework应用的目录: 
引用
  /root 
  /application 
  /controllers 
  /models 
  /views 
  /filters 
  /helpers 
  /scripts 
  /library 
  /public 
  /images 
  /scripts 
  /styles 

   
       其中,library目录下存放的是Zend Framework所有的库文件,如果还有其他第三方的库文件,也可以存放在这里。Public目录是唯一一个可以通过web方式直接访问的目录,但它并不存放php文件,只存放CSS、JavaScript脚本、图片等静态文件。Application目录中存放着实现应用逻辑的所有PHP文件,它又拥有三个子目录:controllers、models、views。顾名思义,它们分别用于存放控制器/模型/视图的相应PHP文件。 

       Zend Framework实现了Front Controller模式,这意味着,所有的http请求都会被转发到同一个入口,然后再路由到相应的控制器。这个入口就是root根目录下的 index.php文件。Zend Framework通过URL Rewrite技术来实现这一点。在root根目录下,存在一个.htaccess文件,内容如下: 
   
引用
  RewriteEngine on 
  RewriteRule .* index.php 
  php_flag magic_quotes_gpc off 
  php_flag register_globals off 

   
       熟悉apache的URL Rewrite技术的读者,很容易理解它的意义:将所有的请求转发到index.php。当然,对于图片之类的静态文件的请求不需要被转发,这可以通过在 public目录下放置另一个.htaccess来覆盖上级目录的Rewrite规则。 

       (习惯在IIS下运行PHP的读者可能会问,Zend Framework是否可以在IIS下运行呢?由于IIS不支持基于. htaccess的URL Rewrite,因此Zend Framework无法简单地在IIS下运行。但是,由于IIS支持基于HttpModule的URL Rewrite,因此理论上经过某些修改,是有可能让Zend Framework在IIS下运行的。有兴趣的读者可以自行尝试。) 

       index.php的功能是将http请求转发到相关的控制器,另外,它还需要完成一些初始化时期的配置工作。它的内容如下: 
   
Html代码   收藏代码
  1. <?php  
  2. error_reporting(E_ALL|E_STRICT);  
  3. date_default_timezone_set('Europe/London');  
  4. set_include_path('.' . PATH_SEPARATOR . './library'  
  5. . PATH_SEPARATOR . './application/models/'  
  6. . PATH_SEPARATOR . get_include_path());  
  7. include "Zend/Loader.php";  
  8. Zend_Loader::loadClass('Zend_Controller_Front');  
  9. // setup controller  
  10. $frontController = Zend_Controller_Front::getInstance();  
  11. $frontController->throwExceptions(true);  
  12. $frontController->setControllerDirectory('./application/controllers');  
  13. // run!  
  14. $frontController->dispatch();  
  15. ?>  

   
       开始的几行,分别用于配置报错等级、设置时区、设置包含文件路径,以及载入相关文件。Zend_Loader::loadClass是一个静态方法,用于装载指定的类。在载入Zend_Controller_Front以后,程序建立了这个类的实例,通知它抛出所有的异常,并且设置了控制器所在的目录。最后,调用dispatch()方法,将http请求转发到相应的控制器。 

       在application/controllers目录下,存放着所有的控制器类。那么路由器是根据什么规则寻找相应的控制器呢?很简单,它按照一定的命名规范来进行匹配。下面是一个控制器文件的内容: 
   
root/application/controllers/IndexController.php 
   
Html代码   收藏代码
  1.   <?php  
  2. class IndexController extends Zend_Controller_Action {  
  3.   function indexAction() {  
  4.     echo "<p>in IndexController::indexAction()</p>";  
  5.   }  
  6.   function addAction() {  
  7.     echo "<p>in IndexController::addAction()</p>";  
  8.   }  
  9.   function editAction() {  
  10.     echo "<p>in IndexController::editAction()</p>";  
  11.   }  
  12.   function deleteAction() {  
  13.     echo "<p>in IndexController::deleteAction()</p>";  
  14.   }  
  15. }  
   
       所有的控制器类都派生自Zend_Controller_Action。控制器名字必须大写字母开头,其他字母必须都为小写,最后加上 Controller结尾,并且存放在同名的php文件中。本例中的控制器是IndexController。(需要指出的是,“其他字母必须都为小写” 是一条很诡异的规则,这意味着CurrentUserController这样的名字是不合法的,无法被正确地路由。如果你这样做了,会是个很难发现的 bug。) 

       控制器拥有一个或多个行为(action),体现在代码上,行为是控制器类拥有的public方法,以小写字母开头,以Action结尾。在本例中,indexAction、deleteAction、addAction和editAction是IndexController的四个行为。 

       在浏览器中,可以通过“控制器/行为”的URL,来访问相应的行为。如上例,URL和行为的对应关系是: 
   
  URL Action 
  http://localhost/root/          IndexController::indexAction() 
  http://localhost/root/index    IndexController::indexAction() 
  http://localhost/root/index/add  IndexController::addAction() 
  http://localhost/root/index/edit IndexController::editAction() 
  http://localhost/root/index/delete IndexController::deleteAction() 
   
       可以看到,indexAction是一个控制器的缺省行为:如果没有指定行为,路由器将把请求转发到indexAction方法。同样,IndexController是缺省的控制器:如果没有指定控制器,路由器将把请求转发到IndexController控制器。 

       在上例中,行为方法直接输出一行代码作为响应。在规范的应用中,与显示相关的代码应该存放在视图中。一个规范的控制器行为方法内容如下: 
   
Html代码   收藏代码
  1. function indexAction() {  
  2.   $view = new Zend_View();  
  3.   $view->setScriptPath('./application/views/scripts’);  
  4.   $view->title = "Hello world";  
  5.   echo $view->render();  
  6. }  
   
       首先,创建了一个视图类(Zend_View)的实例,然后设置其路径,并对它的title属性赋值,最后调用render()方法,渲染相应的模板文件,将结果返回给浏览器。 

       同样的,视图根据特定的命名规范来匹配相应的模板文件。对于IndexController::indexAction()方法,视图会查找如下模板文件:root/application/views/scripts/index/index.phtml。后缀名为.phtml的模板文件事实上就是一个标准的PHP文件。(熟悉.rhtml后缀名的读者有何感觉?)在本例中,index.phtml的内容如下: 
Html代码   收藏代码
  1. <html>  
  2.   <head>  
  3.     <title><?php echo $this->escape($this->title); ?></title>  
  4.   </head>  
  5.   <body>  
  6.     <h1><?php echo $this->escape($this->title); ?></h1>  
  7.   </body>  
  8. </html>  

      最后,我们终于又一次看到了亲切的“Hello world”。 
       Zend Framework使用Zend_Db_Table来实现类似于ActiveRecord的ORM功能。和任何ORM一样,首先需要为它配置数据库的相关信息(服务器,用户名,密码,数据库名,等等)。虽然这并不复杂,但本文不拟讨论这些细节问题。(Zend Framework在它的Roadmap中计划支持YAML!)一旦配置完成后,可以在/application/models子目录下创建和数据库表相对应的模型类。 
       举例来说,在数据库中存在表user,结构如下: 
   
Sql代码   收藏代码
  1. CREATE TABLE user (  
  2.   id int(11) NOT NULL auto_increment,  
  3.   name varchar(100) NOT NULL,  
  4.   password varchar(100) NOT NULL,  
  5.   PRIMARY KEY (id)  
  6. )  

   
       相应地,可以在models目录下创建一个模型:root/application/models/User.php 
   
Html代码   收藏代码
  1. <?php  
  2.   class User extends Zend_Db_Table {  
  3.     protected $_name = 'user';  
  4.   }  
   
       所有数据库相关的代码,都已经被封装在抽象类Zend_Db_Table中。有ROR经验的读者,可以和ROR中的模型对比一下: 
  
  Class User < ActiveRecord::Base 
  End 
   
       Zend Framework的模型仅仅多出了一行,就是把数据库表名赋予$_name属性。 
       下面来看看怎么使用这个User模型类。新的indexAction方法如下: 
   
Html代码   收藏代码
  1. function indexAction() {  
  2. …  
  3. $user = new User();  
  4. $view->user = $user->fetchAll();  
  5. echo $view->render();  
  6. }  


       User类的fetchAll()返回一个数组,包含该表中所有的内容。这个数组被存放在$view的user属性。接下来,看看新的index.phtml: 
Html代码   收藏代码
  1.  …  
  2. <table>  
  3.  <tr>  
  4.    <th>Id</th>  
  5.    <th>Name</th>  
  6.  </tr>  
  7.  <?php foreach($this->user as $user) : ?>  
  8.    <tr>  
  9.      <td><?php echo $this->escape($user->id);?></td>  
  10.      <td><?php echo $this->escape($user->name);?></td>  
  11.    </tr>  
  12.   <?php endforeach; ?>  
  13. </table>  
  14.  …  
   
       这段代码遍历了$this->user,并将它的属性依次打印出来。 
       除了基本的MVC模型以外,Zend Framework还提供了一系列高级功能,下面是一个不全面的列表: 
   
    1.Zend_Acl(access control list):实现了非常灵活的权限控制机制,通过对特定的角色和资源进行规则定义,可以方便地实现各种复杂的权限控制规则,并且权限可以按照角色的树型结构实现继承。 
    2.Zend_Cache:提供了一种通用的数据缓存方式,可以将任何数据缓存到文件系统、数据库、内存,能够与Memcached和SQLite这样的第三方软件很好地集成。 
    3.Zend_Log:提供了一种通用的log解决方案,支持多个log后端,支持log信息格式化,支持信息过滤。 
    4.Zend_Pdf:完全用PHP语言实现的PDF文件操作引擎。 
    5.Zend_Feed:封装了对RSS和ATOM的操作。 
    6.Zend_Gdata:封装了对Google Data API的操作。 
    7.Zend_Json:JSON是AJAX中必不可少的数据格式。Zend_Json封装了数据在PHP和JSON格式之间的转换操作。 
    8.Zend_Rest:REST是越来越流行的Web Service协议,有逐渐凌驾传统的SOAP协议之势。Zend_Rest封装了对REST的操作,可以方便地实现REST的客户端或服务端应用。 
    9.Zend_Search_Lucene:封装了对著名的全文检索引擎Lucene的操作。 
   
       Zend Framework在7月份发布1.0正式版,现在最新的版本为1.0.2。可以说,Zend Framework还是一个非常新的事物。但是在它漫长的测试期间,已经有不少人在尝试,甚至用于正式的项目,因为它的种种功能实在太让人馋涎欲滴了。 

       回到本文开头的两个问题,Zend Framework的前途将会如何呢?虽然作者深知揣测未来的风险,但是还是很愿意尝试回答这两个问题:第一,Zend Framework的出现,已经证明了PHP 5有能力实现大型的、复杂的框架,而由于PHP的编译器掌握在Zend公司手中,能够保证PHP语言会持续发展,以满足进一步的需求。第二,PHP本来就已经在逐步进入企业开发的领域,出现一个重量级的Framework是必然的事情。也许PHP未来的开发主力,将由经过短期培训的、偏向快速解决问题的初级程序员,变为经验丰富的、熟悉各种复杂的IT平台、侧重应用的安全性和健壮性的资深工程师。毕竟,只要经过不懈的努力,脚本小子也可能有成为大师的一天,对吗? 
  至于Zend Framework和ROR之间的竞争,现在没有人能够给出答案。也许到目前为止,Zend Framework还无法达到ROR 100%的生产力,但是它拥有更广大的用户基础,更成熟的语言,更短的学习曲线,类似C和Java的语法也更让人容易掌握。ROR中的DRY、“惯例重于配置”等原则,在Zend Framework中也得了很好的秉承和发扬。无论它是否能够有效地狙击ROR,毫无疑问的是,一旦Zend Framework被PHP社群广泛接受,PHP的生产力将会有极大的提高。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值