ZendChina | Zend中文权威资讯's Archiver

ZendChina 发表于 2007-12-25 20:23

Zend Framework体验

       这是个Framework的时代,写Java程序现在基本上就是和各种Framework打交道了。PHP以简单灵活著称,很多PHPer认为Java太重,见到Framework就烦。但随着项目的扩大,特别是PHP从擅长的中小型网站开发向所谓的“企业应用”发展,有一个良好的Framework支撑,无益对多人的团队开发还是有很多好处的。

       这回要说的是Zend公司推出的Zend Framework(下面简称ZF),网址是[url=http://framework.zend.com/]http://framework.zend.com/[/url],目前的版本是Preview 0.1.2,还不清楚正式版释放的计划。本文最初发表于我的blog [url=http://blog.csdn.net/Aryang/]http://blog.csdn.net/Aryang/[/url],转载请注明出处。

       先说说安装条件,ZF要求基于PHP5,还有需要Apache mod_rewrite的支持,没有考证这个是否是Apache的内置模块,我是通过加参数--enable-rewrite重新编译了Apache。

       下一步就是指定rewrite的规则,有很多方法,我用的是.htaccess文件的方法。在web根目录,也就是index.php所在的目录创建文件.htaccess(注意.开头的文件在unix下默认是隐藏的)。文件的内容如下
[php]
RewriteEngine on
RewriteOptions Inherit
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule  (.*) index.php?apache_path=$1 [L,QSA]
[/php]
       要使.htaccess生效,在httpd.conf里对web目录的配置也有要求,
[php]
Options FollowSymLinks
AllowOverride All
[/php]
加上这个。
       当然rewrite的规则有很多种写法,网上还有一种写法是:
[php]
RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php
[/php]
       本人也对这个也没研究,大概意思就是URL里文件类型除(js|ico|gif|jpg|png|css)以外的都改写成index.php,瞎猜的,有懂的朋友可以讲讲这两种的区别。

       然后就是下载ZF了,我的习惯是把在php.ini里include_path加上ZF/library目录,这样整个网站就可以很方便的访问ZF的库了。

       这里要说说rewrite的作用了。ZF彻底封装了URL的格式,基本上看不到.php的影子了。ZF的App的根目录里只有一个index.php, rewrite会把所有的URL请求改写成对index.php的调用。index.php相当于是个Dispatch,里面会创建一个Zend_Controller_Front对象,它作为一个代理把HTTP请求传递给(dispatch)相应的你写好的Controller。
       然后看网上的Tutorial,找到个例子,改了改,如下
[php]
<?php
//index.php
include 'Zend.php'; //我是已经加入了include_path,没加的写全路径
Zend::loadClass('Zend_Controller_Action');
Zend::loadClass('Zend_Controller_Front');
Zend::loadClass('Zend_InputFilter');
Zend::loadClass('Zend_View');
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory('./controllers');
/*
//数据库调用,可以先不加
require_once 'Zend/Db.php';
$params = array (
    'database' => 'mydb',
    'username' => 'myname',
    'password' => 'mypass'
);
$db = Zend_Db::factory('Oracle', $params);
Zend::register('db', $db); //全局对象注册,很好的方式
*/
$view = new Zend_View;
$view->setScriptPath('./views');
Zend::register('view', $view);
$controller->dispatch();
?>
[/php]
       如果你的调用是 [url=http://test.com/]http://test.com/[/url] ,Apache的设置里这个的实际调用 [url=http://test.com/index.php]http://test.com/index.php[/url],那么这个ZF会去找你写的IndexController.php(xxxController.php的位置通过在index.php里Zend_Controller_Front对象的setControllerDirectory方法指定),调用里面的类IndexController的IndexAction方法(我搜了很多介绍ZF的文章都说是index方法,看ZF源代码才发现应该是IndexAction,不知道是什么原因,估计是版本变动的原因)。
[php]
class IndexController extends Zend_Controller_Action
{
    function indexAction()
    {
        echo "这是首页";
    }
    function noRouteAction()
    {
        echo  "您所请求的页面不存在!";
    }
}
[/php]
       如果你曾经的程序有个"[url=http://test.com/book.php]http://test.com/book.php[/url]"来显示图书的相关页面,那么在ZF里的做法是写个bookController.php,在里面定义bookController类。"[url=http://test.com/book/]http://test.com/book/[/url]"会调用bookController类的IndexAction方法。传统的 "[url=http://test.com/book.php?action=edit&book_id=888]http://test.com/book.php?action=edit&book_id=888[/url]" 如何实现呢?在bookController类里定义“"editAction"方法,URL调用的写法是"[url=http://test.com/book/edit/book_id/888]http://test.com/book/edit/book_id/888[/url]",格式就是 [url=http://host/controller_name/method_name/param1/value1/param2/value2/]http://host/controller_name/method_name/param1/value1/param2/value2/[/url]...在editAction方法里可以通过 $this->_getParam("param1") 获得参数,或通过$this->_getAllParams()获得全部的参数。
[php]
class bookController extends Zend_Controller_Action
{
    function indexAction()
    {
        echo "hi, this is my book";
    }
    function editAction()
    {
        $book_id = $this->_getParam("book_id");
        echo "book id:".$book_id;
    }  
}
[/php]
       这样的话大家可以看到现在写程序方式就是实现一些类,ZF会对URL做解析,然后调用并传递参数。
所谓"Framework"都是这样的,它调用你,不是你调用它。

       目前感觉严重不爽的就是应用必须是网站的根目录,实际一个网站有多个应用的话,我们一般就是把每个应用放在不同的目录下。行动,在ZF的邮件列表里发现老外对这个也有意见,很多人做了处理。看到了这个网站 [url=http://kpumuk.info/php/zend-framework-router-for-subdirectory-based-site/]http://kpumuk.info/php/zend-framework-router-for-subdirectory-based-site/[/url] 里面实现了对App存放子目录的处理,大概就是自己写了个Router,替换掉ZF里的Router。但这个网站提供的代码在ZF 0.1.2里运行有问题,估计他是在0.1.0的时候写的。我做了相应修改:
[php]
<?php
/** Zend_Controller_Router_Interface */
require_once 'Zend/Controller/Router/Interface.php';
/** Zend_Controller_Dispatcher_Interface */
require_once 'Zend/Controller/Dispatcher/Interface.php';
/** Zend_Controller_Router_Exception */
require_once 'Zend/Controller/Router/Exception.php';
/** Zend_Controller_Dispatcher_Action */
require_once 'Zend/Controller/Dispatcher/Interface.php';
class Zend_Controller_SubDirectoryRouter implements Zend_Controller_Router_Interface
{
  public function route(Zend_Controller_Dispatcher_Interface $dispatcher)
  {
    // SubDirectoryRouter: what's the path to where we are?
    $pathIndex = dirname($_SERVER['SCRIPT_NAME']);
    // SubDirectoryRouter: remove $pathIndex from $_SERVER['REQUEST_URI']
    $path = str_replace($pathIndex, '', $_SERVER['REQUEST_URI']);
    if (strstr($path, '?')) {
      $path = substr($path, 0, strpos($path, '?'));
    }
    $path = explode('/', trim($path, '/'));
    /**
     * The controller is always the first piece of the URI, and
     * the action is always the second:
     *
     * [url=http://zend.com/controller-name/action-name/]http://zend.com/controller-name/action-name/[/url]
     */
    $controller = $path[0];
    $action     = isset($path[1]) ? $path[1] : null;
    /**
     * If no controller has been set, IndexController::index()
     * will be used.
     */
    if (!strlen($controller)) {
      $controller = 'index';
      $action = 'index';
    }
    /**
     * Any optional parameters after the action are stored in
     * an array of key/value pairs:
     *
     * [url=http://www.zend.com/controller-name/action-name/param-1/3/param-2/7]http://www.zend.com/controller-name/action-name/param-1/3/param-2/7[/url]
     *
     * $params = array(2) {
     *              ["param-1"]=> string(1) "3"
     *              ["param-2"]=> string(1) "7"
     * }
     */
    $params = array();
    for ($i=2; $i<sizeof($path); $i=$i+2) {
      $params[$path[$i]] = isset($path[$i+1]) ? $path[$i+1] : null;
    }
    $actionObj = new Zend_Controller_Dispatcher_Token($controller, $action, $params);
    if (!$dispatcher->isDispatchable($actionObj)) {
      /**
       * @todo error handling for 404's
       */
      throw new Zend_Controller_Router_Exception('Request could not be mapped to a route.');
    } else {
      return $actionObj;
    }
  }
}
?>
[/php]
       文件命名SubDirectoryRouter.php,保存于ZF/library/Zend/Controller/,然后修改index.php在$controller->dispatch(); 之前加入如下:
Zend::loadClass('Zend_Controller_SubDirectoryRouter');
$router = new Zend_Controller_SubDirectoryRouter();
$controller->setRouter($router);
这样就可以把我们的应用置于网站某子目录下了。ZF里有很多内容,这是我刚接触了解到的,如有新的体验,再和诸位一起探讨(wdy)。

[color=#ff0000]文章转载自:[/color][url=http://www.phpchina.com/][color=#ff0000]PHPChina开源社区门户[/color][/url]

页: [1]

Powered by Discuz! Archiver 6.1.0  © 2001-2007 Comsenz Inc.