位置:首頁 > 框架 > Yii2教學 > 從 Yii 1.1升級到 Yii2

從 Yii 1.1升級到 Yii2

從 Yii 1.1 升級

2.0 版框架是完全重寫的,在 1.1 和 2.0 兩個版本之間存在相當多差異。因此從 1.1 版升級並不像小版本間的跨越那麼簡單,通過本指南你將會了解兩個版本間主要的不同之處。
 
如果你之前冇有用過 Yii 1.1,可以跳過本章,直接從"[入門篇](start-installation.md)"開始讀起。
 
請注意,Yii 2.0 引入了很多本章並冇有涉及到的新功能。強烈建議你通讀整部權威指南來了解所有新特性。這樣有可能會發現一些以前你要自己開發的功能,而現在已經被包含在核心代碼中了。
 

安裝

Yii 2.0 完全擁抱 [Composer](https://getcomposer.org/),它是PHP中的一個依賴管理工具。核心框架以及擴展的安裝都通過 Composer 來處理。想要了解更多如何安裝 Yii 2.0 請參閱本指南的 [安裝 Yii](start-installation.md) 章節。如果你想創建新擴展,或者把你已有的 Yii 1.1 的擴展改寫成兼容 2.0 的版本,你可以參考 [創建擴展](extend-creating-extensions.md) 章節。
 

PHP 需求

Yii 2.0 需要 PHP 5.4 或更高版本,該版本相對於 Yii 1.1 所需求的 PHP 5.2 而言有巨大的改進。因此在語言層麵上有很多的值得注意的不同之處。下麵是 PHP 層的主要變化彙總:
 
- [命名空間](http://php.net/manual/zh/language.namespaces.php)
- [匿名函數](http://php.net/manual/zh/functions.anonymous.php)
- 數組短語法 `[...元素...]` 用於取代 `array(...元素...)`
- 視圖文件中的短格式 echo 標簽 `<?=`,自 PHP 5.4 起總會被識彆並且合法,無論 short_open_tag 的設置是什麼,可以安全使用。
- [SPL 類和接口](http://php.net/manual/zh/book.spl.php)
- [延遲靜態綁定](http://php.net/manual/zh/language.oop5.late-static-bindings.php)
- [日期和時間](http://php.net/manual/zh/book.datetime.php)
- [Traits](http://php.net/manual/zh/language.oop5.traits.php)
- [intl](http://php.net/manual/zh/book.intl.php) Yii 2.0 使用 PHP 擴展 `intl` 來支持國際化的相關功能。
 
 

命名空間

Yii 2.0 裡最明顯的改動就數命名空間的使用了。幾乎每一個核心類都引入了命名空間,比如 `yii\web\Request`。1.1 版用於類名前的字母 “C” 已經不再使用。當前的命名規範與目錄結構相吻合。例如,`yii\web\Request` 就表明對應的類文件是 Yii 框架文件夾下的 `web/Request.php` 文件。
 
(有了 Yii 的類自動加載器,你可以直接使用全部核心類而不需要顯式包含具體文件。)
 

組件(Component)與對象(Object)

Yii 2.0 把 1.1 裡的 `CComponent` 類拆分成了兩個類:[[yii\base\Object]] 和 [[yii\base\Component]]。[[yii\base\Object|Object]] 類是一個輕量級的基類,你可以通過 getters 和 setters 來定義 [object 的屬性](concept-properties.md)。[[yii\base\Component|Component]] 類繼承自 [[yii\base\Object|Object]],同時進一步支持 [事件](concept-events.md) 和 [行為](concept-behaviors.md)。
如果你不需要用到事件或行為,應該考慮使用 [[yii\base\Object|Object]] 類作為基類。這通常是表示基本數據結構的類。
 

對象的配置

[[yii\base\Object|Object]] 類引入了一種統一對象配置的方法。所有 [[yii\base\Object|Object]] 的子類都應該用以下方法聲明它的構造方法(如果需要的話),以正確配置它自身:
 
class MyClass extends \yii\base\Object
{
    public function __construct($param1, $param2, $config = [])
    {
        // ... 配置生效前的初始化過程

        parent::__construct($config);
    }

    public function init()
    {
        parent::init();

        // ...配置生效後的初始化過程
    }
}
在上麵的例子裡,構造方法的最後一個參數必須輸入一個配置數組,包含一係列用於在方法結尾初始化相關屬性的鍵值對。你可以重寫 [[yii\base\Object::init()|init()]] 方法來執行一些需要在配置生效後進行的初始化工作。
 
你可以通過遵循以下約定俗成的編碼習慣,來使用配置數組創建並配置新的對象:
 
$object = Yii::createObject([
    'class' => 'MyClass',
    'property1' => 'abc',
    'property2' => 'cde',
], [$param1, $param2]);
 
更多有關配置的細節可以在[配置](concept-configurations.md)章節找到。
 

事件(Event)

在 Yii 1 中,通常通過定義 `on` 開頭的方法(例如 `onBeforeSave`)來創建事件。而在 Yii 2 中,你可以使用任意的事件名了。同時通過調用 [[yii\base\Component::trigger()|trigger()]] 方法來觸發相關事件:
 
$event = new \yii\base\Event;
$component->trigger($eventName, $event);
 
要給事件附加一個事件句柄(Event Handler 或者叫事件處理器),需要使用 [[yii\base\Component::on()|on()]] 方法:
 
$component->on($eventName, $handler);
// 要解除相關句柄,使用 off 方法:
// $component->off($eventName, $handler);
 
事件功能還有更多增強之處。要了解它們,請查看[事件](concept-events.md)章節。
 

路徑彆名(Path Alias)

Yii 2.0 將路徑彆名的應用擴大至文件/目錄路徑和 URL。Yii 2.0 中路徑彆名必須以 `@` 符號開頭,以區彆於普通文件目錄路徑或 URL。例如 `@yii` 就是指向 Yii 安裝目錄的彆名。絕大多數 Yii 核心代碼都支持彆名。例如 [[yii\caching\FileCache::cachePath]] 就同時支持路徑彆名或普通的目錄地址。
 
路徑彆名也和類的命名空間密切相關。建議給每一個根命名空間定義一個路徑彆名,從而無須額外配置,便可啟動 Yii 的類自動加載機製。例如,因為有 `@yii` 指向 Yii 安裝目錄,那類似 `yii\web\Request` 的類就能被 Yii 自動加載。同理,若你用了一個第三方的類庫,如 Zend Framework,你隻需定義一個名為 `@Zend` 的路徑彆名指向該框架的安裝目錄。之後 Yii 就可以自動加載任意 Zend Framework 中的類了。
 
更多路徑彆名信息請參閱[路徑彆名](concept-aliases.md)章節。
 

視圖(View)

Yii 2 中視圖最明顯的改動是視圖內的特殊變量 `$this` 不再指向當前控製器或小部件,而是指向**視圖**對象,它是 2.0 中引入的全新概念。**視圖**對象為 [[yii\web\View]] 的實例,他代表了 MVC 模式中的視圖部分。如果你想要在視圖中訪問一個控製器或小部件,可以使用 `$this->context`。
 
要在其他視圖裡渲染一個局部視圖,使用 `$this->render()`,而不是 `$this->renderPartial()`。`render()` 現在隻返回渲染結果,而不是直接顯示它,所以現在你必須顯式地把它 **echo** 出來。像這樣:
 
echo $this->render('_item', ['item' => $item]);
 
除了使用 PHP 作為主要的模板語言,Yii 2.0 也裝備了兩種流行模板引擎的官方支持:Smarty 和 Twig。過去的 Prado 模板引擎不再被支持。要使用這些模板引擎,你需要配置 `view` 應用組件,給它設置 [[yii\base\View::$renderers|View::$renderers]] 屬性。具體請參閱[模板引擎](tutorial-template-engines.md)章節。
 
 

模型(Model)

Yii 2.0 使用 [[yii\base\Model]] 作為模型基類,類似於 1.1 的 `CModel` 。`CFormModel` 被完全棄用了,現在要創建表單模型類,可以通過繼承 [[yii\base\Model]] 類來實現。
 
Yii 2.0 引進了名為 [[yii\base\Model::scenarios()|scenarios()]] 的新方法來聲明支持的場景,並指明在哪個場景下某屬性必須經過驗證,可否被視為安全值等等。如:
 
public function scenarios()
{
    return [
        'backend' => ['email', 'role'],
        'frontend' => ['email', '!role'],
    ];
}
 
上麵的代碼聲明了兩個場景:`backend` 和 `frontend` 。對於 `backend` 場景,`email` 和 `role` 屬性值都是安全的,且能進行批量賦值。對於 `frontend` 場景,`email` 能批量賦值而 `role` 不能。 `email` 和 `role` 都必須通過規則驗證。
 
[[yii\base\Model::rules()|rules()]] 方法仍用於聲明驗證規則。注意,由於引入了 [[yii\base\Model::scenarios()|scenarios()]],現在已經冇有 `unsafe` 驗證器了。
 
大多數情況下,如果 [[yii\base\Model::rules()|rules()]] 方法內已經完整地指定場景了,那就不必覆寫 [[yii\base\Model::scenarios()|scenarios()]],也不必聲明 `unsafe` 屬性值。
 
要了解更多有關模型的細節,請參考[模型](structure-models.md)章節。
 

控製器(Controller)

Yii 2.0 使用 [[yii\web\Controller]] 作為控製器的基類,類似於 1.1 的 `CWebController`。使用 [[yii\base\Action]] 作為操作類的基類。
 
這些變化最明顯的影響是,當你在寫控製器操作的代碼時,應該返回(return)要渲染的內容而不是輸出(echo)它:
 
public function actionView($id)
{
    $model = \app\models\Post::findOne($id);
    if ($model) {
        return $this->render('view', ['model' => $model]);
    } else {
        throw new \yii\web\NotFoundHttpException;
    }
}
 
請查看 [控製器(Controller)](structure-controllers.md) 章節了解有關控製器的更多細節。
 

小部件(Widget)

Yii 2.0 使用 [[yii\base\Widget]] 作為小部件基類,類似於 1.1 的 `CWidget`。
 
為了讓框架獲得更好的 IDE 支持,Yii 2.0 引進了一個調用小部件的新語法。包含 [[yii\base\Widget::begin()|begin()]],[[yii\base\Widget::end()|end()]] 和 [[yii\base\Widget::widget()|widget()]] 三個靜態方法,用法如下:
 
use yii\widgets\Menu;
use yii\widgets\ActiveForm;

// 注意必須 **"echo"** 結果以顯示內容
echo Menu::widget(['items' => $items]);

// 傳遞一個用於初始化對象屬性的數組
$form = ActiveForm::begin([
    'options' => ['class' => 'form-horizontal'],
    'fieldConfig' => ['inputOptions' => ['class' => 'input-xlarge']],
]);
... 表單輸入欄都在這裡 ...
ActiveForm::end();
更多細節請參閱[小部件](structure-widgets.md)章節。
 

主題(Theme)

2.0 主題的運作方式跟以往完全不同了。它們現在基於**路徑映射機製**,該機製會把一個源視圖文件的路徑映射到一個主題視圖文件路徑。舉例來說,如果路徑映射為 `['/web/views' => '/web/themes/basic']`,那麼 `/web/views/site/index.php` 視圖經過主題修飾的版本就會是 `/web/themes/basic/site/index.php`。也因此讓主題現在可以應用在任何視圖文件之上,甚至是渲染控製器上下文環境之外的視圖文件或小部件。
 
同樣,`CThemeManager` 組件已經被移除了。取而代之的 `theme` 成為了 `view` 應用組件的一個可配置屬性。
 
更多細節請參考[主題](output-theming.md)章節。
 

控製台應用(Console Application)

控製台應用現在如普通的 Web 應用程序一樣,由控製器組成,控製台的控製器繼承自 [[yii\console\Controller]],類似於 1.1 的 `CConsoleCommand`。
 
運行控製台命令使用 `yii <route>`,其中 `<route>` 代表控製器的路由(如 `sitemap/index`)。額外的匿名參數傳遞到對應的控製器操作方法,而有名的參數根據 [[yii\console\Controller::options()]] 的聲明來解析。
 
Yii 2.0 支持基於代碼注釋自動生成相的關命令行幫助(help)信息。
 
更多細節請參閱[控製台命令](tutorial-console.md)章節。

國際化(I18N)

Yii 2.0 移除了原來內置的日期格式器和數字格式器,為了支持 [PECL intl PHP module](http://pecl.php.net/package/intl)(PHP 的國際化擴展)的使用。
 
消息翻譯現在由 `i18n` 應用組件執行。該組件管理一係列消息源,允許使用基於消息類彆的不同消息源。
 
更多細節請參閱[國際化(Internationalization)](tutorial-i18n.md)章節。
 

操作過濾器(Action Filters)

操作的過濾現在通過行為(behavior)來實現。要定義一個新的,自定義的過濾器,請繼承 [[yii\base\ActionFilter]] 類。要使用一個過濾器,需要把過濾器類作為一個 `behavior` 綁定到控製器上。例如,要使用 [[yii\filters\AccessControl]] 過濾器,你需要在控製器內添加如下代碼:
 
public function behaviors()
{
    return [
        'access' => [
            'class' => 'yii\filters\AccessControl',
            'rules' => [
                ['allow' => true, 'actions' => ['admin'], 'roles' => ['@']],
            ],
        ],
    ];
}
更多細節請參考[過濾器](structure-filters.md)章節。

前端資源(Assets)

Yii 2.0 引入了一個新的概念,稱為**資源包**(Asset Bundle),以代替 1.1 的腳本包概念。
 
一個資源包是一個目錄下的資源文件集合(如 JavaScript 文件、CSS 文件、圖片文件等)。每一個資源包被表示為一個類,該類繼承自 [[yii\web\AssetBundle]]。用 [[yii\web\AssetBundle::register()]] 方法注冊一個資源包後,就使它的資源可被 Web 訪問了,注冊了資源包的頁麵會自動包含和引用資源包內指定的 JS 和 CSS 文件。
 
更多細節請參閱 [前端資源管理(Asset)](structure-assets.md) 章節。
 

助手類(Helpers)

Yii 2.0 很多常用的靜態助手類,包括:
* [[yii\helpers\Html]]
* [[yii\helpers\ArrayHelper]]
* [[yii\helpers\StringHelper]]
* [[yii\helpers\FileHelper]]
* [[yii\helpers\Json]]
 
請參考[助手一覽](helper-overview.md) 章節來了解更多。
 

表單

Yii 2.0 引進了**表單欄(field)**的概念,用來創建一個基於 [[yii\widgets\ActiveForm]]的表單。一個表單欄是一個由標簽、輸入框、錯誤消息(可能還有提示文字)組成的容器,被表示為 [[yii\widgets\ActiveField|ActiveField]] 對象。使用表單欄建立表單的過程比以前更整潔利落:
 

 <?php field($model, 'username') ?>
 <?php  field($model, 'password')->passwordInput() ?>
    
 
請參考[創建表單](input-forms.md)章節來了解更多細節。
 

查詢生成器(Query Builder)

 
Yii 1.1 中,查詢語句的生成分散在多個類中,包括 `CDbCommand`,`CDbCriteria` 以及 `CDbCommandBuilder`。Yii 2.0 以 [[yii\db\Query|Query]] 對象的形式表示一個數據庫查詢,這個對象使用 [[yii\db\QueryBuilder|QueryBuilder]] 在幕後生成 SQL 語句。例如:
 
$query = new \yii\db\Query();
$query->select('id, name')
      ->from('user')
      ->limit(10);

$command = $query->createCommand();
$sql = $command->sql;
$rows = $command->queryAll();
最重要的是,這些查詢生成方法還可以和[活動記錄](db-active-record.md)配合使用。
請參考[查詢生成器(Query Builder)](db-query-builder.md)章節了解更多內容。

活動記錄(Active Record)

Yii 2.0 的[活動記錄](db-active-record.md)改動了很多。兩個最顯而易見的改動分彆涉及查詢語句的生成(query building)和關聯查詢的處理(relational query handling)。
1.1 中的 `CDbCriteria` 類在 Yii 2 中被 [[yii\db\ActiveQuery]] 所替代。這個類是繼承自 [[yii\db\Query]],因此也繼承了所有查詢生成方法。開始拚裝一個查詢可以調用 [[yii\db\ActiveRecord::find()]] 方法進行:
 
// 檢索所有 *活動的* 客戶和訂單,並以 ID 排序:
$customers = Customer::find()
    ->where(['status' => $active])
    ->orderBy('id')
    ->all();
要聲明一個關聯關係,隻需簡單地定義一個 getter 方法來返回一個 [[yii\db\ActiveQuery|ActiveQuery]] 對象。getter 方法定義的屬性名(譯者注:即 getOrders() 中的 orders)表示關聯關係名。如,以下代碼聲明了一個名為 `orders` 的關係(1.1 中必須在 `relations()` 方法內聲明關係):
 
class Customer extends \yii\db\ActiveRecord
{
    public function getOrders()
    {
        return $this->hasMany('Order', ['customer_id' => 'id']);
    }
}
現在你就可以通過調用 `$customer->orders` 來訪問關聯表中某用戶的訂單了。你還可以用以下代碼進行一場指定條件的實時關聯查詢:
 
$orders = $customer->getOrders()->andWhere('status=1')->all();
 
當貪婪加載一段關聯關係時,Yii 2.0 和 1.1 的運作機理並不相同。具體來說,在 1.1 中使用一條 JOIN 語句同時查詢主表和關聯表記錄。在 Yii 2.0 中會使用兩個冇有 JOIN 的 SQL 語句:第一條語句取回主表記錄,第二條通過主表記錄經主鍵篩選後查詢關聯表記錄。
 
當生成返回大量記錄的查詢時,可以鏈式書寫 [[yii\db\ActiveQuery::asArray()|asArray()]] 方法,這樣會以數組的形式返回查詢結果,而不必返回
[[yii\db\ActiveRecord|ActiveRecord]] 對象,這能顯著降低因大量記錄讀取所消耗的 CPU 時間和內存。如:
 
$customers = Customer::find()->asArray()->all();
另一個改變是你不能再通過公共數據定屬性(Attribute)的默認值了。如果你需要這麼做的話,可以在你的記錄類的 `init` 方法中設置它們。
 
public function init()
{
    parent::init();
    $this->status = self::STATUS_NEW;
}
曾幾何時,在 1.1 中重寫一個活動記錄類的構造方法(Constructor)會導致一些問題。它們不會在 2.0 中出現了。需要注意的是,如果你需要在構造方法中添加一些參數,恐怕必須重寫 [[yii\db\ActiveRecord::instantiate()]] 方法。
活動記錄方麵還有很多其他的變化與改進,請參考[活動記錄](db-active-record.md)章節以了解更多細節。
 

用戶及身份驗證接口(IdentityInterface)

1.1 中的 `CWebUser` 類現在被 [[yii\web\User]] 所取代,隨之 `CUserIdentity` 類也不在了。與之相對的,為達到相同目的,你可以實現 [[yii\web\IdentityInterface]] 接口,它使用起來更直觀。在高級應用模版裡提供了一個這樣的一個例子。
要了解更多細節請參考[認證(Authentication)](security-authentication.md),[授權(Authorization)](security-authorization.md)以及[高級應用模版](tutorial-advanced-app.md) 這三個章節。
 

URL 管理

Yii 2.0 的 URL 管理跟 1.1 中很像。一個主要的改進是現在的 URL 管理支持**可選參數**了。比如,如果你在 2.0 中定義了一個下麵這樣的規則,那麼它可以同時匹配 `post/popular` 和 `post/1/popular` 兩種 URL。而在 1.1 中為達成相同效果,必須要使用兩條規則。
 
[
    'pattern' => 'post//',
    'route' => 'post/index',
    'defaults' => ['page' => 1],
]
請參考[URL 解析和生成](runtime-url-handling.md) 章節,以了解更多細節。.
 

同時使用 Yii 1.1 和 2.x

如果你有一些遺留的 Yii 1.1 代碼,需要跟 Yii 2.0 一起使用,可以參考 [1.1 和 2.0 共用](extend-using-v1-v2.md)章節。