2.0 版框架是完全重寫的,在 1.1 和 2.0 兩個版本之間存在相當多差異。因此從 1.1 版升級并不像小版本間的跨越那么簡單,通過本指南你將會了解兩個版本間主要的不同之處。
如果你之前沒有用過 Yii 1.1,可以跳過本章,直接從"入門篇quot;開始讀起。
請注意,Yii 2.0 引入了很多本章并沒有涉及到的新功能。強烈建議你通讀整部權(quán)威指南來了解所有新特性。這樣有可能會發(fā)現(xiàn)一些以前你要自己開發(fā)的功能,而現(xiàn)在已經(jīng)被包含在核心代碼中了。
Yii 2.0 完全擁抱 Composer,它是事實上的 PHP 依賴管理工具。核心框架以及擴展的安裝都通過 Composer 來處理。想要了解更多如何安裝 Yii 2.0 請參閱本指南的 安裝 Yii 章節(jié)。如果你想創(chuàng)建新擴展,或者把你已有的 Yii 1.1 的擴展改寫成兼容 2.0 的版本,你可以參考 創(chuàng)建擴展 章節(jié)。
Yii 2.0 需要 PHP 5.4 或更高版本,該版本相對于 Yii 1.1 所需求的 PHP 5.2 而言有巨大的改進。因此在語言層面上有很多的值得注意的不同之處。下面是 PHP 層的主要變化匯總:
[...元素...]
用于取代 array(...元素...)
<?=
,自 PHP 5.4 起總會被識別并且合法,無論 short_open_tag 的設(shè)置是什么,可以安全使用。intl
來支持國際化的相關(guān)功能。Yii 2.0 里最明顯的改動就數(shù)命名空間的使用了。幾乎每一個核心類都引入了命名空間,比如 yii\web\Request
。1.1 版類名前綴 “C” 已經(jīng)不再使用。當前的命名方案與目錄結(jié)構(gòu)相吻合。例如,yii\web\Request
就表明對應(yīng)的類文件是 Yii 框架文件夾下的web/Request.php
文件。
有了 Yii 的類自動加載器,你可以直接使用全部核心類而不需要顯式包含具體文件。
Yii 2.0 把 1.1 中的 CComponent
類拆分成了兩個類:yii\base\Object 和 yii\base\Component。yii\base\Object 類是一個輕量級的基類,你可以通過 getters 和 setters 來定義對象的屬性。yii\base\Component 類繼承自 yii\base\Object,同時進一步支持 事件 和 行為。
如果你不需要用到事件或行為,應(yīng)該考慮使用 yii\base\Object 類作為基類。這種類通常用來表示基本的數(shù)據(jù)結(jié)構(gòu)。
yii\base\Object 類引入了一種統(tǒng)一對象配置的方法。所有 yii\base\Object 的子類都應(yīng)該用以下方法聲明它的構(gòu)造方法(如果需要的話),以正確配置它自身:
class MyClass extends \yii\base\Object
{
public function __construct($param1, $param2, $config = [])
{
// ... 配置生效前的初始化過程
parent::__construct($config);
}
public function init()
{
parent::init();
// ... 配置生效后的初始化過程
}
}
在上面的例子里,構(gòu)造方法的最后一個參數(shù)必須傳入一個配置數(shù)組,包含一系列用于在方法結(jié)尾初始化相關(guān)屬性的鍵值對。你可以重寫 yii\base\Object::init() 方法來執(zhí)行一些需要在配置生效后進行的初始化工作。
你可以通過遵循以下約定俗成的編碼習(xí)慣,來使用配置數(shù)組創(chuàng)建并配置新的對象:
$object = Yii::createObject([
'class' => 'MyClass',
'property1' => 'abc',
'property2' => 'cde',
], [$param1, $param2]);
更多有關(guān)配置的細節(jié)可以在配置章節(jié)找到。
在 Yii 1 中,通常通過定義 on
開頭的方法(例如 onBeforeSave
)來創(chuàng)建事件。而在 Yii 2 中,你可以使用任意的事件名了。同時通過調(diào)用 yii\base\Component::trigger() 方法來觸發(fā)相關(guān)事件:
$event = new \yii\base\Event;
$component->trigger($eventName, $event);
要給事件附加一個事件事件處理器,需要使用 yii\base\Component::on() 方法:
$component->on($eventName, $handler);
// 解除事件處理器,使用 off 方法:
// $component->off($eventName, $handler);
事件功能還有更多增強之處。要了解它們,請查看事件章節(jié)。
Yii 2.0 將路徑別名的應(yīng)用擴大至文件/目錄路徑和 URL。Yii 2.0 中路徑別名必須以 @
符號開頭,以區(qū)別于普通文件目錄路徑或 URL。例如 @yii
就是指向 Yii 安裝目錄的別名。絕大多數(shù) Yii 核心代碼都支持別名。例如 yii\caching\FileCache::cachePath 就同時支持路徑別名或普通的目錄地址。
路徑別名也和類的命名空間密切相關(guān)。建議給每一個根命名空間定義一個路徑別名,從而無須額外配置,便可啟動 Yii 的類自動加載機制。例如,因為有 @yii
指向 Yii 安裝目錄,那類似 yii\web\Request
的類就能被 Yii 自動加載。同理,若你用了一個第三方的類庫,如 Zend Framework,你只需定義一個名為 @Zend
的路徑別名指向該框架的安裝目錄。之后 Yii 就可以自動加載任意 Zend Framework 中的類了。
更多路徑別名信息請參閱路徑別名章節(jié)。
Yii 2 中視圖最明顯的改動是視圖內(nèi)的特殊變量 $this
不再指向當前控制器或小部件,而是指向視圖對象,它是 2.0 中引入的全新概念。視圖對象為 yii\web\View 的實例,他代表了 MVC 模式中的視圖部分。如果你想要在視圖中訪問一個控制器或小部件,可以使用$this->context
。
要在其他視圖里渲染一個局部視圖,使用 $this->render()
,而不是 $this->renderPartial()
。render()
現(xiàn)在只返回渲染結(jié)果,而不是直接顯示它,所以現(xiàn)在你必須顯式地把它 echo 出來。像這樣:
echo $this->render('_item', ['item' => $item]);
除了使用 PHP 作為主要的模板語言,Yii 2.0 也裝備了兩種流行模板引擎的官方支持:Smarty 和 Twig。過去的 Prado 模板引擎不再被支持。要使用這些模板引擎,你需要配置 view
應(yīng)用組件,給它設(shè)置 yii\base\View::$renderers 屬性。具體請參閱模板引擎章節(jié)。
Yii 2.0 使用 yii\base\Model 作為模型基類,類似于 1.1 的 CModel
。CFormModel
被完全棄用了,現(xiàn)在要創(chuàng)建表單模型類,可以通過繼承 yii\base\Model 類來實現(xiàn)。
Yii 2.0 引進了名為 yii\base\Model::scenarios() 的新方法來聲明支持的場景,并指明在哪個場景下某屬性必須經(jīng)過驗證,可否被視為安全值等等。如:
public function scenarios()
{
return [
'backend' => ['email', 'role'],
'frontend' => ['email', '!role'],
];
}
上面的代碼聲明了兩個場景:backend
和 frontend
。對于 backend
場景,email
和 role
屬性值都是安全的,且能進行批量賦值。對于 frontend
場景,email
能批量賦值而 role
不能。 email
和 role
都必須通過規(guī)則驗證。
yii\base\Model::rules() 方法仍用于聲明驗證規(guī)則。注意,由于引入了 yii\base\Model::scenarios(),現(xiàn)在已經(jīng)沒有 unsafe
驗證器了。
大多數(shù)情況下,如果 yii\base\Model::rules() 方法內(nèi)已經(jīng)完整地指定場景了,那就不必覆寫 yii\base\Model::scenarios(),也不必聲明unsafe
屬性值。
要了解更多有關(guān)模型的細節(jié),請參考模型章節(jié)。
Yii 2.0 使用 yii\web\Controller 作為控制器的基類,它類似于 1.1 的 CController
。使用 yii\base\Action 作為操作類的基類。
這些變化最明顯的影響是,當你在寫控制器操作的代碼時,應(yīng)該返回(return)要渲染的內(nèi)容而不是輸出(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)章節(jié)了解有關(guān)控制器的更多細節(jié)。
Yii 2.0 使用 yii\base\Widget 作為小部件基類,類似于 1.1 的 CWidget
。
為了讓框架獲得更好的 IDE 支持,Yii 2.0 引進了一個調(diào)用小部件的新語法。包含 yii\base\Widget::begin(),yii\base\Widget::end() 和 yii\base\Widget::widget() 三個靜態(tài)方法,用法如下:
use yii\widgets\Menu;
use yii\widgets\ActiveForm;
// 注意必須 **"echo"** 結(jié)果以顯示內(nèi)容
echo Menu::widget(['items' => $items]);
// 傳遞一個用于初始化對象屬性的數(shù)組
$form = ActiveForm::begin([
'options' => ['class' => 'form-horizontal'],
'fieldConfig' => ['inputOptions' => ['class' => 'input-xlarge']],
]);
... 表單輸入欄都在這里 ...
ActiveForm::end();
更多細節(jié)請參閱小部件章節(jié)。
2.0 主題的運作方式跟以往完全不同了。它們現(xiàn)在基于路徑映射機制,該機制會把一個源視圖文件的路徑映射到一個主題視圖文件路徑。舉例來說,如果路徑映射為 ['/web/views' => '/web/themes/basic']
,那么 /web/views/site/index.php
視圖經(jīng)過主題修飾的版本就會是 /web/themes/basic/site/index.php
。也因此讓主題現(xiàn)在可以應(yīng)用在任何視圖文件之上,甚至是渲染控制器上下文環(huán)境之外的視圖文件或小部件。
同樣,CThemeManager
組件已經(jīng)被移除了。取而代之的 theme
成為了 view
應(yīng)用組件的一個可配置屬性。
更多細節(jié)請參考主題章節(jié)。
控制臺應(yīng)用現(xiàn)在如普通的 Web 應(yīng)用程序一樣,由控制器組成,控制臺的控制器繼承自 yii\console\Controller,類似于 1.1 的CConsoleCommand
。
運行控制臺命令使用 yii <route>
,其中 <route>
代表控制器的路由(如 sitemap/index
)。額外的匿名參數(shù)傳遞到對應(yīng)的控制器操作方法,而有名的參數(shù)根據(jù) yii\console\Controller::options() 的聲明來解析。
Yii 2.0 支持基于代碼注釋自動生成相的關(guān)命令行幫助(help)信息。
更多細節(jié)請參閱控制臺命令章節(jié)。
Yii 2.0 移除了原來內(nèi)置的日期格式器和數(shù)字格式器,為了支持 PECL intl PHP module(PHP 的國際化擴展)的使用。
消息翻譯現(xiàn)在由 i18n
應(yīng)用組件執(zhí)行。該組件管理一系列消息源,允許使用基于消息類別的不同消息源。
更多細節(jié)請參閱國際化(Internationalization)章節(jié)。
操作的過濾現(xiàn)在通過行為(behavior)來實現(xiàn)。要定義一個新的,自定義的過濾器,請繼承 yii\base\ActionFilter 類。要使用一個過濾器,需要把過濾器類作為一個 behavior
綁定到控制器上。例如,要使用 yii\filters\AccessControl 過濾器,你需要在控制器內(nèi)添加如下代碼:
public function behaviors()
{
return [
'access' => [
'class' => 'yii\filters\AccessControl',
'rules' => [
['allow' => true, 'actions' => ['admin'], 'roles' => ['@']],
],
],
];
}
更多細節(jié)請參考過濾器章節(jié)。
Yii 2.0 引入了一個新的概念,稱為資源包(Asset Bundle),以代替 1.1 的腳本包概念。
一個資源包是一個目錄下的資源文件集合(如 JavaScript 文件、CSS 文件、圖片文件等)。每一個資源包被表示為一個類,該類繼承自 yii\web\AssetBundle。用 yii\web\AssetBundle::register() 方法注冊一個資源包后,就使它的資源可被 Web 訪問了,注冊了資源包的頁面會自動包含和引用資源包內(nèi)指定的 JS 和 CSS 文件。
更多細節(jié)請參閱 前端資源管理(Asset) 章節(jié)。
Yii 2.0 很多常用的靜態(tài)助手類,包括:
請參考助手一覽 章節(jié)來了解更多。
Yii 2.0 引進了表單欄(field)的概念,用來創(chuàng)建一個基于 yii\widgets\ActiveForm 的表單。一個表單欄是一個由標簽、輸入框、錯誤消息(可能還有提示文字)組成的容器,被表示為一個 yii\widgets\ActiveField 對象。使用表單欄建立表單的過程比以前更整潔利落:
<?php $form = yii\widgets\ActiveForm::begin(); ?>
<?= $form->field($model, 'username') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<div class="form-group">
<?= Html::submitButton('Login') ?>
</div>
<?php yii\widgets\ActiveForm::end(); ?>
請參考創(chuàng)建表單章節(jié)來了解更多細節(jié)。
Yii 1.1 中,查詢語句的生成分散在多個類中,包括 CDbCommand
,CDbCriteria
以及 CDbCommandBuilder
。Yii 2.0 以 yii\db\Query 對象的形式表示一個數(shù)據(jù)庫查詢,這個對象使用 yii\db\QueryBuilder 在幕后生成 SQL 語句。例如:
$query = new \yii\db\Query();
$query->select('id, name')
->from('user')
->limit(10);
$command = $query->createCommand();
$sql = $command->sql;
$rows = $command->queryAll();
最重要的是,這些查詢生成方法還可以和活動記錄配合使用。
請參考查詢生成器(Query Builder)章節(jié)了解更多內(nèi)容。
Yii 2.0 的活動記錄改動了很多。兩個最顯而易見的改動分別涉及查詢語句的生成(query building)和關(guān)聯(lián)查詢的處理(relational query handling)。
1.1 中的 CDbCriteria
類在 Yii 2 中被 yii\db\ActiveQuery 所替代。這個類是繼承自 yii\db\Query,因此也繼承了所有查詢生成方法。開始拼裝一個查詢可以調(diào)用 yii\db\ActiveRecord::find() 方法進行:
// 檢索所有“活動的”客戶和訂單,并以 ID 排序:
$customers = Customer::find()
->where(['status' => $active])
->orderBy('id')
->all();
要聲明一個關(guān)聯(lián)關(guān)系,只需簡單地定義一個 getter 方法來返回一個 yii\db\ActiveQuery 對象。getter 方法定義的屬性名代表關(guān)聯(lián)表名稱。如,以下代碼聲明了一個名為 orders
的關(guān)系(1.1 中必須在 relations()
方法內(nèi)聲明關(guān)系):
class Customer extends \yii\db\ActiveRecord
{
public function getOrders()
{
return $this->hasMany('Order', ['customer_id' => 'id']);
}
}
現(xiàn)在你就可以通過調(diào)用 $customer->orders
來訪問關(guān)聯(lián)表中某用戶的訂單了。你還可以用以下代碼進行一場指定條件的實時關(guān)聯(lián)查詢:
$orders = $customer->getOrders()->andWhere('status=1')->all();
當貪婪加載一段關(guān)聯(lián)關(guān)系時,Yii 2.0 和 1.1 的運作機理并不相同。具體來說,在 1.1 中使用一條 JOIN 語句同時查詢主表和關(guān)聯(lián)表記錄。在 Yii 2.0 中會使用兩個沒有 JOIN 的 SQL 語句:第一條語句取回主表記錄,第二條通過主表記錄經(jīng)主鍵篩選后查詢關(guān)聯(lián)表記錄。
當生成返回大量記錄的查詢時,可以鏈式書寫 yii\db\ActiveQuery::asArray() 方法,這樣會以數(shù)組的形式返回查詢結(jié)果,而不必返回 yii\db\ActiveRecord 對象,這能顯著降低因大量記錄讀取所消耗的 CPU 時間和內(nèi)存。如:
$customers = Customer::find()->asArray()->all();
另一個改變是你不能再通過公共變量定義屬性(Attribute)的默認值了。如果你需要這么做的話,可以在你的記錄類的 init
方法中設(shè)置它們。
public function init()
{
parent::init();
$this->status = self::STATUS_NEW;
}
曾幾何時,在 1.1 中重寫一個活動記錄類的構(gòu)造方法會導(dǎo)致一些問題。它們不會在 2.0 中出現(xiàn)了。需要注意的是,如果你需要在構(gòu)造方法中添加一些參數(shù),恐怕必須重寫 yii\db\ActiveRecord::instantiate() 方法。
活動記錄方面還有很多其他的變化與改進,請參考活動記錄章節(jié)以了解更多細節(jié)。
在 2.0 中遺棄了活動記錄行為基類 CActiveRecordBehavior
。如果你想創(chuàng)建活動記錄行為,需要直接繼承 yii\base\Behavior
。如果行為類中需要表示一些事件,需要像這樣覆寫 events()
方法:
namespace app\components;
use yii\db\ActiveRecord;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
// ...
public function events()
{
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
];
}
public function beforeValidate($event)
{
// ...
}
}
1.1 中的 CWebUser
類現(xiàn)在被 yii\web\User 所取代,隨之 CUserIdentity
類也不在了。與之相對的,為達到相同目的,你可以實現(xiàn) yii\web\IdentityInterface 接口,它使用起來更直觀。在高級應(yīng)用模版里提供了一個這樣的一個例子。
要了解更多細節(jié)請參考認證(Authentication),授權(quán)(Authorization)以及高級應(yīng)用模版 這三個章節(jié)。
Yii 2.0 的 URL 管理跟 1.1 中很像。一個主要的改進是現(xiàn)在的 URL 管理支持可選參數(shù)了。比如,如果你在 2.0 中定義了一個下面這樣的規(guī)則,那么它可以同時匹配 post/popular
和 post/1/popular
兩種 URL。而在 1.1 中為達成相同效果,必須要使用兩條規(guī)則。
[
'pattern' => 'post/<page:\d+>/<tag>',
'route' => 'post/index',
'defaults' => ['page' => 1],
]
如果你有一些遺留的 Yii 1.1 代碼,需要跟 Yii 2.0 一起使用,可以參考 1.1 和 2.0 共用章節(jié)。
更多建議: