?
? ????? PHP ??? ???? ??? ?? ??
2.0 版框架是完全重寫的,在 1.1 和 2.0 兩個版本之間存在相當多差異。因此從 1.1 版升級并不像小版本間的跨越那么簡單,通過本指南你將會了解兩個版本間主要的不同之處。
如果你之前沒有用過 Yii 1.1,可以跳過本章,直接從"入門篇"開始讀起。
請注意,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í)行一些需要在配置生效后進行的初始化工作。
你可以通過遵循以下約定俗成的編碼習慣,來使用配置數(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>gt;
,其中?<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)造方法會導致一些問題。它們不會在 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],
]
請參考URL 解析和生成?章節(jié),以了解更多細節(jié)。.