當前(2019-03-22)CodeIgniter 框架的最新版本是 3.1.5,於2017年6月發佈,距今快兩年了也沒有更新,這與 Laravel 的更新速度相比差距太大了。由於確實,它是一個很古老的框架了(第一個版本在2006年發佈),當初的設計原則,開發環境與如今都已經大爲不一樣。它有本身的設計原則,有相配套的一大堆工具、庫,使用這些現有的工具就已經能很好地知足平常開發所需。php
雖然已是2019年了,可是公司用的框架是CI框架,因此我也應當快速適應CI框架的開發模式。本文就針對CI框架開發中的一些重點問題進行梳理和記錄。CI框架的官網文檔( http://codeigniter.org.cn/user_guide/index.html )很完善,可是我以爲仍然有必要整理出本身的一套實用規則。html
就一個常規PHP框架來講,我認爲應當包含這幾個部分:git
咱們下載好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。這是爲了防止意外訪問嗎?json
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框架中的「容器」。app
調用控制器方法(即業務邏輯)經過這段代碼調用執行:composer
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
目錄中的類庫,也是同上的加載機制,只不過這裏面的類庫是開發人員本身寫的功能模塊。下面詳細描述每種模塊的加載方式。
首先,咱們看到上節中的 $this->load
,這就是CI框架中的加載類(CI_Loader
),咱們全部須要的類庫、模塊均可以經過它來加載。這個加載類其實是「容器」的一個對象屬性,從下面 model 的源碼能夠看到,實際上全部容器的「對象屬性」均可以直接經過模型獲取:
class CI_Model { public function __get($key) { return get_instance()->$key; } }
在業務功能開發中,使用最頻繁的就是模型了。CI框架提供的模型類是 core/Model.php
即 CI_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層,這由你本身決定。
通常在 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
對象。
最複雜的部分其實已經介紹完了,下面是一些經常使用的類庫介紹
在使用自定義的輔助函數以前,須要加載一下,語法同上。只不過它會去 application/helpers
目錄下去尋找相應文件。
$this->load->helper('dt');
application/libraries
目錄下的類,加載語法同上,使用其實沒什麼問題,值得注意的是如何寫一個本身的類庫。
$this->load->library('t');
配置文件也須要加載,而後 item
方法直接訪問配置文件中的值,自定義的配置須要設置爲 $config
數組的屬性的形式。
# application/config/d.php $config['ddd'] = ''; # Controller $this->load->config('d'); $data = $this->config->item('ddd')
因爲如今CI項目只是做爲API,因此並沒有視圖,但爲了介紹,下面提供了一個示例:
# application/views/welcome.php # Controller $this->load->view('welcome', $data);
這個視圖文件就是一個普通的PHP文件,能夠直接輸出。
驅動其實也是類庫的一種。
就我入手這個CI項目的一個月經驗來看,平常業務開發就是這些東西,後面也不過是在這個框架基礎上不斷深刻和完善。因此這篇文章做爲入門總結應該算是足夠了。
PS - 我的博客連接 CI框架入門筆記