文档章节

PHP沉思录-第四篇-Zend Framework-左轻侯-《程序员》2007年12月号

一配
 一配
发布于 2015/10/16 18:25
字数 3726
阅读 34
收藏 0
PHP

本文发表于《程序员》杂志2007年第12期,略有删节。    
  PHP沉思录之四:Zend Framework 
  左轻侯 
  2007.11.11 
   
   从理论上来说,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请求转发到相关的控制器,另外,它还需要完成一些初始化时期的配置工作。它的内容如下: 
   
  <?php 
  error_reporting(E_ALL|E_STRICT); 
  date_default_timezone_set('Europe/London'); 
  set_include_path('.' . PATH_SEPARATOR . './library' 
  . PATH_SEPARATOR . './application/models/' 
  . PATH_SEPARATOR . get_include_path()); 
  include "Zend/Loader.php"; 
  Zend_Loader::loadClass('Zend_Controller_Front'); 
  // setup controller 
  $frontController = Zend_Controller_Front::getInstance(); 
  $frontController->throwExceptions(true); 
  $frontController->setControllerDirectory('./application/controllers'); 
  // run! 
  $frontController->dispatch(); 
  ?> 
   
   开始的几行,分别用于配置报错等级、设置时区、设置包含文件路径,以及载入相关文件。Zend_Loader::loadClass是一个静态方法,用于装载指定的类。在载入Zend_Controller_Front以后,程序建立了这个类的实例,通知它抛出所有的异常,并且设置了控制器所在的目录。最后,调用dispatch()方法,将http请求转发到相应的控制器。 
  在application/controllers目录下,存放着所有的控制器类。那么路由器是根据什么规则寻找相应的控制器呢?很简单,它按照一定的命名规范来进行匹配。下面是一个控制器文件的内容: 
   
  root/application/controllers/IndexController.php 
   
  <?php 
  class IndexController extends Zend_Controller_Action { 
  function indexAction() { 
  echo "<p>in IndexController::indexAction()</p>"; 
  } 
  function addAction() { 
  echo "<p>in IndexController::addAction()</p>"; 
  } 
  function editAction() { 
  echo "<p>in IndexController::editAction()</p>"; 
  } 
  function deleteAction() { 
  echo "<p>in IndexController::deleteAction()</p>"; 
  } 
  } 
   
   所有的控制器类都派生自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控制器。 
   在上例中,行为方法直接输出一行代码作为响应。在规范的应用中,与显示相关的代码应该存放在视图中。一个规范的控制器行为方法内容如下: 
   
  function indexAction() { 
  $view = new Zend_View(); 
  $view->setScriptPath('./application/views/scripts’); 
  $view->title = "Hello world"; 
  echo $view->render(); 
  } 
   
   首先,创建了一个视图类(Zend_View)的实例,然后设置其路径,并对它的title属性赋值,最后调用render()方法,渲染相应的模板文件,将结果返回给浏览器。 
   同样的,视图根据特定的命名规范来匹配相应的模板文件。对于IndexController::indexAction()方法,视图会查找如下模板文件:root/application/views/scripts/index/index.phtml。后缀名为.phtml的模板文件事实上就是一个标准的PHP文件。(熟悉.rhtml后缀名的读者有何感觉?)在本例中,index.phtml的内容如下: 
   
  <html> 
  <head> 
  <title><?php echo $this->escape($this->title); ?></title> 
  </head> 
  <body> 
  <h1><?php echo $this->escape($this->title); ?></h1> 
  </body> 
  </html> 
   
   最后,我们终于又一次看到了亲切的“Hello world”。 
  Zend Framework使用Zend_Db_Table来实现类似于ActiveRecord的ORM功能。和任何ORM一样,首先需要为它配置数据库的相关信息(服务器,用户名,密码,数据库名,等等)。虽然这并不复杂,但本文不拟讨论这些细节问题。(Zend Framework在它的Roadmap中计划支持YAML!)一旦配置完成后,可以在/application/models子目录下创建和数据库表相对应的模型类。
  举例来说,在数据库中存在表user,结构如下: 
   
  CREATE TABLE user ( 
  id int(11) NOT NULL auto_increment, 
  name varchar(100) NOT NULL, 
  password varchar(100) NOT NULL, 
  PRIMARY KEY (id) 
  ) 
   
   相应地,可以在models目录下创建一个模型: 
   
  root/application/models/User.php 
   
  <?php 
  class User extends Zend_Db_Table 
  { 
  protected $_name = 'user'; 
  } 
   
   所有数据库相关的代码,都已经被封装在抽象类Zend_Db_Table中。有ROR经验的读者,可以和ROR中的模型对比一下: 
   
  Class User < ActiveRecord::Base 
  End 
   
   Zend Framework的模型仅仅多出了一行,就是把数据库表名赋予$_name属性。 
   下面来看看怎么使用这个User模型类。新的indexAction方法如下: 
   
  function indexAction() { 
  … 
  $user = new User(); 
  $view->user = $user->fetchAll(); 
  echo $view->render(); 
  } 
   
   User类的fetchAll()返回一个数组,包含该表中所有的内容。这个数组被存放在$view的user属性。接下来,看看新的index.phtml: 
   
  … 
  <table> 
  <tr> 
  <th>Id</th> 
  <th>Name</th> 
  </tr> 
  <?php foreach($this->user as $user) : ?> 
  <tr> 
  <td><?php echo $this->escape($user->id);?></td> 
  <td><?php echo $this->escape($user->name);?></td> 
  </tr> 
  <?php endforeach; ?> 
  </table> 
  … 
   
   这段代码遍历了$this->user,并将它的属性依次打印出来。 
   除了基本的MVC模型以外,Zend Framework还提供了一系列高级功能,下面是一个不全面的列表: 
   
   Zend_Acl(access control list):实现了非常灵活的权限控制机制,通过对特定的角色和资源进行规则定义,可以方便地实现各种复杂的权限控制规则,并且权限可以按照角色的树型结构实现继承。 
   Zend_Cache:提供了一种通用的数据缓存方式,可以将任何数据缓存到文件系统、数据库、内存,能够与Memcached和SQLite这样的第三方软件很好地集成。 
   Zend_Log:提供了一种通用的log解决方案,支持多个log后端,支持log信息格式化,支持信息过滤。 
   Zend_Pdf:完全用PHP语言实现的PDF文件操作引擎。 
   Zend_Feed:封装了对RSS和ATOM的操作。 
   Zend_Gdata:封装了对Google Data API的操作。 
   Zend_Json:JSON是AJAX中必不可少的数据格式。Zend_Json封装了数据在PHP和JSON格式之间的转换操作。 
   Zend_Rest:REST是越来越流行的Web Service协议,有逐渐凌驾传统的SOAP协议之势。Zend_Rest封装了对REST的操作,可以方便地实现REST的客户端或服务端应用。 
   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的生产力将会有极大的提高。 

本文转载自:http://www.bloggern.com/2584.html

一配
粉丝 35
博文 146
码字总数 117133
作品 0
西城
私信 提问
PHP沉思录-第六篇-Drupal的性能问题-左轻侯-《程序员》2008年11月号

创建时间:2008-11-09 01:12:51 最后修改时间:2008-11-09 01:12:51 本文发表在《程序员》杂志2008年第11期 PHP沉思录之六:Drupal的性能问题 左轻侯 Drupal是一个基于PHP的开源CMS系统,也是...

一配
2015/10/16
89
1
PHP沉思录-第三篇-Smarty-左轻侯-《程序员》2007年10月号

创建时间:2007-10-31 21:23:11 最后修改时间:2007-10-31 21:23:11 PHP沉思录之三:Smarty   左轻侯   2007.8.11       在任何Web应用中,如何将程序代码和界面设计,或者说,将逻辑...

一配
2015/10/16
29
0
PHP沉思录-第二篇-PME模型-左轻侯-《程序员》2007年7月号

本文发表在《程序员》第7期 PHP沉思录之二 左轻侯 PME模型 在大规模的程序设计中,组件(component)已经成为一种非常流行的技术。常见的组件技术都基于PME模型,即属性(Property)、方法(...

一配
2015/10/16
36
0
PHP沉思录-第一篇-工作模型与数据库访问接口-左轻侯-《程序员》2007年5月号

PHP沉思录 作者:左轻侯 创建时间:2007-05-10 09:47:29 最后修改时间:2010-12-31 23:19:57 本文发表于《程序员》5月号   是一个系列的第一篇,目前想到的其他一些主题是:      SQL...

一配
2015/10/16
30
0
最基础的数据结构-左轻侯

作者:左轻侯 创建时间:2007-03-04 22:29:06 最后修改时间:2008-01-18 22:07:52 本文发表于《程序员》2007年第3期      最基础的数据结构   左轻侯   2007.2.3      引言   ...

一配
2015/10/16
47
0

没有更多内容

加载失败,请刷新页面

加载更多

最简单的获取相机拍照的图片

  import android.content.Intent;import android.graphics.Bitmap;import android.os.Bundle;import android.os.Environment;import android.provider.MediaStore;import andr......

MrLins
28分钟前
4
0
说好不哭!数据可视化深度干货,前端开发下一个涨薪点在这里~

随着互联网在各行各业的影响不断深入,数据规模越来越大,各企业也越来越重视数据的价值。作为一家专业的数据智能公司,个推从消息推送服务起家,经过多年的持续耕耘,积累沉淀了海量数据,在...

个推
29分钟前
7
0
第三方支付-返回与回调注意事项

不管是支付宝,微信,还是其它第三方支付,第四方支付,支付机构服务商只要涉及到钱的交易都要进行如下校验,全部成功了才视为成功订单 1.http请求是否成功 2.校验商户号 3.校验订单号及状态...

Shingfi
32分钟前
4
0
简述Java内存分配和回收策略以及Minor GC 和 Major GC(Full GC)

内存分配: 1. 栈区:栈可分为Java虚拟机和本地方法栈 2. 堆区:堆被所有线程共享,在虚拟机启动时创建,是唯一的目的是存放对象实例,是gc的主要区域。通常可分为两个区块年轻代和年老代。更...

DustinChan
38分钟前
6
0
Excel插入批注:可在批注插入文字、形状、图片

1.批注一直显示:审阅选项卡-------->勾选显示批注选项: 2.插入批注快捷键:Shift+F2 组合键 3.在批注中插入图片:鼠标右键点击批注框的小圆点【重点不可以在批注文本框内点击】----->调出批...

东方墨天
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部