ThinkPHP控制器學(xué)習(xí)(一)

星空

多層控制器的使用

TP3.23對控制器做了更加細(xì)致的分層,除了默認(rèn)的Controller層吹泡,還可以自定義事件控制層Event

建立的方法是:

  • 在模塊第一級目錄揭朝,即Controller層的同級目錄潭袱,新建文件夾Event
  • Event文件夾中屯换,新建文件 AdminEvent.class.php
  • 在新建文件中輸入代碼
namespace Admin\Event;
// use Think\Controller;  
// 如果不使用到controller的功能 
// 可以不用添加該命名空間引用 也不用繼承controller
class AdminEvent extents Controller {
    public function test() {
        echo 'Hello World !';
    }
}

系統(tǒng)默認(rèn)的控制器(即訪問控制器)是Controller嘉抓,因此在瀏覽器輸入http://localhost/forum/index.php/Admin/admin/test是無法進(jìn)行訪問的抑片,Event控制器僅在內(nèi)部方法方法中進(jìn)行訪問。當(dāng)然可以通過DEFAULT_C_LAYER來修改訪問控制器的名稱疾牲。但建議不這么做鸥跟。

定義了事件控制器,對系統(tǒng)模塊的構(gòu)建有很大的好處枫匾∏从牵可以將瀏覽器的請求與內(nèi)部事件處理相隔離沾谓,使整個業(yè)務(wù)邏輯看上去更為簡潔明了均驶。

如一個后臺系統(tǒng),有多個頁面腾它,都需要對用戶是否登錄進(jìn)行檢測瞒滴,如果這個檢測都在Controller進(jìn)行的話妓忍,整個業(yè)務(wù)邏輯會顯得很混亂,而且可能會有代碼冗余碘举。
這時可以通過Event事件控制器來定義一個檢測方法引颈,然后在Controller層進(jìn)行調(diào)用,這樣代碼不僅更為簡練售滤,業(yè)務(wù)邏輯也更為清晰完箩。

Event控制器

namespace Admin\Event;
use Think\Controller;      
class AdminEvent extents Controller {
    /**
     *  登錄檢測  檢測session中用戶
     *  @param    類型    參數(shù)名 含義
     *  @return 類型  
     */
    function checkLogin() {
        $value = session('UserName');
        if(!isset($value)) {
            $this->error('請登錄后訪問' , U('admin/login'));
        }
    }
}

Controller控制器

namespace Admin\Controller;
use Think\Controller;
class AdminController extends Controller {

    /** 
     *  后臺首頁面
     */
    public function index(){

        A('Admin' , 'Event')->checkLogin();
        
        $this->assign('title','后臺');   
        $this->display();   
    }

    /**
     -  文章顯示控制
     -  @param  
     -  @return 
     */
    public function article() {
         
        A('Admin' , 'Event')->checkLogin();

        $this->assign('title','文章-后臺');             
        $this->display();
    }
}

這樣無論是從那種鏈接登入后臺粱快,都會進(jìn)行用戶檢測事哭,不僅提高了安全性降盹,而且代碼邏輯清晰澎现。

我們可以將數(shù)據(jù)庫添加操作在Event控制器中完成,在Controller控制器只進(jìn)行模板輸出妹蔽,接受表單提交胳岂。
以上乳丰。

初始化操作

Think\Controller.class.php的構(gòu)造方法中進(jìn)行視圖類實(shí)例化后汞斧,會檢測是否存在一個_initialize方法粘勒。如果存在庙睡,就會事先調(diào)用該方法。

這就是控制器的初始化操作雕擂。在控制器類中定義_initialize方法暂刘,在操作其他方法之前都會先執(zhí)行該方法。

如:

namespace Admin\Controller;
use Think\Controller;
class AdminController extends Controller {

    # 初始化操作
    public function _initialize() {
        echo '頁面初始化捂刺,請等待<br/>';
    }

    # 主頁
    public function index() {
        echo 'index';
    }
}

在瀏覽器輸入http://localhost/forum/index.php/Admin,則會輸出

頁面初始化募寨,請等待
index

有了這個方法族展,我們上面所講的登錄檢測就能夠再次進(jìn)行簡化了。即在_initialize方法中進(jìn)行是否登錄的檢測拔鹰。但在_initialize添加了登錄檢測后仪缸,我們不能夠?qū)⑴c登錄有關(guān)的內(nèi)容放入AdminController控制器中了,否則會不停的跳轉(zhuǎn)到error頁面恰画,而無法顯示登陸頁面。

我們可以將登錄注冊同時拿出焕妙,新建一個控制器,名字叫UserController果复。在這個頁面進(jìn)行登陸與注冊功能私植,而error頁面跳轉(zhuǎn)到該頁面。

UserController

namespace Admin\Controller;
use Think\Controller;
class UserController extends Controller {
    
    /**
     *  用戶登錄
     */
     public function login() {
        echo '用戶登錄';
     }

    /**
     *  用戶注冊
     */
    public function register() {
        echo '用戶注冊';
    }
}   

AdminController

namespace Admin\Controller;
use Think\Controller;
class AdminController extends Controller {

    # 初始化操作
    public function _initialize() {
        A('Admin' , 'Event')->checkLogin();
    }

    /** 
     *  后臺首頁面
     */
    public function index(){           
        
        $this->assign('title','后臺');   
        $this->display();   
    }

    /**
     -  文章顯示控制
     -  @param  
     -  @return 
     */
    public function article() {            

        $this->assign('title','文章-后臺');             
        $this->display();
    }
}

AdminEvent

namespace Admin\Event;
use Think\Controller;      
class AdminEvent extents Controller {
    /**
     *  登錄檢測  檢測session中用戶
     *  @param    類型    參數(shù)名 含義
     *  @return 類型  
     */
    function checkLogin() {
        $value = session('UserName');
        if(!isset($value)) {
            $this->error('請登錄后訪問' , U('user/login'));
        }
    }
}

這樣一個比較完善的后臺登陸就完成了(當(dāng)然還未實(shí)現(xiàn)具體的業(yè)務(wù)邏輯)逆趋,比較最原始的方法惠窄,代碼簡潔清晰了很多蒋腮,也完全符合MVC設(shè)計思想。

前置與后置

與初始化設(shè)置類似浙踢,TP提供了前置與后置操作,要進(jìn)行前后置操作需要真實(shí)的方法蓝翰,系統(tǒng)在執(zhí)行該方法前會進(jìn)行檢測,如果定義了前后置操作蚓挤,則會安照順序進(jìn)行。定義的方法是在執(zhí)行方法前加入_before__after_,如

namespace Admin\Controller;
use Think\Controller;
class AdminController extends Controller {
    public function _before_index() {}
    public function index() {}
    public function _after_index() {}
}

在訪問http://localhost/forum/index.php/Admin的時候化漆,就會先執(zhí)行_before_index座云,在執(zhí)行index,最后執(zhí)行_after_index锣夹。注意的是如果在index中定義了斷點(diǎn)方法链患,如die婉宰,exit歌豺,跳轉(zhuǎn)方法errorsuccess就不會繼續(xù)執(zhí)行_after_index心包。

這個前后置方法类咧,我暫時還未想到有什么比較有用的地方,先寫出來蟹腾,以后想到了痕惋,在進(jìn)行添加。

空操作與空控制器

按照ThinkPHPURL命名規(guī)則(pathinfo模式)娃殖,入口文件之后的操作成為

模塊
控制器
操作

http://servername/index.php/模塊/控制器/操作/[參數(shù)名/參數(shù)值…]

空操作
就是指系統(tǒng)找不到url指定的操作方法值戳,此時就會報錯,可以使用定義空操作方法來進(jìn)行避免炉爆。如:

namespace Admin\Controller;
use Think\Controller;
class AdminController extends Controller {

    /** 
     *  后臺首頁面
     */
    public function index(){           
        
        $this->assign('title','后臺');   
        $this->display();   
    }
    
    /**
     -  空操作防止
     -  @param    無
     -  @return   無   
     */
    public function _empty() {
        $this->display('404');
    }
}

定義后堕虹,在輸入錯誤的操作方法時,就會顯示_empty中的內(nèi)容芬首。你可以定義一個404頁面赴捞,在_empty中進(jìn)行跳轉(zhuǎn)。

空控制器

與空操作類似衩辟,訪問不存在的控制器就會產(chǎn)生空控制器操作,避免該錯誤的方法是波附,在Controller中定義一個EmptyController控制器艺晴,在該控制器中同樣定義_empty方法昼钻。

namespace Admin\Controller;
use Think\Controller;
class EmptyController extends Controller {
       
    /**
     -    空操作防止
     -    @param    無
     -    @return   無   
     */
    public function _empty() {
         $this->display('admin/404');
    }
}

404頁面
對于404頁面的定制,如果沒有特殊需求的同學(xué)封寞,建議使用騰訊的404公益頁面然评,只要嵌入一小段JS代碼,就會跳轉(zhuǎn)到騰訊的尋找失蹤兒童的404頁面狈究。雖然可能和你的網(wǎng)站風(fēng)格不統(tǒng)一碗淌,但是每多一個看見該頁面的人,就可能加大找回一個失蹤兒童的幾率抖锥。一小段代碼亿眠,獻(xiàn)出一段愛心,你值得擁有磅废。

// 騰訊404頁面
<script type="text/javascript" src="http://www.qq.com/404/search_children.js" charset="utf-8" homePageUrl="http://yoursite.com/yourPage.html" homePageName="回到我的主頁"></script>
20160529162719.png

Action參數(shù)綁定

在說Action參數(shù)綁定前纳像,先說說與之相關(guān)的問題。在學(xué)習(xí)Action參數(shù)綁定之前拯勉,我獲取GET參數(shù)的方式是怎么樣竟趾?
自然是利用$_GET來獲取URL上的參數(shù),如:

# 我要點(diǎn)擊一個文章鏈接宫峦,來進(jìn)行文章編輯 url如下
http://localhost/forum/index.php/Admin/admin/article/act/edit/aid/2
# 然后通過$_GET來獲取act aid得到參數(shù)岔帽,來判斷進(jìn)行的操作以及操作的文章id
if($_GET['act'] == 'edit') {
    # 文章編輯  利用 aid從數(shù)據(jù)庫取出文章進(jìn)行編輯
}

這種方式雖然可行,卻不夠優(yōu)雅导绷,作為一個立志成為攻城獅的程序員來說犀勒,要想盡方法使你的代碼更加簡潔,更加優(yōu)雅诵次。

這時來看看Action參數(shù)綁定账蓉,什么是Action參數(shù)綁定

Action參數(shù)綁定是通過直接綁定URL地址中的變量作為操作方法的參數(shù)逾一, 可以簡化方法的定義甚至路由的解析铸本。

說的還挺繞,其實(shí)就是把GET形式傳遞的參數(shù)直接綁定到你的操作方法上遵堵,你就能夠直接訪問箱玷,而不用通過$_GET
舉個例子陌宿,還是上面的鏈接http://localhost/forum/index.php/Admin/admin/article/act/edit/aid/2锡足。
定義操作方法如下:

namespace Admin\Controller;
use Think\Controller;
class AdminController extends Controller {

    /** 
     *  文章顯示控制器
     *  @param:$act   string   進(jìn)行的文章操作  默認(rèn)值空 -> 顯示所有文章
     *  @param:$aid   int      文章的主鍵id    默認(rèn)值0  -> 顯示所有文章
     */
    public function article($act='' , $aid = 0) {
        
        if(empty($act) || empty($aid) ) {

            # 顯示所有文章

        } else {
            
            # 進(jìn)行想要的操作
            echo '你要進(jìn)行的操作是'.$act.',你想要'.$act.'的文章id是'.$aid;

        }
    }
}

訪問上面的鏈接壳坪,結(jié)果為

你要進(jìn)行的操作是edit舶得,你想要edit的文章id是2

這就是Action參數(shù)綁定。要使用這種方式需要開啟URL_PARAMS_BIND設(shè)置(默認(rèn)設(shè)置true)爽蝴。

Action參數(shù)綁定有兩種形式

按照變量名綁定
按照變量順序綁定

URL_PARAMS_BIND_TYPE的值設(shè)置成0沐批,按照變量名綁定译红,設(shè)置成1米丘,按照變量順序綁定月帝。

按照字面意思也可以理解阱扬,按照變量名綁定即尋找get參數(shù)時,按照操作方法中定義的變量名去尋找相應(yīng)的值躺彬。如果沒有就報錯煤墙。這也是最常用的方式。

按照變量順序綁定宪拥,即按照url上get參數(shù)的順序去給操作方法上的變量賦值仿野,這樣在url上的參數(shù)就能夠隨意變換位置,同時url上get參數(shù)也可以隱藏變量名江解。

舉例說明一下:

按照變量名綁定
鏈接 http://localhost/forum/index.php/Admin/admin/article/act/edit/aid/2 那么打印出來的結(jié)果

你要進(jìn)行的操作是edit设预,你想要edit的文章id是2

鏈接 http://localhost/forum/index.php/Admin/admin/article/aid/2/act/edit 那么打印出來的結(jié)果

你要進(jìn)行的操作是edit,你想要edit的文章id是2

可以看出無論怎么變換位置犁河,得到的結(jié)果是一樣的鳖枕。

按照變量順序綁定
鏈接 http://localhost/forum/index.php/Admin/admin/article/edit/2 那么打印出來的結(jié)果

你要進(jìn)行的操作是edit,你想要edit的文章id是2

鏈接 http://localhost/forum/index.php/Admin/admin/article/2/edit 那么打印出來的結(jié)果

你要進(jìn)行的操作是2桨螺,你想要edit的文章id是edit

因此如果采用變量順序綁定時宾符,一定要確保url上的get參數(shù)順序與操作方法上的參數(shù)順序一致。

值得注意的是按照變量名綁定僅對類似于pathinfo方式的地址有效灭翔。如pathinfo模式兼容模式魏烫。

偽靜態(tài)

偽靜態(tài)是相對于靜態(tài)頁面來說的,主要是為了更好的SEO效果肝箱,并不是真正的靜態(tài)哄褒,而是在URL的結(jié)尾添加了類似htmlhtm等的后綴煌张。在TP中默認(rèn)是開啟偽靜態(tài)的呐赡。可以通過URL_HTML_SUFFIX來設(shè)置靜態(tài)的后綴名骏融,如:

'URL_HTML_SUFFIX'=>'shtml'

訪問:

http://localhost/forum/index.php/Admin/admin/article/2/edit.shtml 

就是有效的链嘀,而訪問.html則會報錯。也可以設(shè)置多個靜態(tài)后綴档玻,使用**|**來進(jìn)行分割怀泊。

// 多個偽靜態(tài)后綴設(shè)置 用|分割
'URL_HTML_SUFFIX' => 'html|shtml|htm' 

也可以對某些后綴進(jìn)行禁止訪問,利用URL_DENY_SUFFIX

'URL_HTML_SUFFIX' => 'html' 

設(shè)置后就不能訪問任何以html為后綴的url误趴∨恚可以將URL的模式改成rewrite模式來配合偽靜態(tài),否則一個鏈接上既有.php,也有.html看上去很別扭枣申。

注意:使用偽靜態(tài)模式必須開啟httpd.confmod_rewrite.so模塊树灶。

rewire模式切換

開啟rewrite模式需要配合修改apache的重寫內(nèi)容。

打開httpd.conf文件糯而,搜索mod_rewrite.so,將該模塊前面的#刪除泊窘。然后新建.htaccess熄驼,放入如下代碼:

<IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>

保存到項(xiàng)目入口文件同級目錄。重啟apache即可烘豹。

apache的部分重寫規(guī)則

實(shí)現(xiàn)偽靜態(tài)多數(shù)是利用apache的URL重寫規(guī)則(RewriteRule)瓜贾,我不是很懂RewriteRule,只是從網(wǎng)上找來了一些資料携悯。
上述代碼中祭芦,RewriteEngine表示是否開啟重寫引擎,RewriteCond重寫應(yīng)用條件憔鬼,RewriteRule表示重寫規(guī)則龟劲。從代碼中明顯看出,利用了正則表達(dá)式的功能轴或。

正則表達(dá)式含義

表達(dá)式 含義 表達(dá)式 含義
昌跌? 0-1個字符 $ 段落結(jié)束字符
. 1個字符 \ 轉(zhuǎn)移字符
* 0-x個字符 取反
+ 1-x個字符 () 內(nèi)存限定傳值
^ 段落開始字符 [0-9] 所有數(shù)字字符
[a-z] 所有小寫字母 [A-Z] 所有大寫字母
{n} 重復(fù)n次 {n,} 重復(fù)n次或更多次
{n,m} 重復(fù)n到m次

在被匹配的字符串中$N表示與表達(dá)式中第一個()進(jìn)行匹配照雁,上述代碼中RewriteRule中的$1就表示與表達(dá)式中的第一個()進(jìn)行匹配蚕愤,這樣所有index.php/都會被其他字符或空字符匹配。

RewriteRule我確實(shí)不怎么懂饺蚊,網(wǎng)上的資料也很亂萍诱,就不多寫了,英語好的同學(xué)去看官方文檔吧污呼。

總結(jié)

今天關(guān)于控制器的學(xué)習(xí)就寫到這里裕坊,還有很多想要說的,但沒必要都一一贅述曙求。下次會將閱讀源碼的一些想法寫出來碍庵。最后想吐槽一下,簡書關(guān)于PHP的程序員好像很少悟狱,每次找很長時間才能看見一篇關(guān)于PHP的静浴,醉了醉了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挤渐,一起剝皮案震驚了整個濱河市苹享,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖得问,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件囤攀,死亡現(xiàn)場離奇詭異,居然都是意外死亡宫纬,警方通過查閱死者的電腦和手機(jī)焚挠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來漓骚,“玉大人蝌衔,你說我怎么就攤上這事◎蝓澹” “怎么了噩斟?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長孤个。 經(jīng)常有香客問我剃允,道長,這世上最難降的妖魔是什么齐鲤? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任斥废,我火速辦了婚禮,結(jié)果婚禮上给郊,老公的妹妹穿的比我還像新娘营袜。我一直安慰自己,他們只是感情好丑罪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布荚板。 她就那樣靜靜地躺著,像睡著了一般吩屹。 火紅的嫁衣襯著肌膚如雪跪另。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天煤搜,我揣著相機(jī)與錄音免绿,去河邊找鬼。 笑死擦盾,一個胖子當(dāng)著我的面吹牛嘲驾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播迹卢,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辽故,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了腐碱?” 一聲冷哼從身側(cè)響起誊垢,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后喂走,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體殃饿,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年芋肠,在試婚紗的時候發(fā)現(xiàn)自己被綠了乎芳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡帖池,死狀恐怖秒咐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碘裕,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布攒钳,位于F島的核電站帮孔,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏不撑。R本人自食惡果不足惜文兢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望焕檬。 院中可真熱鬧姆坚,春花似錦、人聲如沸实愚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腊敲。三九已至击喂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碰辅,已是汗流浹背懂昂。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留没宾,地道東北人凌彬。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像循衰,于是被迫代替她去往敵國和親铲敛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容