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