程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> ThinkPHP、ZF2、Yaf、Laravel框架路由大比拼

ThinkPHP、ZF2、Yaf、Laravel框架路由大比拼

編輯:PHP綜合

前言

讀過一篇關於Zend Framework2的技術文章《ZF2多級樹形路由Route配置實例》,是介紹路由配置的。我覺得很有意思,這是的需求:

/user對應用戶列表頁面
/user/:user_id對應用戶的個人主頁,比如 /user/AlloVince 就對應AlloVince用戶的個人主頁
/user/:user_id/blog/對應用戶的博客列表頁面,比如 /user/AlloVince/blog 就會列出AlloVince寫過的Blog
/user/:user_id/blog/:blog_id對應用戶的一篇博客文章
方案引用自原文:

'router' => array(
  'routes' => array(
    'user' => array(
      'type' => 'Segment',
      'options' => array(
        'route' => '/user[/]',
        'defaults' => array(
          'controller' => 'UserController',
          'action' => 'index',
        ),
      ),
      'may_terminate' => true,
      'child_routes' => array(
        'profile' => array(
          'type' => 'Segment',
          'options' => array(
            'route' => '[:id][/]',
            'constraints' => array(
              'id' => '[a-zA-Z0-9_-]+'
            ),
            'defaults' => array(
              'action' => 'get'
            ),
          ),
          'may_terminate' => true,
          'child_routes' => array(
            'blog' => array(
              'type' => 'Segment',
              'options' => array(
                'route' => 'blog[/]',
                'constraints' => array(
                ),
                'defaults' => array(
                  'action' => 'blog'
                )
              ),
              'may_terminate' => true,
              'child_routes' => array(
                'post' => array(
                  'type' => 'Segment',
                  'options' => array(
                    'route' => '[:post_id][/]',
                    'constraints' => array(
                      'post_id' => '[a-zA-Z0-9_-]+'
                    ),
                    'defaults' => array(
                      'action' => 'post'
                    )
                  ),
                  'may_terminate' => true,
                ),
              ),
            ),
          ), //profile child_routes end
        ), //profile end
      ), //user child_routes end
    ), //user end
  ),
),

看了這篇文章後,我打算使用我用過的PHP框架來實現這個路由需求。

ThinkPHP

新建一個ThinkPHP項目:

復制代碼 代碼如下:
composer create-project topthink/thinkphp tp --prefer-dist

命令行顯示我安裝的是3.2.2

Installing topthink/thinkphp (3.2.2)
我看ThinkPHP官網最新穩定版本是3.2.3。

我特意去packagist官網查了一下,庫中穩定版確實是3.2.2。

我得使用3.2.3。為什麼我特別糾結這一點哩?因為:

3.2的路由功能是針對模塊設置的,所以URL中的模塊名不能被路由,路由定義也通常是放在模塊配置文件中。 3.2.3版本開始增加全局路由定義支持,可以在項目的公共配置文件中定義路由。
也就是說,路由重寫的部分是Controller和Action部分,Moudle還是存在。

我希望的是/user,而不是home/user。(ThinkPHP中默認Module是Home,'DEFAULT_MODULE' => 'Home',可以修改)

當然,這個問題也可以修改.htaccess文件的解決。但是,我還是決定安裝3.2.3。

在ThinkPHP官網下載最新的包,解壓。

使用浏覽器訪問一下項目的入口文件,讓ThinkPHP自動生成了一個默認的應用模塊Home。

修改公共配置文件tp\Application\Common\Conf\config.php:

<?php
return array(
  // 開啟路由
  'URL_ROUTER_ON' => true,
  // URL訪問模式,可選參數0、1、2、3,代表以下四種模式:
  // 0 (普通模式); 1 (PATHINFO 模式); 2 (REWRITE 模式); 3 (兼容模式) 默認為PATHINFO 模式
  'URL_MODEL' => 2,
  // URL偽靜態後綴設置,為空表示可以支持所有的靜態後綴
  // 使用U函數生成URL時會不帶後綴
  'URL_HTML_SUFFIX' => '',
  // URL變量綁定到Action方法參數,默認為true
  'URL_PARAMS_BIND' => true,
  // URL變量綁定的類型 0 按變量名綁定 1 按變量順序綁定,默認為0
  'URL_PARAMS_BIND_TYPE' => 0,
  // 路由配置
  'URL_ROUTE_RULES' => array(
    '/^url$/' => 'Home/User/url',
    '/^user$/' => 'Home/User/index',
    '/^user\/([a-zA-Z0-9_-]+)$/' => 'Home/User/show?name=:1',
    '/^user\/([a-zA-Z0-9_-]+)\/blog$/' => 'Home/Blog/index?name=:1',
    '/^user\/([a-zA-Z0-9_-]+)\/blog\/([0-9]+)$/' => 'Home/Blog/show?name=:1&blog_id=:2',
  ),
);
?>

創建文件tp\Application\Home\Controller\UserController.class.php:

<?php
namespace Home\Controller;
use Think\Controller;
class UserController extends Controller {
  public function url() {
    $name = 'jing';
    $blogId = 1;
    $urls = array(
      U('/user'),
      U("/user/{$name}"),
      U("/user/{$name}/blog"),
      U("/user/{$name}/blog/{$blogId}"),
    );
    foreach ($urls as $url) {
      echo "<a href=\"{$url}\">{$url}<a/><br />\n";
    }
  }
  public function index() {
    echo '我是用戶列表^_^';
  }
  public function show($name) {
    echo "歡迎你,{$name}";
  }
}
?>

創建文件tp\Application\Home\Controller\BlogController.class.php:

<?php
namespace Home\Controller;
use Think\Controller;
class BlogController extends Controller {
  public function index($name) {
    echo "這是{$name}的博客列表";
  }
  public function show($blog_id, $name) {
    echo "{$name}的這篇博客的id為{$blog_id}";
  }
}
?>

訪問:http://127.0.0.1/tp/url

輸出:

復制代碼 代碼如下:
<a href="/tp/user">/tp/user<a/><br />
<a href="/tp/user/jing">/tp/user/jing<a/><br />
<a href="/tp/user/jing/blog">/tp/user/jing/blog<a/><br />
<a href="/tp/user/jing/blog/1">/tp/user/jing/blog/1<a/><br />

訪問上面4個鏈接,依次返回:

我是用戶列表^_^
歡迎你,jing
這是jing的博客列表
jing的這篇博客的id為1
下面其他框架,也同樣輸出以上內容。

Zend Framework 2

使用ZF2骨架程序創建一個ZF2項目:

composer create-project --stability="dev" zendframework/skeleton-application zf2

修改默認模塊Application的配置文件zf2\module\Application\config\module.config.php:

<?php
/**
 * Zend Framework (http://framework.zend.com/)
 *
 * @link   http://github.com/zendframework/ZendSkeletonApplication for the canonical source repository
 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
 * @license  http://framework.zend.com/license/new-bsd New BSD License
 */
return array(
  'router' => array(
    'routes' => array(
      'home' => array(
        'type' => 'Zend\Mvc\Router\Http\Literal',
        'options' => array(
          'route' => '/url',
          'defaults' => array(
            'controller' => 'Application\Controller\User',
            'action' => 'url',
          ),
        ),
      ),
      // The following is a route to simplify getting started creating
      // new controllers and actions without needing to create a new
      // module. Simply drop new controllers in, and you can access them
      // using the path /application/:controller/:action
      'application' => array(
        'type' => 'Literal',
        'options' => array(
          'route' => '/application',
          'defaults' => array(
            '__NAMESPACE__' => 'Application\Controller',
            'controller' => 'Index',
            'action' => 'index',
          ),
        ),
        'may_terminate' => true,
        'child_routes' => array(
          'default' => array(
            'type' => 'Segment',
            'options' => array(
              'route' => '/[:controller[/:action]]',
              'constraints' => array(
                'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
              ),
              'defaults' => array(
              ),
            ),
          ),
        ),
      ),
      'user_list' => array(
        'type' => 'Segment',
        'options' => array(
          'route' => '/user[/]',
          'defaults' => array(
            '__NAMESPACE__' => 'Application\Controller',
            'controller' => 'User',
            'action' => 'index',
          ),
        ),
        'may_terminate' => true,
        'child_routes' => array(
          'user' => array(
            'type' => 'Segment',
            'options' => array(
              'route' => '[:name][/]',
              'constraints' => array(
                'name' => '[a-zA-Z0-9_-]+',
              ),
              'defaults' => array(
                'action' => 'show',
              ),
            ),
            'may_terminate' => true,
            'child_routes' => array(
              'blog_list' => array(
                'type' => 'Segment',
                'options' => array(
                  'route' => 'blog[/]',
                  'constraints' => array(
                  ),
                  'defaults' => array(
                    'controller' => 'Blog',
                    'action' => 'index',
                  )
                ),
                'may_terminate' => true,
                'child_routes' => array(
                  'blog' => array(
                    'type' => 'Segment',
                    'options' => array(
                      'route' => '[:blog_id]',
                      'constraints' => array(
                        'blog_id' => '[0-9]+',
                      ),
                      'defaults' => array(
                        'action' => 'show',
                      )
                    ),
                    'may_terminate' => true,
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    ),
  ),
  'service_manager' => array(
    'abstract_factories' => array(
      'Zend\Cache\Service\StorageCacheAbstractServiceFactory',
      'Zend\Log\LoggerAbstractServiceFactory',
    ),
    'aliases' => array(
      'translator' => 'MvcTranslator',
    ),
  ),
  'translator' => array(
    'locale' => 'en_US',
    'translation_file_patterns' => array(
      array(
        'type' => 'gettext',
        'base_dir' => __DIR__ . '/../language',
        'pattern' => '%s.mo',
      ),
    ),
  ),
  'controllers' => array(
    'invokables' => array(
      'Application\Controller\Index' => 'Application\Controller\IndexController',
      'Application\Controller\User' => 'Application\Controller\UserController',
      'Application\Controller\Blog' => 'Application\Controller\BlogController',
    ),
  ),
  'view_manager' => array(
    'display_not_found_reason' => true,
    'display_exceptions' => true,
    'doctype' => 'HTML5',
    'not_found_template' => 'error/404',
    'exception_template' => 'error/index',
    'template_map' => array(
      'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
      'application/index/index' => __DIR__ . '/../view/application/index/index.phtml',
      'error/404' => __DIR__ . '/../view/error/404.phtml',
      'error/index' => __DIR__ . '/../view/error/index.phtml',
    ),
    'template_path_stack' => array(
      __DIR__ . '/../view',
    ),
  ),
  // Placeholder for console routes
  'console' => array(
    'router' => array(
      'routes' => array(
      ),
    ),
  ),
);
?>

這個文件是骨架程序中自帶的,我只是修改了router部分和controllers部分。要我寫這麼長的文件,那就太為難我了。這也是ZF官方發布了一個骨架程序的原因。

創建文件zf2\module\Application\src\Application\Controller\UserController.php:

<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class UserController extends AbstractActionController {
  public function urlAction() {
    $name = 'jing';
    $blogId = 1;
    $urls = array(
      $this->url()->fromRoute('user_list'),
      $this->url()->fromRoute('user_list/user', array('name' => $name)),
      $this->url()->fromRoute('user_list/user/blog_list', array('name' => $name)),
      $this->url()->fromRoute('user_list/user/blog_list/blog', array('name' => $name, 'blog_id' => $blogId)),
    );
    $view = new ViewModel(compact('urls'));
    $view->setTerminal(true);
    return $view;
  }
  public function indexAction() {
    $view = new ViewModel();
    // 禁用布局模板
    $view->setTerminal(true);
    return $view;
  }
  public function showAction() {
    $username = $this->params()->fromRoute('name');
    $view = new ViewModel(compact('username'));
    $view->setTerminal(true);
    return $view;
  }
}
?>

創建文件zf2\module\Application\src\Application\Controller\BlogController.php:

<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class BlogController extends AbstractActionController {
  public function indexAction() {
    $username = $this->params()->fromRoute('name');
    $view = new ViewModel(compact('username'));
    $view->setTerminal(true);
    return $view;
  }
  public function showAction() {
    $username = $this->params()->fromRoute('name');
    $blogId = $this->params()->fromRoute('blog_id');
    $view = new ViewModel(compact('username', 'blogId'));
    $view->setTerminal(true);
    return $view;
  }
}
?>

zf2不支持Action參數綁定,ThinkPHP不僅支持綁定,還支持2種綁定方式:按變量名綁定和按變量順序綁定。

zf2中Action必須得返回視圖,除非exit()。如果你知道可以禁用視圖的辦法,請告訴我。

創建文件zf2\module\Application\view\application\user\url.phtml:

<?php foreach ($urls as $url): ?>
<a href="<?php echo $url;?>"><?php echo $url;?><a/><br />
<?php endforeach; ?>

創建文件zf2\module\Application\view\application\user\index.phtml:

我是用戶列表^_^
創建文件zf2\module\Application\view\application\user\show.phtml:

歡迎你,<?php echo $username; ?>
創建文件zf2\module\Application\view\application\blog\index.phtml:

這是<?php echo $username; ?>的博客列表
創建文件zf2\module\Application\view\application\blog\show.phtml:

復制代碼 代碼如下:
<?php echo $username; ?>的這篇博客的id為<?php echo $blogId; ?>

Yaf

安裝Yaf

使用代碼生成工具創建Yaf項目

修改啟動文件yaf\application\Bootstrap.php,修改其中的_initRoute方法:

    $router = Yaf_Dispatcher::getInstance()->getRouter();
    $route0 = new Yaf_Route_Rewrite('url', array(
      'controller' => 'User',
      'action' => 'url',
        ), array()
    );
    $route1 = new Yaf_Route_Rewrite('user', array(
      'controller' => 'User',
      'action' => 'index',
        ), array()
    );
    $route2 = new Yaf_Route_Regex('#user/([a-zA-Z0-9_-]+)#', array(
      'controller' => 'User',
      'action' => 'show',
        ), array(1 => 'name',)
    );
    $route3 = new Yaf_Route_Regex('#user/([a-zA-Z0-9_-]+)/blog#', array(
      'controller' => 'Blog',
      'action' => 'index',
        ), array(1 => 'name',)
    );
    $route4 = new Yaf_Route_Regex('#user/([a-zA-Z0-9_-]+)/blog/([0-9]+)#', array(
      'controller' => 'Blog',
      'action' => 'show',
        ), array(1 => 'name', 2 => 'blogId',)
    );
    $router->addRoute('url', $route0);
    $router->addRoute('user_list', $route1);
    $router->addRoute('user', $route2);
    $router->addRoute("blog_list", $route3);
    $router->addRoute("blog", $route4);

Yaf有路由功能,但是沒有根據路由名生成URL的方法。所以我定義了一個項目名,用於拼接URL。

在配置文件中添加配置項yaf\conf\application.ini:

復制代碼 代碼如下:
project.name = 'yaf'

創建文件yaf\application\controllers\User.php:

<?php
class UserController extends Yaf_Controller_Abstract {
  public function urlAction() {
    $name = 'jing';
    $blogId = 1;
    $app = Yaf_Application::app();
    $projectName = $app->getConfig()->project->name;
    $urls = array(
      "/{$projectName}/user",
      "/{$projectName}/user/{$name}",
      "/{$projectName}/user/{$name}/blog",
      "/{$projectName}/user/{$name}/blog/{$blogId}",
    );
    foreach ($urls as $url) {
      echo "<a href=\"{$url}\">{$url}<a/><br />\n";
    }
    return false;
  }
  public function indexAction() {
    echo '我是用戶列表^_^';
    // 禁用視圖模板
    return false;
  }
  public function showAction($name) {
    echo "歡迎你,{$name}";
    return false;
  }
}

創建文件yaf\application\controllers\Blog.php:

復制代碼 代碼如下:
<?php
class BlogController extends Yaf_Controller_Abstract {
    public function indexAction($name) {
        echo "這是{$name}的博客列表";
        return false;
    }
    public function showAction($blogId, $name) {
        echo "{$name}的這篇博客的id為{$blogId}";
        return false;
    }
}

Yaf的Action支持參數綁定,是按變量名綁定的。$name、$blogId要和路由中配置的名稱一樣,而和參數順序無關。

Laravel

新建Laravel項目:

復制代碼 代碼如下:
composer create-project laravel/laravel --prefer-dist

清除合並文件。在目錄laravel\vendor\下有個文件compiled.php,這個文件是為了減少IO提高框架性能,將很多類文件合並到一個文件中而生存的。在開發環境下,應該刪除該文件,否則修改了一些文件發現沒有效果,其實是因為文件已經合並緩存了。
清除命令:

復制代碼 代碼如下:
php artisan clear-compiled

在生產環境中應該開啟,以提升性能:

復制代碼 代碼如下:
php artisan optimize --force

修改路由文件laravel\app\Http\routes.php:

復制代碼 代碼如下:
<?php
Route::get('/url', array('uses' => 'UserController@getUrl'));
Route::get('/user', array('uses' => 'UserController@getIndex'));
Route::get('/user/{username}', array('uses' => 'UserController@getShow'));
Route::get('/user/{username}/blog', array(
    'as' => 'blog_list',
    'uses' => 'BlogController@getIndex',
));
Route::get('/user/{username}/blog/{blogId}', array(
    'as' => 'blog',
    'uses' => 'BlogController@getShow',
))->where(array('blogId' => '[0-9]+'));

查看路由定義情況:

復制代碼 代碼如下:
php artisan route:list

輸出:

復制代碼 代碼如下:
+--------+----------+-------------------------------+-----------+----------------------------------------------+------------+
| Domain | Method   | URI                           | Name      | Action                                       | Middleware |
+--------+----------+-------------------------------+-----------+----------------------------------------------+------------+
|        | GET|HEAD | url                           |           | App\Http\Controllers\UserController@getUrl   |            |
|        | GET|HEAD | user                          |           | App\Http\Controllers\UserController@getIndex |            |
|        | GET|HEAD | user/{username}               |           | App\Http\Controllers\UserController@getShow  |            |
|        | GET|HEAD | user/{username}/blog          | blog_list | App\Http\Controllers\BlogController@getIndex |            |
|        | GET|HEAD | user/{username}/blog/{blogId} | blog      | App\Http\Controllers\BlogController@getShow  |            |
+--------+----------+-------------------------------+-----------+----------------------------------------------+------------+

定義路由變量全局模式,修改文件laravel\app\Providers\RouteServiceProvider.php中的boot方法:

復制代碼 代碼如下:
    public function boot(Router $router) {
        $router->pattern('username', '[a-zA-Z0-9_-]+');

        parent::boot($router);
    }

創建UserController控制器:

復制代碼 代碼如下:
php artisan make:controller UserController

Laravel幫我們在laravel\app\Http\Controllers目錄下創建了文件UserController.php,文件中已經為我們寫好一部分骨架代碼。修改文件laravel\app\Http\Controllers\UserController.php:

復制代碼 代碼如下:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
class UserController extends Controller {
    public function getUrl() {
        $name = 'jing';
        $blogId = 1;
        $urls = array(
            url('/user'),
            action('UserController@getShow', array($name)),
            route('blog_list', array($name)),
            route('blog', array($name, $blogId)),
        );
        foreach ($urls as $url) {
            echo "<a href=\"{$url}\">{$url}<a/><br />\n";
        }
    }
    public function getIndex() {
        echo '我是用戶列表^_^';
    }
    public function getShow($name) {
        echo "歡迎你,{$name}";
    }
}

創建BlogController控制器:

復制代碼 代碼如下:
php artisan make:controller BlogController

修改文件laravel\app\Http\Controllers\BlogController.php:

復制代碼 代碼如下:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
class BlogController extends Controller {
    public function getIndex($name) {
        echo "這是{$name}的博客列表";
    }
    public function getShow($name, $blogId) {
        echo "{$name}的這篇博客的id為{$blogId}";
    }
}

Laravel的Action也支持參數綁定,是按變量順序綁定的,和變量名無關。

後語

我是Laravel粉,但是我也沒有想黑其他框架的意思,大家有興趣也可以用自己熟悉的框架來實現這個小例子,寫了記得@我,語言不限。

以上所述就是本文的全部內容了,希望大家能夠喜歡。

請您花一點時間將文章分享給您的朋友或者留下評論。我們將會由衷感謝您的支持!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved