CI框架入門筆記


PS - 個人博客原文:CI框架入門筆記

當前(2019-03-22)CodeIgniter 框架的最新版本是 3.1.5,於2017年6月發布,距今快兩年了也沒有更新,這與 Laravel 的更新速度相比差距太大了。因為確實,它是一個很古老的框架了(第一個版本在2006年發布),當初的設計原則,開發環境與現在都已經大為不同。它有自己的設計原則,有相配套的一大堆工具、庫,使用這些現有的工具就已經能很好地滿足日常開發所需。

雖然已經是2019年了,但是公司用的框架是CI框架,所以我也應當快速適應CI框架的開發模式。本文就針對CI框架開發中的一些重點問題進行梳理和記錄。CI框架的官網文檔( http://codeigniter.org.cn/user_guide/index.html )很完善,但是我覺得仍然有必要整理出自己的一套實用規則。

就一個常規PHP框架來說,我認為應當包含這幾個部分:

  • (1)index.php 或全局 App 對象,一個提供統一入口,一個提供容器資源管理
  • (2)路由控制
  • (3)請求和響應對象的封裝,輸入數據過濾和驗證,輸出數據的驗證和轉義,各種輸入輸出方法
  • (4)MVC 分層,控制器,模型和視圖層,以及 Service 層
  • (5)數據庫操作:數據庫驅動、查詢構造器、通用的查詢方法
  • (6)文件存儲、緩存管理
  • (7)Session, Cookie管理
  • (8)安全性、配置、國際化、自動加載、第三方擴展機制
  • (9)常見的工具類(其實應當通過擴展提供)
  • (10)模板語言(這個不是必要的,因為PHP本身就能輸出)

入門

了解框架

我們下載好CI框架解壓之后的初始目錄是下面這樣的:

application/
    controller/
        cache/
        config/
        controllers/
        core/
        helpers/
        hooks/
        language/
        libraries/
        logs/
        models/
        third_party/
        views/
        .htaccess
        index.html
system/
    core/
    database/
    fonts/
    helpers/
    language/
    libraries/
    index.html
.gitignore
composer.json
index.php

其中,我注意到,每個目錄下面都有一個index.html文件,其內容也都是一樣的:403 Forbidden。這是為了防止意外訪問嗎?

application/ 就是是項目目錄,就是我們實際的項目代碼存放處,下面分了很多子目錄,看名字就知道會放哪種功能的代碼,這些子目錄目前除了包含一個 403 index.html 文件,沒有別的內容。system/ 就是框架目錄,下面就是框架代碼。

根目錄的 index.php 是整個項目的唯一入口點。index.php 主要的功能是定義了一些系統目錄,包括項目目錄、視圖目錄、框架目錄,在最后調用了框架目錄下的 core/CodeIgniter.php,這個文件是CI框架的入口點和結束點,即包含了CI框架的所有生命周期。它的執行過程如下:

* 定義全局常量,加載全局函數,環境檢測,PHP版本判斷
* 注冊錯誤處理函數,自動加載函數(Composer判斷)
* 加載一系列類:
    * Hooks,鈎子函數類
    * Config,配置類
    * UTF-8,
    * URI,(CI_URI)
    * Router,路由類
    * Output,輸出類
    * Security,安全類
    * Input,輸入類
    * Lang,多語言類
* 加載控制器類
    * 判斷控制器類、方法是否存在,不存在則404
    * 調用控制器前置鈎子函數
    * 實例化控制器
    * 調用控制器后置鈎子函數
    * 調用控制器方法(業務邏輯)
    * 輸出響應
* 調用系統后置鈎子函數

在實例化控制器這一部分中,注意到它定義了一個靜態實例,代碼如下

# core/CodeIgniter.php
# 此處定義了一個全局函數 get_instance(),返回一個靜態對象。
function &get_instance()
{
    return CI_Controller::get_instance();
}
// ...

$CI = new $class();


# core/Controller.php
class CI_Controller {
    public function __construct()
    {
        self::$instance =& $this;
        // ...
    }

    public static function &get_instance()
    {
        return self::$instance;
    }
}

在之后的任意位置的代碼中,只要通過 get_instance() 方法就能獲取唯一的 Controller 對象,它其實就是CI框架中的“容器”。

調用控制器方法(即業務邏輯)通過這段代碼調用執行:

call_user_func_array(array(&$CI, $method), $params);

業務邏輯

在調用上述代碼之后,就進入到 application/ 目錄下我們的實際的業務功能代碼。上面的 &$CI 就是 $class 名對象,即根據URL參數解析對應到 application/controllers/ 目錄下的實際控制器類文件名。具體的映射方法可以看文檔( https://codeigniter.org.cn/user_guide/general/controllers.html

比如,有一個 URI 是這樣的:/welcome,會解析為 application/controller/Welcome.php 文件,它應該是一個繼承自 CI_Controller 的類。/welcome 相當於 /welcome/index,URI 的第一個部分是控制器,第二個部分是控制器的方法,所以這個 URI 會調用 Welcome 類的 index 方法。URI 中只有第一個部分時,那第二個部分默認是 index。在控制器方法中我們編寫實際的業務功能代碼。示例如下:

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Welcome extends CI_Controller {

	public function index()
	{
		$this->load->view('welcome_message');
	}
}

加載功能模塊(類庫)

CI框架默認提供了模型、視圖、輔助函數、日志、配置、緩存等功能。這些功能模塊默認是不加載的,需要在控制器中進行手動按需加載。另外,libraries 目錄中的類庫,也是同上的加載機制,只不過這里面的類庫是開發人員自己寫的功能模塊。下面詳細描述每種模塊的加載方式。

model

首先,我們看到上節中的 $this->load,這就是CI框架中的加載類(CI_Loader),我們所有需要的類庫、模塊都可以通過它來加載。這個加載類實際上是“容器”的一個對象屬性,從下面 model 的源碼可以看到,實際上所有容器的“對象屬性”都可以直接通過模型獲取:

class CI_Model {
    public function __get($key)
    {
        return get_instance()->$key;
    }
}

在業務功能開發中,使用最頻繁的就是模型了。CI框架提供的模型類是 core/Model.phpCI_Model 類,它其實就是一個很簡單的類,沒有提供任何內容,如果你需要使用模型,那就應該在 application/models 下面新建一個繼承自 CI_Model 的類,然后在使用模型的地方先使用 $this->load->model() 來加載它,加載了之后,就能直接通過 $this->{模型名} 訪問該模型對象:

 $this->load->model('User_model');
 $result = $this->User_model->get_one($id);

model() 默認到 application/model/ 目錄下尋找 user_model.php 這個文件名,然后加載 User_model 類,實例化之,並賦值作為“容器”的對象屬性,屬性名就是模型名。model() 方法部分源碼:


public function model($model, $name = '', $db_conn = FALSE)
{
    // ...
    $model = new $model();
    $CI->$name = $model;
}

model() 方法的第二個參數可以指定屬性名,示例代碼如下:

$this->load->model('User_model', 'USER');
$result = $this->USER->get_one($id);

CI框架並沒有規定模型類中應當放什么,這取決於你。通常我們會寫一個 Base_Model 類,用來提供各種查詢方法,然后在具體的模型類中實現具體模型對應的業務方法。在控制器中直接調用模型類的業務方法獲取數據。在CI框架中我們使用模型類的理由就是封裝邏輯,不然所有的邏輯都寫在控制器中(我看到項目中現在有一部分老代碼就是這樣做的!)。CI也沒有提供進一步Service層,這由你自己決定。

database

一般在 Base_Model 類中,我們會加載一下默認的數據庫,封裝若干查詢方法:

class Base_Model 
{
    function __construct()
    {
        // ...
        $this->load->database();
    }

    function save() {}
    function get_one() {}
    function get_all() {}
    function update() {}
    function delete() {}
    function query() {}
    ...
}

調用了 database() 之后,會實際化一個 CI_DB 對象,並賦值為控制器的 $db 屬性,database() 部分源碼如下:

public function database($params = '', $return = FALSE, $query_builder = NULL)
{
    // ...
    if ($return === TRUE)
    {
        return DB($params, $query_builder);
    }
    // ...
    $CI->db =& DB($params, $query_builder);
}

可以看到,當第二個參數為 TRUE 時,直接返回 DB 對象,並不會設置為控制器的屬性。這一點在具體的模型類中會有用,比如我們會在具體的模型類中加載不同的數據庫類:

class Article_model extends Base_Model
{	
    public function __construct()
    {
        $this->db = $this->load->database('myDb2', TRUE);
	}
}

這里獲取 myDb2 數據庫對象,避免了污染全局的 $CI->db 對象。

最復雜的部分其實已經介紹完了,下面是一些常用的類庫介紹

helper

在使用自定義的輔助函數之前,需要加載一下,語法同上。只不過它會去 application/helpers 目錄下去尋找相應文件。

$this->load->helper('dt');

libraries

application/libraries 目錄下的類,加載語法同上,使用其實沒什么問題,值得注意的是如何寫一個自己的類庫。

$this->load->library('t');

config

配置文件也需要加載,然后 item 方法直接訪問配置文件中的值,自定義的配置需要設置為 $config 數組的屬性的形式。

# application/config/d.php
$config['ddd'] = '';

# Controller
$this->load->config('d');
$data = $this->config->item('ddd')

view

由於現在CI項目只是作為API,所以並無視圖,但為了介紹,下面提供了一個示例:

# application/views/welcome.php

# Controller
$this->load->view('welcome', $data);

這個視圖文件就是一個普通的PHP文件,可以直接輸出。

driver

驅動其實也是類庫的一種。

總結

就我入手這個CI項目的一個月經驗來看,日常業務開發就是這些東西,后面也不過是在這個框架基礎上不斷深入和完善。所以這篇文章作為入門總結應該算是足夠了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM