1. 程式人生 > >寫一個屬於自己的PHP的MVC框架(二)

寫一個屬於自己的PHP的MVC框架(二)

第一篇文章已經把所需的目錄搭建好了,接下來的工作就是寫一些程式碼了


用編輯器開啟public/index.php檔案,寫上下面的程式碼


<?php

    define(DS, DIRECTORY_SEPARATOR);
    define(ROOT, dirname(dirname(__FILE__)));
    
    $url = $_GET['url'];
    
    // 載入引導
    require_once( ROOT . DS . 'core' . DS . 'bootstrap.php' );
    
    
    

入口檔案的程式碼很簡潔,其中$url是個全域性變數,用來獲取當做請求的引數

現在先把載入引導的那句註釋掉,然後在下面echo $url,即

//require_once( ROOT . DS . 'core' . DS . 'bootstrap.php' );

echo $url;

然後在瀏覽器位址列輸入http://localhost/wudicsmvc/

注:D:\AppServ\www\wudicsmvc

然後,你會發現,啥也沒顯示。


接著輸入http://localhost/wudicsmvc/wudics

就會發現網頁打出wudics這幾個字


說明可以正常獲取url引數了,這個作為一個全域性變數存在,主要用來獲取客戶端的請求

如訪問哪個控制器的哪個方法

http://localhost/wudicsmvc/home/index

可以這樣規定,訪問home控制器的index方法,當然你也可以有不同的規定,也就是路由規則,據說是mvc一個很重要的概念


index.php檔案沒有啥內容,載入了一個bootstrap.php檔案,開啟core目錄下的bootstrap.php檔案:

<?php
    // 載入配置
    require_once(ROOT . DS . 'cfg' . DS . 'config.php');
    
    // 路由請求
    require_once(ROOT . DS . 'core' . DS . 'route.php');

同樣載入了兩個檔案,一個是cfg目錄下的config.php,一個是core目錄下的route.php


看下config.php

<?php

    // mysql連線引數
    define('DB_HOST', 'localhost');
    define('DB_USER', 'root');
    define('DB_PASS', '123456');
    define('DB_NAME', 'transdb');
    
    // smarty的一些常量
    define('DIR_TPL', ROOT . DS . 'app' . DS . 'view' . DS . 'template_dir' . DS . 'default' . DS);
    define('DIR_CPL', ROOT . DS . 'app' . DS . 'view' . DS . 'compile_dir' . DS);
    define('DIR_CFG', ROOT . DS . 'app' . DS . 'view' . DS . 'config_dir' . DS);
    define('DIR_CAC', ROOT . DS . 'app' . DS . 'view' . DS . 'cache_dir' . DS);
    
    // 預設控制類方法
    $default['controller'] = 'home';
    $default['action'] = 'index';
    
    // pulibc資料夾的路徑,方便模板設計
    define('WEBSITE', 'http://localhost');
    define('WEBIMG', WEBSITE . dirname(dirname($_SERVER['PHP_SELF'])) . '/public/img/');

一些常量和全域性變數,這個很有用,因為常量和全域性變數在單一入口php程式裡都是共享的資源


然後是route.php檔案

<?php


    function callHook()
    {
        global $url;
        global $default;
        
        // Get the $controller $action $param
        $param = array();
        
        $urlArr = explode("/", rtrim($url, "/"));
        $controller = array_shift($urlArr);
        $action = array_shift($urlArr);
        $param = $urlArr;
        
        if ($controller == "")
        {
            $controller = $default['controller'];
            $action = $default['action'];
        }
        
        if ($action == "")
        {
            $action = $default['action'];
        }
        
        
        // 控制類書寫規則 HomeController->Index 
        $controllerName = ucfirst($controller).'Controller';
        $dispatch = new $controllerName($controller, $action);
        
        if (method_exists($dispatch, ucfirst($action)))
        {
            call_user_func_array(array($dispatch, ucfirst($action)), $param);
        }
        else
        {
            /* Error Code for Method is not exists */
            die('method not exitsts.<br />');
        }
    }


 
    // 自動載入類
    function __autoload($classname)
    {
        if (file_exists(ROOT . DS . 'core' . DS . strtolower($classname) . '.class.php'))
        {
            require_once(ROOT . DS . 'core' . DS . strtolower($classname) . '.class.php');
        }
        else if (file_exists(ROOT . DS . 'app' . DS . 'controller' . DS . strtolower($classname) . '.php'))
        {
            require_once(ROOT . DS . 'app' . DS . 'controller' . DS . strtolower($classname) . '.php');
        }
        else if (file_exists(ROOT . DS . 'app' . DS . 'model' . DS . strtolower($classname) . '.php'))
        {
            require_once(ROOT . DS . 'app' . DS . 'model' . DS . strtolower($classname) . '.php');
        }
        else
        {
            /* Error Code for can not find the files */
            die('class not found.<br />');
        }
    }


    
    callHook();

這個頁面,首先定義了兩個函式callHook和__autoload,然後頁面底部有一句callHook();到此,程式就開始執行了。


callHook函式:

其作用就是定位上面所說的控制器,方法,引數

當代碼執行這裡時

// 控制類書寫規則 HomeController->Index 
        $controllerName = ucfirst($controller).'Controller';
        $dispatch = new $controllerName($controller, $action);

程式就會執行__autoload方法,這個方法可以在你使用類的時候可以自動載入所需的檔案

不需要手動require,這樣可以方便的時候各種類庫,方便省事,不需要每次呼叫類之前都手動載入.php類檔案


method_exists方法判斷這個類中是不是存在該方法,若存在,就call_user_func_array呼叫該方法


注:__autoload方法是一些載入類庫檔案的規則,這個要根據你的習慣來定義的。


至此,程式就跳到某某控制器的某某方法執行了。比如說HomeController類中的Index方法,該檔案就在你的__autoload規則裡定義著。

我這裡的就是app/controller/homecontroller.php檔案了

<?php

class HomeController extends Controller
{
    public function Index()
    {
        $user = new user();
        $tpl = new tpl();
        $tpl->set('name', $user->name);
        $tpl->render('index.html');
    }
}

這個方法里加載了user類(Model)和tpl類(view)

user類負責從資料庫讀資料

tpl類負責把顯示資料


所以也可以這樣說,controller類起到了一個連線的作用,控制著資料和顯示,使兩者可以很好的繫結在一起,model和view就分開了

這樣做就可以實現了當初的想法,把php程式碼和html佈局分離開來


我期待我能夠整合出一個屬於自己的方便使用的php框架,希望大家來QQ群給點意見,QQ群號:667110936671109366711093