Posts Tagged ‘1050’

PHP 的 ORM 持久层框架解决方案

星期一, 07月 26th, 2010

    1、Propel
    Propel是一个适用于PHP5的OR映射(Object Relational Mapping)框架,它基于Apache Torque提供对象持久层支持。它通过XML格式的模式定义文件和相应的配置文件来生成SQL和类,它允许你使用对象代替SQL来读写数据库表中的记录。Propel提供一个生成器来为你的数据模型创建SQL定义文件和PHP类。开发者也可以十分简单的定制生成的类,还可以通过XML, PHP类和Phing构建工具把Propel集成到已有的应用开发框架中去。例如PHP框架symfony的1.2以前的版本就是使用了精简版的Propel作为默认ORM框架。
    官方网站:http://www.propelorm.org/

    2、Doctrine
    Doctrine是一个PHP的ORM框架,它必须运行在php5.2.3以后版本,它是一个功能强大的数据抽象层。它的一个主要特征就是使用面向对象的方式来实现数据库查询的封装,它底层通过一个类似 Hibernate HQL的DQL的查询语句进行数据库查询, 这使得开发的灵活性更强,大大减小了重复代码。相比Propel,Doctrine的优点在于它支持全文检索,Doctrine的文档一直就比Propel要全面丰富,社区更活跃,而且使用起来更自然、易阅读、更接近原生SQL。性能方面也略微优于Propel。同样你也可以可以很方便的把 Doctrine集成到现有的应用框架中去,比如PHP框架symfony的1.3以后的版本将Doctrine作为默认的ORM框架,同时也可以将Doctrine和Codeigniter整合起来。
    官方网站: http://www.doctrine-project.org/

    3、EZPDO
    EZPDO是一个十分轻量级的PHP ORM框架。EZPDO的作者的本意旨在降低复杂的ORM学习曲线,尽可能在ORM的运行效率和功能之间做一个平衡,它是我至今用过的最简单的ORM框架,我目前还想将它集成到我的Light Framework SDK中来,而且运行效率相当不错,功能也基本能满足需求,只不过ESPDO的更新比较缓慢。
    官方网站: http://www.ezpdo.net/blog/?p=2

    4、RedBean
    RedBean是一个易于使用,轻量级PHP ORM框架,提供对 MySQL、SQLite 和PostgreSQL的支持。RedBean架构非常灵活,核心也非常简约,开发者可以很方便的通过插件来扩展功能。
    官方网站:http://www.redbeanphp.com/

    5、其他
    国内的fleaphp开发框架基于TableDataGateway实现ORM;Zend Framework除了提供对SQL 语句的封装以外,也同样实现了TableGateway、TableRowSet、TableRow的实现;还有一些类似Rails的ActiveRecord实现的解决方案。更多ORM框架请阅:http://www.oschina.net/project/tag/126

    总结:

    总的来说,一般ORM框架对付简单的应用系统来说都能满足需求,可以大大降低开发难度,提高开发效率。但是它在SQL优化方面,肯定是比纯SQL语言要差很多,对复杂关联、SQL内嵌表达式的处理都不是很理想。也许这主要是由于PHP本身对象持久化的问题,导致ORM效率过低,普遍比纯SQL要慢10~50倍。但是,这些都是有办法解决的,最基本的解决性能的方案,可以通过缓存来提高效率。比如,Hibernate虽然配置比较繁杂,但是它通过灵活的使用二级缓存和查询缓存,来极大地缓解数据库的查询压力,提升了系统的性能。Python的SQLAlchemy以及Django中的Models模型感觉上也都还不错,笔者认为Django 的Models 模型ORM 效率也还可以,至少比PHP要快。

高性能的PHP框架Yii 1.1.3发布

星期三, 07月 7th, 2010

    Yii 1.1.3版本发布,它是一套高性能,基于组件的PHP框架,Yii的特点是快速开发。此版本主要是对bug的修复和性能的修改,点击查看详细更新:
    http://www.yiiframework.com/files/CHANGELOG-1.1.3.txt

    Yii(读作“易”)代表简单(easy)、高效(efficient)、可扩展(extensible)。

    通过一个简单的命令行工具yiic可以快速创建一个Web应用程序的代码框架,开发者可以在生成的代码框架基础上添加业务逻辑,以快速完成应用程序的开发。

    点击下载:http://code.google.com/p/yii/downloads/list?can=1&q=1.1

    原文链接:http://www.javaeye.com/news/16750

    来源:互联网 2010-07-07

Sencha Touch:新的Touch Web App重量级框架

星期二, 07月 6th, 2010

    在几天前,著名的JavaScript框架ExtJS宣布,将现有ExtJS整合JQTouch和Rapha库,推出适用于最前沿Touch Web的Sencha Touch框架,该框架是世界上第一个基于HTML5的Mobile App框架。同时,ExtJS也正式更名为Sencha。原域名www.extjs.com也已经跳转至http://www.sencha.comlogo-sencha-sm.png

    同时,JQTouch的创始人David Kaneda,以及Rapha?l的创始人也已加盟Sencha团队。“在未来的几个月内,我们的合作将会创造出令人惊叹的新东西来。不会等太久的,我保 证!”Sencha的CEO Abraham Elias如是说。

    Sencha,翻译意为“煎茶”,是指一种在日本很流行的绿茶品种,“我们之所以选择这个名字,因为它会唤醒下一代软件开发并且它很容易记忆、拼写 和发音”,在Java开发的传统中,它代表了软件开发的一个新水平阶段。

    另外,Sencha还成立了一个基金会叫“Sencha Labs”,以支持非商业项目开发。jQTouch和Rapha?l将保留原有的MIT许可证。原JQTouch项目将由Jonathan Stark接 手维护和更新。

(more...)

开源 Python 开发框架 Django 1.1 发布

星期三, 08月 5th, 2009

    经过近一年的开发,有着许多全新特性和数千项改进的 Django 1.1 闪亮登场。

    Django是用Python语言写的开源web开发框架(open source web framework),它鼓励快速开发,并遵循MVC设计。Django遵守BSD版权,初次发布于2005年7月,并于2008年9月发布了第一个正式版本1.0。Django的主要目的是简便、快速的开发数据库驱动的网站。它强调代码复用,多个组件可以很方便的以插件形式服务于整个框架,Django 有许多功能强大的第三方插件,你甚至可以很方便的开发出自己的工具包。这使得Django具有很强的可扩展性。它还强调快速开发(RAD)和 DRY(Dont Repeat Yourself)原则。

    这次发布还包含了以往版本的安全更新。

    下载Django1.1:
    http://www.djangoproject.com/download

    Django1.1发布公告:
    http://docs.djangoproject.com/en/dev/releases/1.1

    (2009-8-05 信息来源: Internet)

开发者不可不知的PHP框架深度解析

星期二, 08月 4th, 2009

    PHP成为世界上最流行的脚本语言有许多原因:灵活性,易用性等等。但通常只用PHP或者其他语言编码就会显得单调、重复,这时候就需要一个PHP框架来代替程序员完成那些重复不变的部分。本文通过回答What, When, Why 以及 Which这些问题,将对PHP框架进行全面解析。

    PHP框架是什么?

    PHP框架提供了一个用以构建web应用的基本框架,从而简化了用PHP编写web应用程序的流程。换言之,PHP框架有助于促进快速应用开发( RAD ),不但节省开发时间、有助于建立更稳定的应用,而且减少了重复编码的开发。通过确保适当的数据库交换和在表现层编码,框架还可以帮助初学者建立更稳定的应用服务。这可以让你花更多的时间去创建实际的Web应用程序,而不是花时间写重复的代码。

    通常认为PHP框架的作用相当于模型-视图-控制器(Model View Controller)。MVC是种编程的架构模式,将业务逻辑从UI中分离出来,允许一个一个单独修改(也称为关注点分离)。在MVC中,Model指数据,View指表现层,Controller则指应用程序或业务逻辑。基本上, MVC打破了一个应用的开发进程,这样各组件就可以不受影响地各自工作。从本质上讲,这使得用PHP编码更快更简单。

    为什么要使用PHP框架?

    开发人员使用PHP框架的好处很多,其中之一是加快开发进程。在类似项目中重用代码将为开发者节省大量的时间和精力。框架为执行繁琐的代码任务提供预建模块,因此,开发人员可以把时间花在实际应用的开发上,而不是每一个项目都重新构建基础功能。

    稳定是开发者使用框架的另一个重要原因。虽然简单是PHP最大的优点,很多人也因为这一点喜欢使用这个脚本语言,但它同时也是PHP最大的缺点。一些开发者尤其是初学者很容易写出低劣的代码,而自己却没有意识到。使用PHP,应用往往会将静态工作加倍,不知不觉中您可能已经在编码时打开了一个大的安全漏洞,因此可能会受到攻击。重要的是要记住,PHP是一个非常宽容的语言,因此,更重要的是在编程时确保封闭任何漏洞,即便应用看起来可以正常工作。

    最后,PHP框架的使用是非常广泛的,而且有许多不同的框架可供选择。许多开发者会选择知名的框架,是因为它的知名度、其开发团队的巨大支持,而且他们可以通过论坛/社区来与其他使用相同框架的开发者交流,当然你也可以开发自己的框架。这里提醒一下,首先应该检查你的项目来决定是否应该使用一个框架。你应该问自己:它会节省你和其他使用者的时间和精力么?应用程序的性能会更好么?是否会提高稳定性?如果这些问题你的回答都是是,那么你就该为你的项目选择一个合适的框架了。

    何时使用PHP框架?

    这是一个无论有经验的开发者还是初级开发者都共有的问题,而且这个问题也确实没有直接的回答。对于许多初学者来说,一个框架将提供很多简便和稳定,因此应该尽可能地使用PHP框架。这将有助于减少或消除不良编码,加快开发进程。

    另一方面,许多有经验的PHP程序员将框架视为不知道如何写出好的、干净的代码的低级程序员的工具。姑且不论这一点的真假,起码毋庸置疑的是PHP框架是一个可以用来节省时间并强化自己编码的工具。

    当工作的项目时间紧迫时,使用PHP框架就有很多好处,可以大大加快编码进程,因此所以如果你时间紧迫,使用PHP框架就是很好的选择。另一个例子是,当你所做的项目有大量代码时,也应当考虑使用PHP框架,因为这将有助于减少工作的繁琐度。

    寻找一个什么样的PHP框架?

    有许多可供开发者选择的PHP框架,甚至还可以创建自己的框架,尽管只建议PHP专家级这样做。当寻找你最需要的PHP框架时,重要的是要搞清楚谁将自始至终使用或修改你的应用,如果是有很多人做这件事情,那么最好使用流行的PHP框架,这样大部分开发者都不会陌生。另一方面,如果你想构建Web应用程序为你个人使用,那就最好选择令你满意的PHP框架,而不在乎它在开发者社区中是否流行。

    选择PHP框架的参考因素有很多,包括:容易使用、快速开发、性能、开发者中的流行程度、强大的功能,技术支持、论坛等。当你第一次选择PHP框架时,为了找到一个适合你需求的最佳选择,建议多尝试几个。每个框架都有所不同,并有不同的长处和短处。例如Zend框架由于V3和多样的功能、并且有一个广泛的支持系统,因而它流行了这么久。相反, CakePHP是另一个晚于Zend框架的PHP框架,相应的支持系统也比较少,但更方便和易于使用。

    正如你所看到的,每种类型的PHP框架都有自己的优点,因此,最好反复试验以找出其中哪个最适合你的需要。另一个选择PHP框架的有效方式是咨询你的同事,看看开发社区里选择哪个。那些真正使用过具体框架的能够明确地告诉你它的易用性、功能、支持可用性、社区内的情况,当然可能还有不足。

    使用PHP框架最常见的错误

    任何类型的编程中都可能有错误,但是PHP框架有助于显著限制这些错误。重复编码似乎加剧了这种错误,而框架则解决了这一问题。尽管如此,在使用任何PHP框架时仍要注意。例如,除非你是一位PHP编程的专家,否则你应该总是选择使用流行的框架,有大量的支持和积极的用户群。很多框架的支持很少甚至没有,它们可能是被PHP知识有限的个别开发者所创建的。这些类型的框架,可能会使你的应用程序无法正常运行,更糟糕的是,可能会给你的网站带来灾难性的安全问题。

    另一些常见的错误是,不能确保你的数据库和Web服务器符合特定框架。例如,Seagull PHP Framework建议如下配置:

    * PHP :最低是PHP 4.3.0,PHP 5.1.1或者更高版本更佳,避免任何5.0.x版本中的东西;

    * MySQL的:支持MySQL的4.0.x,4.1.x和5.0.x,也可以使用3.23.x;

    * Apache:Seagull支持1.3.x以及Apache的2.x系列。

    如果你没有满足这些要求,您将无法在你所选的框架中看到最好的性能。即使你是PHP的专家,你也应该经常复习框架的说明文档,确认兼容性后再尝试。

    类似于前面提到的常见的错误,不遵循建议的安装进程的话,你的PHP框架也可以给你带来一些令人头疼的问题。以Seagull 为例,在Seagull的wiki有一个详细的框架安装过程,其中有几个关键步骤,很容易被不小心或不知情的开发者忽视。因此你要花费时间来安装框架并遵循安装说明。

    最好的PHP框架有哪些?

    过去的几年中,因为PHP已发展成为大多数开发者选择的脚本语言,因而也产生了大量的PHP框架。什么是最好的PHP框架,仁者见仁智者见智,因为并非每一个框架都能够适合每一个人。以下是5个最佳和最流行的PHP框架选择:

    Zend Framework在开发者社区中很有人气,其重点是Web 2.0风格的应用程序。由于其大量的党羽、广泛的支持和积极的用户群,Zend被称为PHP Company。Zend即使不是当今最流行的PHP框架,也绝对是之一。它强大的功能能够满足企业级的需求,当然它的使用也需要具备广泛的PHP知识。

    从初学者到高级PHP开发者,CakePHP都是一个很棒的选择。它与 Ruby on Rails设计的原则基本相同,主要集中在快速开发方面使其成为一个快速应用开发的优良框架。其迅速增长的支持系统、简单和可扩展性使CakePHP成为当今最热门的PHP框架。

    Symfony针对的更多的是高级开发者,也即创建企业级应用的开发者,尤其是Askeet和Yahoo! Bookmarks。这个开源的PHP框架功能全面,但它的主要缺点是速度慢于其他框架。

    CodeIgniter以其易用性、性能和速度而闻名。不同于Symfony,CodeIgniter主要针对的是与人共享主机的开发者,或者为小型设备寻找PHP框架的开发者。它提供简单的解决办法,而且有一个扩展库包括视频教程、论坛、用户指南和wiki。初学者应该考虑使用CodeIgniter 。

    Seagull是一个稳定的用于构建web、命令行和GUI应用的PHP框架。这是一个非常易于使用的框架,非常适合初学者到高级程序员。对于初学者,Seagull有一个范例应用库,可以自己设定后满足自身需求;对于高级开发者,Seagull提供了众多选择包括最佳实践、标准、模块化的代码基,这些都可以帮助快速简单地构建Web应用程序。Seagull有一个活跃的开发者社区,内有大量的支持性文档和说明。

    概括

    PHP框架为各种技术等级的开发者减少了重复编码的需求、加快了开发进程,并在创建web应用时确保正确的编码。这不仅加快了富应用开发的进程,同时也通过减少代码的安全漏洞而增强了PHP的安全性。

    虽然一些专家级PHP程序员觉得没有必要使用框架开发Web应用程序,但PHP框架仍然可以是快速开发的优秀解决方案,比如在工期很紧的情况下。从初级到中级开发者,框架可以提高PHP的学习,同时促进良好的代码编写和减少坏代码。

    今天有很多的PHP框架可用,因此开发者肯定能从中找到一个适合自己的框架:功能、支持、速度、可扩展性等。开发者广泛使用的一些顶尖的PHP开发框架包括: Zend Framework,CakePHP,Symfony,Codeigniter以及Seagull。

PHP框架Zend Framework1.8与云计算

星期二, 05月 12th, 2009

    PHP程序员将可以通过新的方法轻松地将其PHP应用程序与云联系起来,这要归功于开源Zend框架最新版本的出炉。
    Zend Framework1.8扩大了PHP框架以使其适应Amazon的EC2云计算服务。Zend框架还添加了新的应用程序开发功能以加速PHP的开发。
    Zend框架是PHP用以应对.NET,JavaEE和Ruby on Rails开发框架的工具。随着新版本的推出,Zend技术,这一PHP幕后商业资助者,正在大力扩充PHP的竞争力。而这次新版本的推出是继上个月该公司推出Zend Server PHP中间设备之后的又一举措。
    Zend技术创始人兼首席技术官Zeev Suraski说:“Zend 1.8的推出时间再合适不过了,因为不久前我们才推出了Zend Server,这两个工具会相辅相成的。现在我认为我们的用户真正意义上拥有了完整的堆栈。我们的Zend Studio 集成开发环境现在有了Zend Framework的支持,而且Zend Server还会在旁边起到辅助作用,这一切都为PHP的发展提供了良好的开发与部署条件。”
    Zend框架1.8版本的推出是今年以来对于该框架的首次更新。其1.7版本是在去年十一月份推出的,带有Adobe 动作信息格式的支持。
    Suraki解释称1.8版本中快速应用程序开发(RAD)的功能使得开发人员有能力快速地管理和修改应用程序。新的RAD工具有助于开发人员创建新项目和新控件,一般来说,他们可以开发出项目的各种代码骨架。
    Zend 框架中用于快速应用程序开发的新模块被称为Zend_application,它进一步加快了PHP的发展。Zend框架项目领导人Matt Weier O’Phinney透露,在需要自启动应用程序的时候,Zend_application可以有效地帮助程序员进行开发。而在1.8版本出来之前,程序员需要创建一个自启动脚本,在这一自启动脚本中包含了需要注入到框架对象中的各种资源。通过手动来完成这一操作是相当复杂的,而现在Zend_aaplication就可以为自启动程序建立标准化的方式。

    云技术支持
    Zend在推出1.8版本的框架后继而向云技术靠拢,它为Amazon的EC2服务和S3云存储产品都提供了相应支持。
    “在S3中,我们授予了程序员对几乎可无限扩展的Amazon存储服务器的访问权利,”Suraki解释说,“作为EC2的一个类别,我们赋予了程序员管理EC2实例的能力以方便他们创建,终止以及启动这些实例。”
    Suraki补充说,如果没有云技术的支持,程序员们将很难对使用Zend框架的Amazon的云基础设施进行利用。现在他声称,有了Zend框架就可以对Amazon存取进行程序化管理了。
    虽然Zend公司现在支持Amazon云,但是它现在还不能为谷歌的应用引擎提供支持。尽管在过去谷歌通过谷歌数据应用程序接口为Zend框架提供支持。Suraki和O’Phinney同时指出,现阶段还没有任何要求支持谷歌应用引擎的正式提议,不过O’Phinney称已经在这方面进行过一些初步的试验。谷歌推出的应用引擎支持Python语言,且最近已经开始测试其对Java的支持。
    另一个Zend 框架暂不能提供支持的是Oauth验证。Oauth标准现在正被众多网站实施和测试,这些网站都将其视为一种保护Web认证的简单方式。
    O’Phinney称,虽然Zend框架1.8版本还不支持Oauth验证,但是已经有提议要将其纳入进来了。因此在今年晚些时候,也就是1.9版本的框架中,就可以实现对Oauth的支持了。

    PHP 5.3和PHP 6
    虽然Zend Framework 1.8对于PHP程序员来说是向前迈出了重要异步,但是另一个指日可待的大跃进是PHP语言的更新版本即将推出,因为PHP5.3已经处于发布的候选阶段,PHP6也正在积极地发展。Suraski称,PHP5.3是一个重要进步,因为PHP6指日可待。PHP社区决定与其等着PHP6的敲定,不如在PHP5.3之前就 把PHP6的某些想法公布。
    这其中的一个性能就是命名空间,它是一种能简要概括类和PHP项目的途径。
    “一旦它推出,整个PHP社区都会收益。”Suraski说。至于PHP5.3什么时候出来,反而是个更难回答的问题。

走进Zend Framework框架编程(六):视图(3)

星期日, 11月 23rd, 2008

    6.9视图助手(Helper)
    视图脚本里经常有一些繁杂的事情,比如格式化日期、产生表单元素等等。这些可以用助手帮我们来完成。
    助手类其实是一些以Zend_View_Helper_开头的类,类名的最后一段是助手的名字,助手的名字必须是首字母大写的,该类必须至少有一个以助手名字命名的方法。助手名通常是驼峰式命名,即它不会是大写字母开头的。类名是混合大小写字格式。方法名也是驼峰式命名。
    默认的助手的路径通常指向Zend/View/Helper。即使用setHelperPath()方法重新指定了路径,该路径也会保持以使默认的助手能够工作。
    6.9.1ZF自带的助手
    示例代码:
    <?php
    echo $this->form('frm1', array('action'=>'action.php', 'method'=>'post'), false) ."\n";

    echo $this->formHidden('id', 'submited');

    $content = 'Your Name:' . $this->formText('name', '', array('size' => 20)) .'<br>';
    $content .= 'Password:' . $this->formPassword('pass', '', array('size' => 20));
    echo $this->fieldset('flst', $content, array('legend'=>'Name:', 'style'=>'width:200pt')) .'<br>';

    echo $this->formLabel('email', 'Your Email:');
    echo $this->formText('email', 'you@example.com', array('size' => 32)) .'<br>';

    echo 'Your Country:';
    echo $this->formSelect('country', 'us', null, $this->countries) .'<br>';

    echo 'Would you like to opt in?';
    echo $this->formCheckbox('opt_in', 'yes', null, array('yes', 'no')) .'<br>';

    echo 'Choose them:';
    echo $this->formMultiCheckbox('chkbox', 'A', null, array('A'=>'valA','B'=>'valB','C'=>'valC','D'=>'valD'), '<br>') .'<br>';

    echo 'Choose one:';
    echo $this->formRadio('radio', 'A', null, array('A'=>'valA','B'=>'valB','C'=>'valC','D'=>'valD'), '') .'<br>';

    echo $this->htmlList($this->countries) .'<br>';

    echo $this->url(array('k1'=>'v1','k2'=>'v2','k3'=>'v3')) .'<br>';

    echo $this->formTextarea('ta', '', array('rows'=>'5','cols'=>'25')) .'<br>';

    echo $this->formFile('file', '', array()) .'<br>';

    echo $this->formButton('btn', 'BUTTON', array('onClick'=>''));
    echo $this->formSubmit('OK', 'OK');
    echo $this->formReset('reset', 'Reset');
  ?>

    6.9.2动作(Action)助手
    允许我们在视图脚本里执行某个控制器里的动作方法。
    示例:
      <div id="sidebar right">
        <div class="item">
          <?= $this->action('assign1', 'Book'); ?>
        </div>
      </div>

    6.9.3区域(Partial)助手
    区域助手的基本用法是在它自己的视图范围内解析另一个模板的片段,类似视图脚本嵌套调用。
    区域助手的基本用法:
    示例:
    booklist.php文件包含脚本片段:
    <?php
      if ($this->books):
    ?>
      <table border=1>
      <tr>
        <th>作者</th>
        <th>书名</th>
      </tr>
      <?php
        foreach ($this->books as $key => $val):
      ?>
      <tr>
        <td><?php echo $this->escape($val['author']) ?></td>
        <td><?php echo $this->escape($val['title']) ?></td>
      </tr>
      <?php endforeach; ?>
      </table>
    <?php
      else:
    ?>
      <p>There are no books to display.</p>
    <?php
      endif;
    ?>
    在另一个视图脚本通过Partial助手调用booklist.php文件:
    <?= $this->partial('booklist.php', array(
      'books' => array(
          array('author'=>'zhangqing','title'=>'《book for php》'),
          array('author'=>'zhangking','title'=>'《book for JSP》'),
          array('author'=>'zhanghing','title'=>'《book for ASP.NET》'),
        )));
    ?>
    <?php echo str_repeat('-', 60). '<br>'; ?>
    <?php
      $model = array(
        array('key' => 'Mammal', 'value' => 'Camel'),
        array('key' => 'Bird', 'value' => 'Penguin'),
        array('key' => 'Reptile', 'value' => 'Asp'),
        array('key' => 'Fish', 'value' => 'Flounder'),
      );
    ?>
    <dl>
      <?= $this->partialLoop('partialLoop.phtml', $model) ?>
    </dl>

    使用 PartialLoop 来解析可迭代的(Iterable)的模型
    示例:
    <?php
      $model = array(
        array('key' => 'Mammal', 'value' => 'Camel'),
        array('key' => 'Bird', 'value' => 'Penguin'),
        array('key' => 'Reptile', 'value' => 'Asp'),
        array('key' => 'Fish', 'value' => 'Flounder'),
      );
    ?>
    <dl>
      <?= $this->partialLoop('partialLoop.phtml', $model) ?>
    </dl>
    以上代码中partialLoop 调用了以下partialLoop.phtml的内容:
      <dt><?= $this->key ?></dt>
      <dd><?= $this->value ?></dd>

    6.9.4占位(Placeholder)助手
    示例:
    <?= $this->doctype('XHTML1_STRICT') ?>
    <?php
    // setting meta keywords
    $this->headMeta()->appendName('keywords', 'framework php productivity');
    $this->headMeta()->appendHttpEquiv('expires', 'Wed, 26 Feb 1997 08:21:57 GMT')
                     ->appendHttpEquiv('pragma', 'no-cache')
                     ->appendHttpEquiv('Cache-Control', 'no-cache');
    $this->headMeta()->appendHttpEquiv('Content-Type', 'text/html; charset=UTF-8')
                     ->appendHttpEquiv('Content-Language', 'en-US');
    $this->headMeta()->appendHttpEquiv('Refresh', '3;URL=http://www.some.org/some.html');
    echo $this->headMeta();
    $this->headScript()->appendFile('/js/prototype.js')
                       ->appendScript('xx.js');
    // Putting scripts in order
    // place at a particular offset to ensure loaded last
    $this->headScript()->offsetSetScript(100, '/js/myfuncs.js');
    // use scriptaculous effects (append uses next index, 101)
    $this->headScript()->appendScript('/js/scriptaculous.js');
    // but always have base prototype script load first:
    $this->headScript()->prependScript('/js/prototype.js');
    echo $this->headScript();
    // setting links in a view script:
    $this->headLink()->appendStylesheet('/styles/basic.css')
                     ->headLink(array('rel' => 'favicon', 'href' => '/img/favicon.ico'), 'PREPEND')
                     ->prependStylesheet('/styles/moz.css', 'screen', true);
    // rendering the links:
    echo $this->headLink();
    ?>
    <?php
      $this->placeholder('foo')->setPrefix("<ul>\n<li>")
                               ->setSeparator("</li><li>\n")
                               ->setIndent(4)
                               ->setPostfix("</li></ul>\n");
      $this->placeholder('foo')->set("Some text for later-1");
      $this->placeholder('foo')->bar = "Some text for later-2";
      echo $this->placeholder('foo');

      $foo = $this->placeholder('foo');
      echo $foo[0] .'<br>';
      echo $foo['bar'] .'<br>';
    ?>
    <!-- Default capture: append -->
    <?php
      $this->placeholder('hoo')->captureStart();
      foreach ($this->data as $datum)
      {
    ?>
      <div class="hoo">
        <h2><?= $datum['title'] ?></h2>
        <p><?= $datum['content'] ?></p>
      </div>
    <?php
      }
      $this->placeholder('hoo')->captureEnd();
    ?>

    <?php
      echo $this->placeholder('hoo')
    ?>
    <!-- Capture to key -->
    <?php
      $this->placeholder('woo')->captureStart('SET', 'data');
      foreach ($this->data as $datum):
    ?>
      <div class="woo">
        <h2><?= $datum['title'] ?></h2>
        <p><?= $datum['content'] ?></p>
    </div>
    <?php
      endforeach;
      $this->placeholder('woo')->captureEnd();
    ?>

    <?php
      echo $this->placeholder('woo')->data;
    ?>
    6.9.4自定义助手
    编写及调用自定义助手的方法:
    The class name must, at the very minimum, end with the helper name itself, using MixedCaps. E.g., if you were writing a helper called "specialPurpose", the class name would minimally need to be "SpecialPurpose". You may, and should, give the class name a prefix, and it is recommended that you use 'View_Helper' as part of that prefix: "My_View_Helper_SpecialPurpose". (You will need to pass in the prefix, with or without the trailing underscore, to addHelperPath() or setHelperPath()).

    The class must have a public method that matches the helper name; this is the method that will be called when your template calls "$this->specialPurpose()". In our "specialPurpose" helper example, the required method declaration would be "public function specialPurpose()".

    In general, the class should not echo or print or otherwise generate output. Instead, it should return values to be printed or echoed. The returned values should be escaped appropriately.

    The class must be in a file named after the helper class. Again using our "specialPurpose" helper example, the file has to be named "SpecialPurpose.php".

    Place the helper class file somewhere in your helper path stack, and Zend_View will automatically load, instantiate, persist, and execute it for you.
    示例:
    <?php
      //Custom Helper "myFieldset"
      echo $this->myFieldset('This my custom Helper.').'<br>';
      echo $this->myFieldset('This my custom Helper.').'<br>';
      echo $this->myFieldset('This my custom Helper.').'<br>';
    ?>
    调用代码:
        function customhelperAction()
        {
          $view = new Zend_View();
          $view->setScriptPath('views');
          $view->setHelperPath('views/helpers', 'My_View_Helper');
          echo $view->render('my_custom_helper.php');
        }

走进Zend Framework框架编程(六):视图(2)

星期日, 11月 23rd, 2008

    6.6视图脚本的变量转义输出(escaping output)
    视图脚本得到变量以后,需要通过转义进行输出,变成页面可以显示的Html代码。
    输出语句的格式:
    echo $this->escape($this->variable);
    $variable变量是在视图脚本里用render方法传递过来的。
    一般情况下,传递的变量是通过PHP的 htmlspecialchars()函数转义的。而我们也可以实现我们自己的转义函数。请参考以上“使用回调函数”示例。

    6.7视图脚本的模板系统—操作PHPLib类型的模板
    模板系统进一步完美的实现了视图与程序逻辑的分离。视图脚本可以完美的操作PHPLib等类型的模板。
    6.7.1PHPlib的安装和调用
    为了测试下面的示例,我们必须安装PHPLib模板系统到我们的环境中。从网上下载到phplib-7.4.ZIP安装压缩包,解压到安装ZEND的library文件夹下,就完成了安装。
    为了在ZF的视图脚本里调用得到模板类文件,必须在引导文件Index.php的set_include_path部分添加PHPLib模板类库文件夹phplib-7.4/php到搜索路径中。以下示例同时包含了Smarty模板引擎的类库文件的搜索路径:
    set_include_path('.' .
      PATH_SEPARATOR . '../library/'.
      PATH_SEPARATOR . '../library/phplib-7.4/php/'.
      PATH_SEPARATOR . '../library/Smarty-2.6.19/libs/'.
      PATH_SEPARATOR . 'models/'.
      PATH_SEPARATOR . get_include_path()
    );
    注意,所有路径都是以引导文件所在文件夹作为参照的。尽管视图文件里所在文件夹不是引导文件所在根目录,但在视图文件里包含PHPLib类库文件的语句include_once 'template.inc';仍然是以引导文件所在目录作为参照的。

    6.7.2在视图文件里调用PHPLib模板
    首先包含PHPLib类库文件,然后声明模板类的一个实例。使用模板类,首先需要指定一些属性,比如指定模板所在路径,指定模板文件等,然后用set_var传递模板变量,最后用parse方法调用模板文件。PHPLib模板系统的详细用法请参考其帮助文档。
    示例:
    <?php
      include_once 'template.inc';
      $tpl = new Template();
      $tpl->set_root('views');

      if ($this->books)
      {
        $tpl->set_file(array(
            "booklist" => "booklist.tpl",
            "eachbook" => "eachbook.tpl",
        ));
        foreach ($this->books as $key => $val)
        {
          $tpl->set_var('author', $this->escape($val['author']));
          $tpl->set_var('title', $this->escape($val['title']));
          $tpl->parse("books", "eachbook", true);
        }
        $tpl->pparse("output", "booklist");
      }
      else
      {
        $tpl->setFile("nobooks", "nobooks.tpl");
        $tpl->pparse("output", "nobooks");
      }
    ?>
    booklist.tpl文件内容:
    <?php
      if ($this->books):
    ?>
      <table border=1>
      <tr>
        <th>作者</th>
        <th>书名</th>
      </tr>
      <?php
        foreach ($this->books as $key => $val):
      ?>
      <tr>
        <td><?php echo $this->escape($val['author']) ?></td>
        <td><?php echo $this->escape($val['title']) ?></td>
      </tr>
      <?php endforeach; ?>
      </table>
    <?php
      else:
    ?>
      <p>There are no books to display.</p>
    <?php
      endif;
    eachbook.tpl文件内容:
    <!-- eachbook.tpl -->
    <tr>
      <td>{author}</td>
      <td>{title}</td>
    </tr>

    6.8视图脚本的模板系统—使用 Zend_View_Interface调用第三方模板引擎
    我们还可以通过实现Zend_View_Interface接口,来得到一个可用的模板系统。
    ZF对Zend_View_Interface接口的原始定义:
    /** Return the actual template engine object */
    public function getEngine();

    /* Set the path to view scripts/templates */
    public function setScriptPath($path);

    /* Set a base path to all view resources */
    public function setBasePath($path, $prefix = 'Zend_View');

    /* Add an additional base path to view resources */
    public function addBasePath($path, $prefix = 'Zend_View');

    /* Retrieve the current script paths */
    public function getScriptPaths();

    /* Overloading methods for assigning template variables as object properties */
    public function __set($key, $value);
    public function __get($key);
    public function __isset($key);
    public function __unset($key);

    /* Manual assignment of template variables, or ability to assign multiple
      variables en masse.*/
    public function assign($spec, $value = null);

    /* Unset all assigned template variables */
    public function clearVars();

    /* Render the template named $name */
    public function render($name);
    使用该接口,我们可以很容易的把第三方的模板引擎,比如Smarty,包装成Zend_View兼容的模板类。
    6.8.1Smarty的安装
    下载Smarty软件包,解压到ZEND的library文件夹下,就完成了安装。
    为了在ZF的视图脚本里调用得到模板类文件,必须在引导文件Index.php的set_include_path部分添加Smarty模板类库文件夹Smarty-2.6.19/libs到搜索路径中,参看前面PHPlib的安装说明部分。
    Smarty模板引擎需要建立template_dir和compile_dir文件夹才能工作。ZF手册里的示例因为缺少这些设置而无法运行,正确的代码片段如下:
        public function setScriptPath($path)
        {
            if (is_readable($path))
    {
                $this->_smarty->template_dir = $path;
                $this->_smarty->compile_dir = $path;  //必须加语句:设置编译路径
                $this->_smarty->cache_dir = $path;    //设置缓存路径
    return;
             }
    ……
    我们把对Zend_View_Interface接口的实现的类,放在models文件夹下的ZendViewSmarty.php文件中,该文件的内容如下:
    <?php
    require_once 'Zend/View/Interface.php';
    require_once 'Smarty.class.php';

    class ZendViewSmarty implements Zend_View_Interface
    {
        /**
         * Smarty object
         * @var Smarty
         */
        protected $_smarty;

        /**
         * Constructor
         * @param string $tmplPath
         * @param array $extraParams
         * @return void
         */
        public function __construct($tmplPath = null, $extraParams = array())
        {
            $this->_smarty = new Smarty;

            if (null !== $tmplPath) {
                $this->setScriptPath($tmplPath);
            }

            foreach ($extraParams as $key => $value) {
                $this->_smarty->$key = $value;
            }
        }

        /**
         * Return the template engine object
         * @return Smarty
         */
        public function getEngine()
        {
            return $this->_smarty;
        }

        /**
         * Set the path to the templates
         * @param string $path The directory to set as the path.
         * @return void
         */
        public function setScriptPath($path)
        {
            if (is_readable($path)) {
                $this->_smarty->template_dir = $path;
                $this->_smarty->compile_dir = $path;
                $this->_smarty->cache_dir = $path;
                return;
            }
            throw new Exception('Invalid path provided');
        }

        /**
         * Retrieve the current template directory
         * @return string
         */
        public function getScriptPaths()
        {
            return array($this->_smarty->template_dir);
        }

        /**
         * Alias for setScriptPath
         * @param string $path
         * @param string $prefix Unused
         * @return void
         */
        public function setBasePath($path, $prefix = 'Zend_View')
        {
            return $this->setScriptPath($path);
        }

        /**
         * Alias for setScriptPath
         * @param string $path
         * @param string $prefix Unused
         * @return void
         */
        public function addBasePath($path, $prefix = 'Zend_View')
        {
            return $this->setScriptPath($path);
        }

        /**
         * Assign a variable to the template
         * @param string $key The variable name.
         * @param mixed $val The variable value.
         * @return void
         */
        public function __set($key, $val)
        {
            $this->_smarty->assign($key, $val);
        }

        /**
         * Retrieve an assigned variable
         * @param string $key The variable name.
         * @return mixed The variable value.
         */
        public function __get($key)
        {
            return $this->_smarty->get_template_vars($key);
        }

        /**
         * Allows testing with empty() and isset() to work
         * @param string $key
         * @return boolean
         */
        public function __isset($key)
        {
            return (null !== $this->_smarty->get_template_vars($key));
        }

        /**
         * Allows unset() on object properties to work
         * @param string $key
         * @return void
         */
        public function __unset($key)
        {
            $this->_smarty->clear_assign($key);
        }

        /**
         * Assign variables to the template
         * Allows setting a specific key to the specified value, OR passing an array
         * of key => value pairs to set en masse.
         * @see __set()
         * @param string|array $spec The assignment strategy to use (key or array of key
         * => value pairs)
         * @param mixed $value (Optional) If assigning a named variable, use this
         * as the value.
         * @return void
         */
        public function assign($spec, $value = null)
        {
            if (is_array($spec)) {
                $this->_smarty->assign($spec);
                return;
            }
            $this->_smarty->assign($spec, $value);
        }

        /**
         * Clear all assigned variables
         * Clears all variables assigned to Zend_View either via {@link assign()} or
         * property overloading ({@link __get()}/{@link __set()}).
         * @return void
         */
        public function clearVars()
        {
            $this->_smarty->clear_all_assign();
        }

        /**
         * Processes a template and returns the output.
         * @param string $name The template to process.
         * @return string The output.
         */
        public function render($name)
        {
            return $this->_smarty->fetch($name);
        }
    }
    ?>
    控制脚本中对我们我的模板类的调用代码:
       function smartyAction()
       {
          $view = new ZendViewSmarty(); //实例化新的模板类
          $view->setScriptPath('views'); //设置模板文件路径
          $view->book = 'Enter Zend Framework Programme'; //传递变量给模板引擎
          $view->author = '张庆(网眼)';
          echo $view->render('bookinfo.tpl'); //视图呈现
       }
    我们看到,由于Smarty模板引擎的良好特性,除过实现上述接口的代码比较复杂以外,我们这里的控制代码要比应用PHPLib模板简单得多。我们的数据不必像PHPLib引擎那样,要把数据传给视图脚本,再由视图脚本声明PHPLib类,再把数据发送给模板去呈现。这里是在控制脚本里把数据直接传递给Smarty模板去呈现的。这是因为ZendViewSmarty实现的是Zend_View接口,它和Zend_View的用法是一样的。

    注意:本例只是使用Smarty引擎的其中一种方法。在ZF中还可以用别的形式来使用Smarty模板引擎,我们会在别的章节里介绍。

走进Zend Framework框架编程(六):视图(1)

星期日, 11月 23rd, 2008

    本部分内容包括:视图,模板,视图帮助类等。

    6.0视图介绍
    在Zendframework的MVC编程模型中,视图(View)是在控制器的控制和指挥下,用来对程序逻辑进行呈现(Render)的。呈现的结果,就是我们在浏览器里看到的文字、图片、表单等各种网页元素及其字体、颜色、样式等各种效果。
    Zend_View Class就是负责视图工作的类,它有效地完成了视图与程序逻辑的分离。它提供了视图帮助、输出过滤和变量转义等功能。
    Zend_View还是一个模板系统,我们可以用PHP作为我们的模板语言。当然ZF还可以在View脚本里使用其他第三方的模板系统,比如PHPLib和Smarty等。
    使用Zend_View时主要分两步,首先声明一个Zend_View实例,把变量等赋给它,然后使用控制脚本,根据视图脚本呈现出结果。

    例如:

    控制脚本(在控制器文件的action里,例如IndexController.php中的函数dispdataAction()):
    ……
    Function dispdataAction()
    {
    ……
    $data = 'to view'; //数据变量
    Zend_Loader::loadClass('Zend_View');
    $view = new Zend_View(); //实例化
    $view->books = $data;  //赋值
    echo $view->render('view.php');
    }

    视图脚本转义输出语句(在视图脚本文件里,本例是view.php):
    <?
    php echo $this->escape($this->data
    ?>

    6.1引导文件中setParam('noViewRenderer', <bool>)语句的再解释
    Index文件中$fc->setParam('noViewRenderer', <bool>);语句和视图的某性特性有很大关系,比如视图存放的路径等一些默认属性都受该开关属性的影响。
    false 是noViewRenderer的默认值。也就是说,如果没有该语句,则认为noViewRenderer参数被设置为false。
    noViewRenderer参数被设置为false:意味着控制器使用ZF默认的视图特性,比如视图文件默认必须存放于views\script\<action>\文件夹下,视图文件必须存在,而且其名字必须为<action>.phtml。.phtml是ZF使用的PHP脚本文件,和普通PHP文件没有本质区别。同时,视图对象默认被实例化为$view变量,在控制脚本中使用$view的形式为:$this->view->…。
    noViewRenderer参数被设置为true:意味着控制器不使用ZF默认的视图特性,而是通过显式的实例化Zend_view对象,通过我们自己的代码来设置视图对象的属性和方法。本部分“视图介绍”中就是显式声明和使用视图对象的例子。为了程序的灵活性和可控行,我们自然建议把noViewRenderer 设置为 true,这也是比较通常的做法。

    6.2视图对象的Options
    视图对象的Options选项进一步规定了视图脚本呈现过程中的一些细节。这些选项可以通过在声明视图对象时指定,在构造函数里设置,也可以通过set……()方法来指定。
    —basePath基本路径
    设置方法:setBasePath(), addBasePath()
    例如目录结构:
    base/path/
          helpers/
          filters/
          scripts/
         用$view->setBasePath(”base/ path/”);语句设置基本路径后,在没有$view->setScriptPath('……');语句直接指定脚本路径时,就会自动在base/path/scripts/下搜索视图脚本文件,如果使用了视图助手和过滤器,就会分别自动在helpers/和 filters/文件夹下搜索。

    —encoding字符编码
    用来在使用htmlentities()、htmlspecialchars()或其他操作时,指定字符编码。
    设置方法:setEncoding()
    默认编码是ISO-8859-1 (latin1)。

    —escape回调函数
    用于在视图呈现时调用该函数。后边有示例。
    设置方法:setEscape()

    —filter过滤器
    用于在视图呈现后调用过滤方法。
    设置方法:setFilter(), addFilter(),

    —strictVars
    当视图视图发送一个未初始化的变量时,用该选项指定ZF收购给出一个提示或警告信息:
    Notice: Key "xxx" does not exist ……
    设置方法:strictVars(true)

    6.3视图对象的一些属性存取方法
    —getVars() 得到所有赋予的变量
    —clearVars()清除所有赋予的变量
    —getScriptPath($script) 得到给定脚本的路径
    —getScriptPaths()得到所有脚本的路径
    —getHelperPath($helper)得到某个指定助手类的路径
    —getHelperPaths()得到所有助手的路径
    —getFilterPath($filter) 得到某个指定过滤器类的路径
    —getFilterPaths()得到所有过滤器的路径

    6.4视图的路径:
    6.4.1视图脚本的搜寻路径
    如果引导文件中$fc->setParam('noViewRenderer', false);
    则默认指定视图文件views/scripts/[controller_name]/[action].phtml
    在实际的程序代码中,为了获得可定制的灵活性,都在控制器中实际指定了视图文件的路径:
    指定路径例句:$view->setScriptPath('…/views');或
    $view->addScriptPath('…/views');
    这个时候,引导文件必须有$fc->setParam('noViewRenderer', true);语句,即设置noViewRenderer为true。
    6.4.2视图脚本的搜寻的优先顺序
    $view = new Zend_View();
    $view->addtScriptPath('…/views1');
    $view->addScriptPath('…/views2');
    $view->addScriptPath('…/views3');
    Zend的手册是这样说的:“如果没有指定任何搜素路径,则在控制器文件下搜索视图文件。”但是通过实际环境测试,发现这时会报告错误:
    “no view script directory set; unable to determine location for view script”
    看起来最少需要指定一个搜索路径。
    如果指定了多条搜素路径,则最后的搜索路径优先。也就是说,如果所有的搜索路径下有相同的视图文件,则最后路径下的起作用,它覆盖了前边路径下的视图文件。

    6.5视图控制脚本及其变量传递
    ZF的控制器是实例化和设置Zend_View的地方。在这里,我们给视图赋值并告诉它用指定的视图脚本去呈现它们。
    6.5.1给视图对象赋值
    示例:
    $view->Variable=”……”;的形式
        function assign1Action()
        {
          $view = new Zend_View();
          $view->setScriptPath('views');
          $view->strictVars(true);
          $view->a = "Hay";
          $view->b = "Bee";
          $view->c = "Sea";
          $view->d;
          echo $view->render('tp_abc.php');
       }
    示例:
    $view-> assign(' Variable ', "……");的形式
        function assign2Action()
        {
          $view = new Zend_View();
          $view->setScriptPath('views');
          $view->assign('a', "Hay");
          $view->assign('b', "Bee");
          $view->assign('c', "Sea");
          echo $view->render('tp_abc.php');
       }
    示例:数组
       function assign3Action()
        {
          $view = new Zend_View();
          $view->setScriptPath('views');
          $array = array(
            'a' => "Hay",
            'b' => "Bee",
            'c' => "Sea",
          );
          $view->assign($array);
          echo $view->render('tp_abc.php');
       }
    示例:对象
        function assign4Action()
        {
          $view = new Zend_View();
          $view->setScriptPath('views');
          $obj = new StdClass;
          $obj->a = "Hay";
          $obj->b = "Bee";
          $obj->c = "Sea";
          $view->assign((array) $obj);
          echo $view->render('tp_abc.php');
       }
    示例:
        使用回调函数。
        function myhtmlentityAction()
        {
          $view = new Zend_View();
          $view->setScriptPath('views');
    //自定义类,在/models文件夹下的myclass.php文件中定义
          $mycls = new myClass();
    //调用$mycls类的myHtmlEntity方法
          $view->setEscape(array($mycls, 'myHtmlEntity'));

          $obj = new StdClass;
          $obj->a = "the words hay bee sea ";
          $obj->b = "this is bee";
          $obj->c = " this is sea";
          $view->assign((array) $obj);
          echo $view->render('tp_abc.php');
       }
    tp_abc.php视图脚本模板文件内容:
    <?php
      echo 'a = ' . $this->escape($this->a).'<br>';
      echo 'b = ' . $this->escape($this->b).'<br>';
      echo 'c = ' . $this->escape($this->c).'<br>';
    ?>
    myclass.php文件内容:
    <?php
      class myClass
      {
        public function __construct($options = null)
        {
        }
        function myHtmlEntity($val)
        {//把所有单词首字母变为大写
          return ucwords($val);
        }
      }
    ?>
    输出结果:
    a = The Words Hay Bee Sea
    b = This Is Bee
    c = This Is Sea

走进Zend Framework框架编程(五):Zend_Controller进阶

星期日, 11月 23rd, 2008

    在前边的例子中,我们的index.php引导文件所在的文件夹与控制器、视图等所在的文件夹是不同的,这并不符合一般网站项目的文件夹的组织习惯。从本部分开始,我们把他们放在同一个文件夹中,这是因为ZF提供了灵活的文件夹组织和配置能力。
    我们新的文件夹结构如下:
     …/htdocs
       library
         Zend
       Phpchina2.com
         controllers
         models
         views
         index.php
         .htaccess
    即把原来app_phpchina1.com文件夹下的子文件夹Controllers、models、views转移到文件夹phpchina1.com下,与index.php和.htaccess文件放在一起。为了不覆盖原来的代码,我们把原来的phpchina1.com文件夹拷贝一份,命名为phpchina2.com。
    为了测试,我们建立一个新的虚拟主机phpchina2.com。这可以仿照前面的phpchina1.com来完成,即在httpd.conf中添加:
    <VirtualHost *:8080>
        ServerAdmin any@any.com
        DocumentRoot "C:/Program Files/Apache Software Foundation/Apache2.2/htdocs/phpchina2.com"
        ServerName phpchina2.com
        ErrorLog "logs/phpchina2.com-error.log"
        CustomLog "logs/phpchina2.com-access.log" common
    </VirtualHost>
    重新启动Apache服务。
    然后再在hosts文件中加一条
    <服务器IP>      phpchina1.com
    以后即可以以http://phpchina2.com:8080/*.*的形式访问新的网站。但现在暂时还不能像前边的例子一样运行原来的示例代码,因为还需要对index.php里的路径配置进行调整。
    我们把语句PATH_SEPARATOR . '../App_phpchina1.com/models/'修改为:
    PATH_SEPARATOR . 'models/'
    把语句"default"=>'../app_phpchina1.com/controllers'修改为:
    "default"=>'controllers'

    然后用浏览器打开地址http://phpchina2.com:8080,就可以看到和原来一样,显示了字符串“Hello PHPChina1.com!”。也可以打开http://phpchina2.com:8080/news显示“Welcome to News!”字符串。

    下一步我们对Controllers进行扩展改造。比如我们有这样的需求:如果一个网站项目很大,有多个模块,Controllers文件夹下将有大量的控制器文件,我们打算通过按模块建立子文件夹对其进行分类存放,IndexController.php控制器文件存放在index文件夹下,news控制器文件存放在news文件夹下。
    首先修改index.php文件,把
      $fc->setControllerDirectory(array(
          "default"=>'controllers',
        ));
    处的"default"=>'controllers'修改为
    "default"=>'controllers/index'
    这时http://phpchina2.com:8080地址就可以打开了,显示结果与原来相同。
    但要访问news文件夹下的NewsController.php控制器,必须把news添加到搜索路径,并为其命名,我们这里命名为other模块,这样我们就添加以下语句:
    $fc->addControllerDirectory('controllers/news', 'other');
    然后打开地址http://phpchina2.com:8080/news,看不到原来的结果。
    再打开地址http://phpchina2.com:8080/otherhttp://phpchina2.com:8080/other/news,也看不到原来的结果。
    原来,需要修改NewsController.php中的语句
    Class NewsController extends Zend_Controller_Action为
    class other_NewsController extends Zend_Controller_Action
    即在类名前加“other_”字符串。然后访问地址
    http://phpchina2.com:8080/other/news
    即可得到正确的结果。
    这里有一个新问题,即http://phpchina2.com:8080/other/news和index默认文件夹的
    OtherController控制器中的newsAction方法访问路径是相同的,如果index文件夹下同时还有文件OtherController.php,内容为:
    <?php
    class OtherController extends Zend_Controller_Action
    {
      function newsAction()
      {
        echo "This is OtherController.php ==> newAction";
      }
    }
    ?>
    那么http://phpchina2.com:8080/other/news会不会显示
    This is OtherController.php ==> newAction
    字符串的结果呢?不会的,因为按模块搜索访问方式优先。有了other搜素路径名,就不能再访问默认文件夹下的other控制器中的任何方法了,即使搜素路径下没有任何对应的控制器文件,也不能访问。即,即使没有news文件夹下的NewsController.php文件,http://phpchina2.com:8080/other/news也不会获得index文件夹下OtherController.php中newsAction方法的结果。
    这里的搜素路径和Web服务器的虚拟路径有点相似。但是因为可以用代码指定,所以更灵活一些。后面,我们根据这一点可以灵活的组织网站项目的文件夹结构。
    我们对前边ZF中请求URL的格式做一些补充,原URL格式
    http://host_name/controller_name/action_name/param1/ value1/param2/ value2…
    可以扩展为:
    http://host_name/路径/controller_name/action_name/param1/ value1/param2/ value2…
    路径名需要作为“路径名_”字符串的形式加在
    代码“Class controller_name”的实现代码的前边,成为“Class路径名_controller_name”的形式。明白了这点,在分析ZF的源代码的时候,就不会被路径问题所迷惑了。