課程
/后端開發
/PHP
/Yii框架不得不說的故事—高效篇(2)
yii 1 和 yii2 什么區別呢
2015-07-02
源自:Yii框架不得不說的故事—高效篇(2) 2-1
正在回答
百度一下
幫秋 提問者
大致思路不會變,開發流程變化也不是很大。有變化的是1、yii2帶入的PHP5.4的特性,引入了namespace解決命名沖突,因此基類不會再C字開頭了2、不再所有類都繼承自組件Component,而是選擇繼承object和component(也繼承自object,但帶有事件功能、以及用于擴展的Behavior功能)3、更加的MVC,原先的view層其實基本算是controller直接include進來的,現在有了view的類用來控制,因此View層在使用Controller帶來的參數的方式稍有不同。4、yii2分基本版(看上去和1差不多)和高級版(分前臺和后臺),高級版更加適合開發大型項目。5、其他的都是細節方面的變化,比如塊賦值(基本用于收集表單數據)更加方便了。安裝完畢界面就自帶bootstrap風格了,等等等等。當然還有許多其他的特性,可以直接參看yii在git上更新的文檔:yii2/docs/guide/upgrade-from-v1.md at master 路 yiisoft/yii2 路 GitHub--update--1、加入了Dependency Injection(依賴注入,理論可以看經典翻譯文IoC容器和依賴注入模式(轉)-redcoffee-ChinaUnix博客,yii的具體實現看/vendor/yiisoft/yii2/di下的container和instance就行),以后創建對象時基本都可以用容器的get方法替代new了,很不錯很贊喲~
自己不會百度下
這部分內容是專門為已經有Yii1.1基礎的讀者朋友寫的。將Yii2.0與Yii1.1的不同點著重寫出來,對比學起來會快得多。 而對于從未接觸過Yii的讀者朋友,這部分內容掃一掃就可以了,作為對過往歷史的一個了解就夠了。 如果有的內容你一時沒看明白,也不要緊,本書的正文部分會講清楚的。 另外,沒有Yii1.1的經驗,并不妨礙對Yii2.0的學習。
Yii官方有專門的文檔歸納總結1.1版本和2.0版本的不同。以下內容,主要來自于官方的文檔,我做了下精簡, 選擇比較重要的變化,并加入了一些個人的經驗。
PHP新特性
從對PHP新特性的使用上,兩者就存在很大不同。Yii2.0大量使用了PHP的新特性,這在Yii1.1中是沒有的。因此,Yii2.0對于PHP的版本要求更高,要求PHP5.4及以上。Yii2.0中使用到的PHP新特性,主要有:
命名空間(Namespace)
匿名函數
數組短語法形式: [1,2,3] 取代 array(1,2,3) 。這在多維數組、嵌套數組中,代碼更清晰、簡短。
在視圖文件中使用PHP的 <?= 標簽,取代 echo 語句。
標準PHP庫(SPL) 類和接口,具體可以查看 SPL Class and Interface
延遲靜態綁定, 具體可以查看 Late Static Bindings
PHP標準日期時間
特性(Traits)
使用PHP intl 擴展實現國際化支持, 具體可以查看 PECL init 。
了解Yii2.0使用了PHP的新特性,可以避免開發時由于環境不當,特別是開發生產環境切換時,產生莫名其妙的錯誤。 同時,也是讓讀者朋友借機學習PHP新知識的意思。
Yii2.0與Yii1.1之間最顯著的不同是對于PHP命名空間的使用。Yii1.1中沒有命名空間一說, 為避免Yii核心類與用戶自定義類的命名沖突,所有的Yii核心類的命名,均冠以 C 前綴,以示區別。
而Yii2.0中所有核心類都使用了命名空間,因此, C 前綴也就人老珠黃,退出歷史舞臺了。
命名空間與實際路徑相關聯,比如 yii\base\Object 對應Yii目錄下的 base/Object.php 文件。
基礎類
Yii1.1中使用了一個基礎類 CComponent ,提供了屬性支持等基本功能,因此幾乎所有的Yii核心類都派生自該類。 到了Yii2.0,將一家獨大的 CComponent 進行了拆分。拆分成了 yii\base\Object 和 yii\base\Component 。 拆分的考慮主要是 CComponent 尾大不掉,有影響性能之嫌。 于是,Yii2.0中,把 yii\base\Object 定位于只需要屬性支持,無需事件、行為。 而 yii\base\Component 則在前者的基礎上,加入對于事件和行為的支持。 這樣,開發者可以根據需要,選擇繼承自哪基礎類。
這一功能上的明確劃分,帶來了效率上的提升。在僅表示基礎數據結構,而非反映客觀事物的情況下, yii\base\Object 比較適用。
值得一提的是, yii\base\Object 與 yii\base\Component 兩者并不是同一層級的,前者是后者他爹。
事件(Event)
在Yii1.1中,通過一個 on 前綴的方法來創建事件,比如 CActiveRecord 中的 onBeforeSave() 。 在Yii2.0中,可以任意定義事件的名稱,并自己觸發它:
? ?$event = new \yii\base\Event;// 使用 trigger() 觸發事件$component->trigger($eventName, $event);// 使用 on() 前事件handler與對象綁定$component->on($eventName, $handler);// 使用 off() 解除綁定$component->off($eventName, $handler); ? ?
別名(Alias)
Yii2.0中改變了Yii1.1中別名的使用形式,并擴大了別名的范疇。 Yii1.1中,別名以 . 的形式使用:
RootAlias.path.to.target
而在Yii2.0中,別名以 @ 前綴的方式使用:
@yii/jui
另外,Yii2.0中,不僅有路徑別名,還有URL別名:
? ?// 路徑別名Yii::setAlias('@foo', '/path/to/foo');// URL別名Yii::setAlias('@bar', 'http://www.example.com'); ? ?
別名與命名空間是緊密相關的,Yii建議為所有根命名空間都定義一個別名,比如上面提到的 yii\base\Object , 事實上是定義了 @yii 的別名,表示Yii在系統中的安裝路徑。 這樣一來,Yii就能根據命名空間找到實際的類文件所在路徑,并自動加載。這一點上,Yii2.0與Yii1.1并沒有本質區別。
而如果沒有為根命名空間定義別名,則需要進行額外的配置。將命名空間與實際路徑的映射關系,告知Yii。
關于別名的更詳細內容請看 別名(Alias) 。
視圖(View)
Yii1.1中,MVC(model-view-controller)中的視圖一直是依賴于Controller的,并非是真正意義上獨立的View。 Yii2.0引入了 yii\web\View 類,使得View完全獨立。這也是一個相當重要變化。
首先,Yii2.0中,View作為Application的一個組件,可以在全局中代碼中進行訪問。 因此,視圖渲染代碼不必再局限于Controller中或Widget中。
其次,Yii1.1中視圖文件中的 $this 指的是當前控制器,而在 Yii2.0中,指的是視圖本身。 要在視圖中訪問控制器,可以使用 $this->context 。這個 $this->context 是指誰調用了 yii\base\View::renderFile() 來渲染這個視圖。 一般是某個控制器,也可以是其他實現了 yii\base\ViewContextInterface 接口的對象。
同時,Yii1.1中的 CClientScript 也被淘汰了,相關的前端資源及其依賴關系的管理,交由Assert Bundle yii\web\AssertBundle 來專職處理。 一個Assert Bundle代表一系列的前端資源,這些前端資源以目錄形式進行管理,這樣顯得更有序。 更為重要的是,Yii1.1中需要你格外注意資源在HTML中的順序,比如CSS文件的順序(后面的會覆蓋前面的), JavaScript文件的順序(前后順序出錯會導致有的庫未加載)等。 而在Yii2.0中,使用一個Assert Bundle可以定義依賴于另外的一個或多個Assert Bundle的關系, 這樣在向HTML頁面注冊這些CSS或者JavaScript時,Yii2.0會自動把所依賴的文件先注冊上。
在視圖模版引擎方面,Yii2.0仍然使用PHP作為主要的模版語言。 同時官方提供了兩個擴展以支持當前兩大主流PHP模版引擎:Smarty和Twig,而對于Pardo引擎官方不再提供支持了。 當然,開發者可以通過設置 yii\web\View::$renderers 來使用其他模版。
另外,Yii1.1中,調用 $this->render('viewFile', ...) 是不需要使用 echo 命令的。 而Yii2.0中,記得 render() 只是返回視圖渲染結果,并不對直接顯示出來,需要自己調用 echo
echo $this->render('_item', ['item' => $item]);
如果有一天你發現怎么Yii輸出了個空白頁給你,就要注意是不是忘記使用 echo 了。 還別說,這個錯誤很常見,特別是在對Ajax請求作出響應時,會更難發現這一錯誤。請你們編程時留意。
在視圖的主題(Theme)化方面,Yii2.0的運作機理采用了完全不同的方式。 在Yii2.0中,使用路徑映射的方式,將一個源視圖文件路徑,映射成一個主題化后的視圖文件路徑。 因此, ['/web/views' => '/web/themes/basic'] 定義了一個主題映射關系, 源視圖文件 /web/views/site/index.php 主題化后將是 /web/themes/basic/site/index.php 。 因此, Yii1.1中的 CThemeManager 也被淘汰了。
模型(Model)
MVC中的M指的就是模型,Yii1.1中使用 CModel 來表示,而Yii2.0使用 yii\base\Model 來表示。
Yii1.1中, CFormModel 用來表示用戶的表單輸入,以區別于數據庫中的表。 這在Yii2.0中也被淘汰,Yii2.0傾向于使用繼承自 yii\base\Model 來表示提交的表單數據。
另外,Yii2.0為Model引入了 yii\base\Model::load() 和 yii\base\Model::loadMutiple() 兩個新的方法, 用于簡化將用戶輸入的表單數據賦值給Model:
? ?// Yii2.0使用load()等同于下面Yii1.1的用法$model = new Post;if ($model->load($_POST)) { ? ?... ...}// Yii1.1中常用的套路if (isset($_POST['Post'])) { ? ?$model->attributes = $_POST['Post'];} ? ?
另外一個重要變化就是Yii2.0中改變了Model應用于不同場景的邏輯。通過引入 yii\base\Model::scenarios() 來集中管理場景,使得一個Model所有適用的場景都比較清晰,一目了然。而Yii1.1是沒有一個統一管理場景的方法的。
由此帶來的一個很容易出現的問題就是,當你聲明一個Model處于某一場景時,可能由于拼寫錯誤, 不小心將場景的名稱寫錯了,那么在Yii1.1中,這個錯誤的場景并沒有任何的提示。假設有以下情況:
? ?class UserForm extends CFormModel{ ? ?public $username; ? ?public $email; ? ?public $password; ? ?public $password_repeat; ? ?public $rememberMe=false; ? ?public function rules() ? ?{ ? ? ? ?return array( ? ? ? ? ? ?// username 和 password 在所有場景中都要驗證 ? ? ? ? ? ?array('username, password', 'required'), ? ? ? ? ? ?// email 和 password_repeat 只在注冊場景中驗證 ? ? ? ? ? ?array('email, password_repeat', 'required', 'on'=>'Registration'), ? ? ? ? ? ?array('email', 'email', 'on'=>'Registration'), ? ? ? ? ? ?// rememberMe 僅在登陸場景中驗證 ? ? ? ? ? ?array('rememberMe', 'boolean', 'on'=>'Login'), ? ? ? ?); ? ?}} ? ?
這里針對UserForm的注冊和登陸兩個場景,設定了不同的驗證規則。接下來,你要在注冊場景中使用這個UserForm, 但你一不小心將 Registration 場景設定成了 SignUp , 說實在,我不是學英文出身的,這兩個單詞的意思在我眼里是一樣一樣的。只是Yii不會智能到把這兩個場景等同起來。 那么Yii1.1將不會有任何的提示,并自動地使用第一個驗證規則,而用戶注冊時填寫的 email 和 password_repeat 字段就被拋棄了。這在實際編程中,是經常出現的一個低級錯誤。
從這里可以看到,Yii1.1中對于場景,沒有一個集中統一的管理,也就是說一個Model可適用的場景, 是不確定的、任意的。通過 rules() 你很難一眼看出來一個Model可以適用于多少個場景,每個場景下都有哪些字段是有效的、需要驗證的。
而在Yii2.0中,由于引入了 yii\base\Model::scenarios() 新的方法, 將本Model所有適用的場景,及不同場景下的有效字段都進行了聲明, 這個邏輯就顯得清晰了。而且,如果使用了一個未聲明的場景,Yii2.0會有相應的提示, 這避免了上面這個低級錯誤的可能:
? ?namespace app\models;use yii\db\ActiveRecord;class User extends ActiveRecord{ ? ?public function scenarios() ? ?{ ? ? ? ?return [ ? ? ? ? ? ?'login' => ['username', 'password', 'rememberMe'], ? ? ? ? ? ?'registration' => ['username', 'email', 'password', 'password_repeat'], ? ? ? ?]; ? ?}} ? ?
這樣看來,是不是很清晰?這個User僅有兩種場景,每種場景的有效字段也一目了然。 而至于具體場景下每個字段的驗證規則,仍然由 yii\base\Model::rules() 來確定。 這也意味著, unsafe 驗證在Yii2.0中也沒有了立足之地,凡是 unsafe 的字段,就不在特定的場景中列出來。 或者為了更加明顯的表示某一字段在特定場景下是無效的,可以給這個字段加上 ! 前綴。
在默認情況下, yii\base\Model::scenarios() 所有適用的場景和對應的字段由 yii\base\Model::rules() 的內容自動生成。也就是說,如果你的 rules() 很完備、很清晰,那么也是不需要重載這個 scenarios() 的。 這種情況下,Yii1.1和Yii2.0在這一點上的表現形式,是一樣的。但是,個人經驗看, 我更傾向于將 scenarios() 聲明清楚,而在 rules() 中,僅指定字段的驗證規則,而不涉及場景的內容。 這樣的邏輯更加清晰,便于其他團隊成員閱讀你的代碼,也便于后續的維護和開發。
控制器(Controller)
除了上面講到的控制器中要使用 echo 來顯示渲染視圖的輸出這點區別外, Yii1.1與Yii2.0的控制器還表現出更為明顯的區別,那就是動作過濾器(Action Filter) 的不同。
在Yii2.0中,動作過濾器以行為(behavior)的方式出現, 一般繼承自 yii\base\ActionFilter ,并注入到一個控制器中,以發生作用。比如,Yii1.1中很常見的:
1 2 3 4 5 6 7 8 91011 ? ?public function behaviors(){ ? ?return [ ? ? ? ?'access' => [ ? ? ? ? ? ?'class' => 'yii\filters\AccessControl', ? ? ? ? ? ?'rules' => [ ? ? ? ? ? ? ? ?['allow' => true, 'actions' => ['admin'], 'roles' => ['@']], ? ? ? ? ? ?], ? ? ? ?], ? ?];} ? ?
看著是不是有點像,但又確實不一樣?
Active Record
還記得么?在Yii1.1中,數據庫查詢被分散成 CDbCommand , CDbCriteria 和 CDbCommandBuilder 。 所謂天下大勢分久必合,到了Yii2.0,采用 yii\db\Query 來表示數據庫查詢:
? ?$query = new \yii\db\Query();$query->select('id, name') ? ? ?->from('user') ? ? ?->limit(10);$command = $query->createCommand();$sql = $command->sql;$rows = $command->queryAll(); ? ?
最最最爽的是, yii\db\Query 可以在 Active Record中使用,而在Yii1.1中,要結合兩者,并不容易。
Active Record在Yii2.0中最大的變化一個是查詢的構建,另一個是關聯查詢的處理。
Yii1.1中的 CDbCriteria 在Yii2.0中被 yii\db\ActiveQuery 所取代, 這個把前輩拍死在沙灘上的家伙,繼承自 yii\db\Query ,所以可以進行類似上面代碼的查詢。 調用 yii\db\ActiveRecord::find() 就可以啟動查詢的構建了:
$customers = Customer::find() ? ?->where(['status' => $active]) ? ?->orderBy('id') ? ?->all();
這在Yii1.1中,是不容易實現的。特別是比較復雜的查詢關系。
在關聯查詢方面,Yii1.1是在一個統一的地方 relations() 定義關聯關系。 而Yii2.0改變了這一做法,定義一個關聯關系:
定義一個getter方法
g
轉自深入理解Yii2.0
大家都不在嗎
這個誰知道
Liuyang01
舉報
本教程代領大家學習YII如何提升程序運行效率以及開發效率
Copyright ? 2025 imooc.com All Rights Reserved | 京ICP備12003892號-11 京公網安備11010802030151號
購課補貼聯系客服咨詢優惠詳情
慕課網APP您的移動學習伙伴
掃描二維碼關注慕課網微信公眾號
2015-07-02
百度一下
2015-07-07
大致思路不會變,開發流程變化也不是很大。
有變化的是
1、yii2帶入的PHP5.4的特性,引入了namespace解決命名沖突,因此基類不會再C字開頭了
2、不再所有類都繼承自組件Component,而是選擇繼承object和component(也繼承自object,但帶有事件功能、以及用于擴展的Behavior功能)
3、更加的MVC,原先的view層其實基本算是controller直接include進來的,現在有了view的類用來控制,因此View層在使用Controller帶來的參數的方式稍有不同。
4、yii2分基本版(看上去和1差不多)和高級版(分前臺和后臺),高級版更加適合開發大型項目。
5、其他的都是細節方面的變化,比如塊賦值(基本用于收集表單數據)更加方便了。安裝完畢界面就自帶bootstrap風格了,等等等等。
當然還有許多其他的特性,可以直接參看yii在git上更新的文檔:
yii2/docs/guide/upgrade-from-v1.md at master 路 yiisoft/yii2 路 GitHub
--update--
1、加入了Dependency Injection(依賴注入,理論可以看經典翻譯文IoC容器和依賴注入模式(轉)-redcoffee-ChinaUnix博客,yii的具體實現看/vendor/yiisoft/yii2/di下的container和instance就行),以后創建對象時基本都可以用容器的get方法替代new了,很不錯很贊喲~
2015-07-05
自己不會百度下
這部分內容是專門為已經有Yii1.1基礎的讀者朋友寫的。將Yii2.0與Yii1.1的不同點著重寫出來,對比學起來會快得多。 而對于從未接觸過Yii的讀者朋友,這部分內容掃一掃就可以了,作為對過往歷史的一個了解就夠了。 如果有的內容你一時沒看明白,也不要緊,本書的正文部分會講清楚的。 另外,沒有Yii1.1的經驗,并不妨礙對Yii2.0的學習。
Yii官方有專門的文檔歸納總結1.1版本和2.0版本的不同。以下內容,主要來自于官方的文檔,我做了下精簡, 選擇比較重要的變化,并加入了一些個人的經驗。
PHP新特性
從對PHP新特性的使用上,兩者就存在很大不同。Yii2.0大量使用了PHP的新特性,這在Yii1.1中是沒有的。因此,Yii2.0對于PHP的版本要求更高,要求PHP5.4及以上。Yii2.0中使用到的PHP新特性,主要有:
命名空間(Namespace)
匿名函數
數組短語法形式: [1,2,3] 取代 array(1,2,3) 。這在多維數組、嵌套數組中,代碼更清晰、簡短。
在視圖文件中使用PHP的 <?= 標簽,取代 echo 語句。
標準PHP庫(SPL) 類和接口,具體可以查看 SPL Class and Interface
延遲靜態綁定, 具體可以查看 Late Static Bindings
PHP標準日期時間
特性(Traits)
使用PHP intl 擴展實現國際化支持, 具體可以查看 PECL init 。
了解Yii2.0使用了PHP的新特性,可以避免開發時由于環境不當,特別是開發生產環境切換時,產生莫名其妙的錯誤。 同時,也是讓讀者朋友借機學習PHP新知識的意思。
命名空間(Namespace)
Yii2.0與Yii1.1之間最顯著的不同是對于PHP命名空間的使用。Yii1.1中沒有命名空間一說, 為避免Yii核心類與用戶自定義類的命名沖突,所有的Yii核心類的命名,均冠以 C 前綴,以示區別。
而Yii2.0中所有核心類都使用了命名空間,因此, C 前綴也就人老珠黃,退出歷史舞臺了。
命名空間與實際路徑相關聯,比如 yii\base\Object 對應Yii目錄下的 base/Object.php 文件。
基礎類
Yii1.1中使用了一個基礎類 CComponent ,提供了屬性支持等基本功能,因此幾乎所有的Yii核心類都派生自該類。 到了Yii2.0,將一家獨大的 CComponent 進行了拆分。拆分成了 yii\base\Object 和 yii\base\Component 。 拆分的考慮主要是 CComponent 尾大不掉,有影響性能之嫌。 于是,Yii2.0中,把 yii\base\Object 定位于只需要屬性支持,無需事件、行為。 而 yii\base\Component 則在前者的基礎上,加入對于事件和行為的支持。 這樣,開發者可以根據需要,選擇繼承自哪基礎類。
這一功能上的明確劃分,帶來了效率上的提升。在僅表示基礎數據結構,而非反映客觀事物的情況下, yii\base\Object 比較適用。
值得一提的是, yii\base\Object 與 yii\base\Component 兩者并不是同一層級的,前者是后者他爹。
事件(Event)
在Yii1.1中,通過一個 on 前綴的方法來創建事件,比如 CActiveRecord 中的 onBeforeSave() 。 在Yii2.0中,可以任意定義事件的名稱,并自己觸發它:
? ?$event = new \yii\base\Event;// 使用 trigger() 觸發事件$component->trigger($eventName, $event);// 使用 on() 前事件handler與對象綁定$component->on($eventName, $handler);// 使用 off() 解除綁定$component->off($eventName, $handler);
? ?
別名(Alias)
Yii2.0中改變了Yii1.1中別名的使用形式,并擴大了別名的范疇。 Yii1.1中,別名以 . 的形式使用:
RootAlias.path.to.target
而在Yii2.0中,別名以 @ 前綴的方式使用:
@yii/jui
另外,Yii2.0中,不僅有路徑別名,還有URL別名:
? ?// 路徑別名Yii::setAlias('@foo', '/path/to/foo');// URL別名Yii::setAlias('@bar', 'http://www.example.com');
? ?
別名與命名空間是緊密相關的,Yii建議為所有根命名空間都定義一個別名,比如上面提到的 yii\base\Object , 事實上是定義了 @yii 的別名,表示Yii在系統中的安裝路徑。 這樣一來,Yii就能根據命名空間找到實際的類文件所在路徑,并自動加載。這一點上,Yii2.0與Yii1.1并沒有本質區別。
而如果沒有為根命名空間定義別名,則需要進行額外的配置。將命名空間與實際路徑的映射關系,告知Yii。
關于別名的更詳細內容請看 別名(Alias) 。
視圖(View)
Yii1.1中,MVC(model-view-controller)中的視圖一直是依賴于Controller的,并非是真正意義上獨立的View。 Yii2.0引入了 yii\web\View 類,使得View完全獨立。這也是一個相當重要變化。
首先,Yii2.0中,View作為Application的一個組件,可以在全局中代碼中進行訪問。 因此,視圖渲染代碼不必再局限于Controller中或Widget中。
其次,Yii1.1中視圖文件中的 $this 指的是當前控制器,而在 Yii2.0中,指的是視圖本身。 要在視圖中訪問控制器,可以使用 $this->context 。這個 $this->context 是指誰調用了 yii\base\View::renderFile() 來渲染這個視圖。 一般是某個控制器,也可以是其他實現了 yii\base\ViewContextInterface 接口的對象。
同時,Yii1.1中的 CClientScript 也被淘汰了,相關的前端資源及其依賴關系的管理,交由Assert Bundle yii\web\AssertBundle 來專職處理。 一個Assert Bundle代表一系列的前端資源,這些前端資源以目錄形式進行管理,這樣顯得更有序。 更為重要的是,Yii1.1中需要你格外注意資源在HTML中的順序,比如CSS文件的順序(后面的會覆蓋前面的), JavaScript文件的順序(前后順序出錯會導致有的庫未加載)等。 而在Yii2.0中,使用一個Assert Bundle可以定義依賴于另外的一個或多個Assert Bundle的關系, 這樣在向HTML頁面注冊這些CSS或者JavaScript時,Yii2.0會自動把所依賴的文件先注冊上。
在視圖模版引擎方面,Yii2.0仍然使用PHP作為主要的模版語言。 同時官方提供了兩個擴展以支持當前兩大主流PHP模版引擎:Smarty和Twig,而對于Pardo引擎官方不再提供支持了。 當然,開發者可以通過設置 yii\web\View::$renderers 來使用其他模版。
另外,Yii1.1中,調用 $this->render('viewFile', ...) 是不需要使用 echo 命令的。 而Yii2.0中,記得 render() 只是返回視圖渲染結果,并不對直接顯示出來,需要自己調用 echo
echo $this->render('_item', ['item' => $item]);
如果有一天你發現怎么Yii輸出了個空白頁給你,就要注意是不是忘記使用 echo 了。 還別說,這個錯誤很常見,特別是在對Ajax請求作出響應時,會更難發現這一錯誤。請你們編程時留意。
在視圖的主題(Theme)化方面,Yii2.0的運作機理采用了完全不同的方式。 在Yii2.0中,使用路徑映射的方式,將一個源視圖文件路徑,映射成一個主題化后的視圖文件路徑。 因此, ['/web/views' => '/web/themes/basic'] 定義了一個主題映射關系, 源視圖文件 /web/views/site/index.php 主題化后將是 /web/themes/basic/site/index.php 。 因此, Yii1.1中的 CThemeManager 也被淘汰了。
模型(Model)
MVC中的M指的就是模型,Yii1.1中使用 CModel 來表示,而Yii2.0使用 yii\base\Model 來表示。
Yii1.1中, CFormModel 用來表示用戶的表單輸入,以區別于數據庫中的表。 這在Yii2.0中也被淘汰,Yii2.0傾向于使用繼承自 yii\base\Model 來表示提交的表單數據。
另外,Yii2.0為Model引入了 yii\base\Model::load() 和 yii\base\Model::loadMutiple() 兩個新的方法, 用于簡化將用戶輸入的表單數據賦值給Model:
? ?// Yii2.0使用load()等同于下面Yii1.1的用法$model = new Post;if ($model->load($_POST)) {
? ?... ...}// Yii1.1中常用的套路if (isset($_POST['Post'])) {
? ?$model->attributes = $_POST['Post'];}
? ?
另外一個重要變化就是Yii2.0中改變了Model應用于不同場景的邏輯。通過引入 yii\base\Model::scenarios() 來集中管理場景,使得一個Model所有適用的場景都比較清晰,一目了然。而Yii1.1是沒有一個統一管理場景的方法的。
由此帶來的一個很容易出現的問題就是,當你聲明一個Model處于某一場景時,可能由于拼寫錯誤, 不小心將場景的名稱寫錯了,那么在Yii1.1中,這個錯誤的場景并沒有任何的提示。假設有以下情況:
? ?class UserForm extends CFormModel{
? ?public $username;
? ?public $email;
? ?public $password;
? ?public $password_repeat;
? ?public $rememberMe=false;
? ?public function rules()
? ?{
? ? ? ?return array(
? ? ? ? ? ?// username 和 password 在所有場景中都要驗證
? ? ? ? ? ?array('username, password', 'required'),
? ? ? ? ? ?// email 和 password_repeat 只在注冊場景中驗證
? ? ? ? ? ?array('email, password_repeat', 'required', 'on'=>'Registration'),
? ? ? ? ? ?array('email', 'email', 'on'=>'Registration'),
? ? ? ? ? ?// rememberMe 僅在登陸場景中驗證
? ? ? ? ? ?array('rememberMe', 'boolean', 'on'=>'Login'),
? ? ? ?);
? ?}}
? ?
這里針對UserForm的注冊和登陸兩個場景,設定了不同的驗證規則。接下來,你要在注冊場景中使用這個UserForm, 但你一不小心將 Registration 場景設定成了 SignUp , 說實在,我不是學英文出身的,這兩個單詞的意思在我眼里是一樣一樣的。只是Yii不會智能到把這兩個場景等同起來。 那么Yii1.1將不會有任何的提示,并自動地使用第一個驗證規則,而用戶注冊時填寫的 email 和 password_repeat 字段就被拋棄了。這在實際編程中,是經常出現的一個低級錯誤。
從這里可以看到,Yii1.1中對于場景,沒有一個集中統一的管理,也就是說一個Model可適用的場景, 是不確定的、任意的。通過 rules() 你很難一眼看出來一個Model可以適用于多少個場景,每個場景下都有哪些字段是有效的、需要驗證的。
而在Yii2.0中,由于引入了 yii\base\Model::scenarios() 新的方法, 將本Model所有適用的場景,及不同場景下的有效字段都進行了聲明, 這個邏輯就顯得清晰了。而且,如果使用了一個未聲明的場景,Yii2.0會有相應的提示, 這避免了上面這個低級錯誤的可能:
? ?namespace app\models;use yii\db\ActiveRecord;class User extends ActiveRecord{
? ?public function scenarios()
? ?{
? ? ? ?return [
? ? ? ? ? ?'login' => ['username', 'password', 'rememberMe'],
? ? ? ? ? ?'registration' => ['username', 'email', 'password', 'password_repeat'],
? ? ? ?];
? ?}}
? ?
這樣看來,是不是很清晰?這個User僅有兩種場景,每種場景的有效字段也一目了然。 而至于具體場景下每個字段的驗證規則,仍然由 yii\base\Model::rules() 來確定。 這也意味著, unsafe 驗證在Yii2.0中也沒有了立足之地,凡是 unsafe 的字段,就不在特定的場景中列出來。 或者為了更加明顯的表示某一字段在特定場景下是無效的,可以給這個字段加上 ! 前綴。
在默認情況下, yii\base\Model::scenarios() 所有適用的場景和對應的字段由 yii\base\Model::rules() 的內容自動生成。也就是說,如果你的 rules() 很完備、很清晰,那么也是不需要重載這個 scenarios() 的。 這種情況下,Yii1.1和Yii2.0在這一點上的表現形式,是一樣的。但是,個人經驗看, 我更傾向于將 scenarios() 聲明清楚,而在 rules() 中,僅指定字段的驗證規則,而不涉及場景的內容。 這樣的邏輯更加清晰,便于其他團隊成員閱讀你的代碼,也便于后續的維護和開發。
控制器(Controller)
除了上面講到的控制器中要使用 echo 來顯示渲染視圖的輸出這點區別外, Yii1.1與Yii2.0的控制器還表現出更為明顯的區別,那就是動作過濾器(Action Filter) 的不同。
在Yii2.0中,動作過濾器以行為(behavior)的方式出現, 一般繼承自 yii\base\ActionFilter ,并注入到一個控制器中,以發生作用。比如,Yii1.1中很常見的:
1
2
3
4
5
6
7
8
9
10
11
? ?public function behaviors(){
? ?return [
? ? ? ?'access' => [
? ? ? ? ? ?'class' => 'yii\filters\AccessControl',
? ? ? ? ? ?'rules' => [
? ? ? ? ? ? ? ?['allow' => true, 'actions' => ['admin'], 'roles' => ['@']],
? ? ? ? ? ?],
? ? ? ?],
? ?];}
? ?
看著是不是有點像,但又確實不一樣?
Active Record
還記得么?在Yii1.1中,數據庫查詢被分散成 CDbCommand , CDbCriteria 和 CDbCommandBuilder 。 所謂天下大勢分久必合,到了Yii2.0,采用 yii\db\Query 來表示數據庫查詢:
? ?$query = new \yii\db\Query();$query->select('id, name')
? ? ?->from('user')
? ? ?->limit(10);$command = $query->createCommand();$sql = $command->sql;$rows = $command->queryAll();
? ?
最最最爽的是, yii\db\Query 可以在 Active Record中使用,而在Yii1.1中,要結合兩者,并不容易。
Active Record在Yii2.0中最大的變化一個是查詢的構建,另一個是關聯查詢的處理。
Yii1.1中的 CDbCriteria 在Yii2.0中被 yii\db\ActiveQuery 所取代, 這個把前輩拍死在沙灘上的家伙,繼承自 yii\db\Query ,所以可以進行類似上面代碼的查詢。 調用 yii\db\ActiveRecord::find() 就可以啟動查詢的構建了:
$customers = Customer::find()
? ?->where(['status' => $active])
? ?->orderBy('id')
? ?->all();
這在Yii1.1中,是不容易實現的。特別是比較復雜的查詢關系。
在關聯查詢方面,Yii1.1是在一個統一的地方 relations() 定義關聯關系。 而Yii2.0改變了這一做法,定義一個關聯關系:
定義一個getter方法
g
轉自深入理解Yii2.0
2015-07-02
大家都不在嗎
2015-07-02
這個誰知道