最近再給一個APP寫API,同時還要寫相應的後臺管理網站。爲了便於開發和代碼組織與管理,我決定採用一個現有的框架。Codeigniter因爲其輕量容易自定製的特色吸引了我,一路開發過來也有大半年時間了,寫下一些本身在開發過程當中的一些體會來與你們共勉。php
開發工具備好多,每一個人的習慣也不一樣。Eclipse一直是個人最愛,那麼怎麼讓Eclipse支持codeigniter呢?git
首先這是個PHP項目,因此得讓Eclipse支持PHP。假設你的計算機已經安裝了PHP,那麼最簡單的作法就是在Eclipse的market space中搜索PDT並安裝。具體操做:Help -> Eclipse Marketplace。在輸入框中輸入PDT,點擊find,如圖:github
點擊右下方的install,等待幾分鐘便可。web
如今能夠在Eclipse中寫PHP了,不過對於codeigniter來講,常常用到的語句相似以下:redis
$this->load->model ( 'user_model' ); $this->input->post ('phone');
每次都要手動輸入這麼長的相似的語句對於追求高效的人來講顯然是不可取的,因此得讓Eclipse支持codeigniter特定的代碼提示,包括Controller和Model。把以下代碼添加到算法
system/core/ 目錄下的Controller文件中CI_Controller類的構造函數以前,這其實就是進行apache
變量聲明,Model文件也是一樣操做。json
/** @var CI_Config */ var $config; /** @var CI_DB_active_record */ var $db; /** @var CI_Email */ var $email; /** @var CI_Form_validation */ var $form_validation; /** @var CI_Input */ var $input; /** @var CI_Loader */ var $load; /** @var CI_Router */ var $router; /** @var CI_Session */ var $session; /** @var CI_Table */ var $table; /** @var CI_Unit_test */ var $unit; /** @var CI_URI */ var $uri; /** @var CI_Pagination */ var $pagination;
如今效果以下:vim
只需輸入$this 便可產生代碼提示,效率提升很多。設計模式
通常一個項目中會有許多相同的邏輯,會使用到相同的代碼。若是每次都去複製粘貼不只麻煩並且不利於後續修改,想到須要修改一個邏輯就要到每一個文件裏修改代碼就以爲可怕(涉及到設計模式這一塊了,值得咱們學學)。因此你要善於利用那些自定義輔助函數(helpers)和自定義的庫(libraries)。把相同的邏輯封裝成函數或者類,每次遇到相同的邏輯之時只需調用現成的helper或者library便可,修改也只須要在helper或者library中一處修改,不須要處處找代碼。
舉一個我項目中的例子。API須要給APP發送的請求返回json格式數據,那麼在PHP中的一種實現方法就是:
echo json_encode ( $data);//$data 是array類型的數據
可是若是$data中包含中文字符的話,輸出的json數據會把中文變成Unicode編碼,爲了不客戶端須要再次處理數據,須要加入一個參數,即:
echo json_encode ( $data , JSON_UNESCAPED_UNICODE);//$data 是array類型的數據
這樣就能輸出原始的中文了。可是問題又來了,每次都要寫這麼長一段代碼實在是麻煩,因此封裝成一個輔助函數。在application/helpers 文件夾中新建一個文件render_helper.php。其中代碼以下:
<?php defined ( 'BASEPATH' ) or exit ( 'No direct script access allowed' ); /** 打印不轉義中文的json @param [array] $data */ function echo_json($data) { echo json_encode ( $data, JSON_UNESCAPED_UNICODE ); }
那麼每次調用之時只需先在類中的構造函數載入該輔助函數,以下:
$this->load->helper ( 'render' ); // 載入打印json的自定義輔助函數
就能夠在本類的全部成員函數中使用該方法:
echo_json ( $data);
這樣省時省力(加上Eclipse的代碼提示,你只須要輸入echo,這個函數就能夠出來了)。之後須要修改爲編碼後中文,或者轉換成英文等等(奇怪的需求~)你均可以只修改一行代碼,效率提升很多。
若是一個APP的活躍用戶不是不少,那麼傳統的LAMP架構就能夠應付了。可是隨着用戶的逐漸增多,要想提升併發量,最好仍是加一個緩存。在memcached和redis中,我選擇了redis,主要由於它數據類型更豐富(不只支持key-value型的數據,同時還提供list,set,zset,hash等數據結構的存儲),能幫你實現一部分邏輯(避免重複造輪子)。與Eclipse配置同理,首先得讓計算機上的PHP可以和redis通信(假設你的計算機已經安裝了redis),那麼首選的是phpredis擴展,這裏介紹一下我在Debain服務器上的配置過程,執行的命令以下:
wget https://github.com/nicolasff/phpredis/archive/master.tar.gz #下載擴展 tar xvf master.tar.gz #解壓目錄 cd phpredis-master/ #進入解壓後的目錄 phpize ./configure --enable-redis make && make install #安裝 #可是報錯-bash: phpize: command not found(在使用apt-get install php5安裝php時,默認是沒有安裝phpize的,咱們安裝phpredis時,須要用到phpize,所以,須要先安裝#phpize。咱們經過安裝php開發者工具來獲取phpize。執行以下命令便可: apt-get install php5-dev) ls /usr/lib/php5/20100525/#根據安裝提示的文件,結果:curl.so gd.so redis.so vim /etc/php5/apache2/php.ini #打開PHP配置文件 # Dynamic Extensions 後面添加extension=redis.so,由於上面命令結果顯示有redis.so /etc/init.d/apache2 restart #重啓Apache服務器
如今PHP就能和redis通信了,測試以下:
<?php $redis = new Redis(); $redis->connect('127.0.0.1',6379); $redis->auth('你的密碼');//爲了安全,要給redis設置密碼 $redis->set('tom','hanks'); echo ' tom:'.$redis->get('tom'). '</br>';// tom:hanks echo 'will:'.$redis->get('will'); //will: ?>
好了,如今來到配置codeigniter使其可以使用redis的步驟了。Codeigniter3.0.0自己具備redis支持,可是它實現的功能過於單一,不可以知足個人業務需求,因此必需要修改。可是最好不要直接在/system/libraries/Cache/drivers/Cache_redis.php 中修改,由於之後codeigniter升級採用直接覆蓋system文件夾的形式,會覆蓋掉你的代碼。因此最明智的作法仍是本身建立一個庫,具體步驟以下:
一、在application/config/redis.php 中加入配置信息:
<?php defined ( 'BASEPATH' ) or exit ( 'No direct script access allowed' ); $config ['socket_type'] = 'tcp'; config ['host'] = '你的服務器域名或者IP'; $config ['password'] = '你的redis密碼'; $config ['port'] = 6379; $config ['timeout'] = 0;
二、在application/libraries中創建以下圖的文件結構
Rediscli.php 代碼以下:
<?php defined ( 'BASEPATH' ) or exit ( 'No direct script access allowed' ); class Rediscli extends CI_Driver_Library { public $valid_drivers; public $CI; function __construct() { $this->CI = & get_instance (); $this->valid_drivers = array ( 'default' ); } }
Rediscli_default.php 代碼從/system/libraries/Cache/drivers/Cache_redis.php 直接拷貝過來,惟一的不一樣是把類名從CI_Cache_redis改成Rediscli_default,這樣就能按照官方的使用方法使用咱們本身寫的庫。
三、如今能夠在Rediscli_default.php中添加或者修改方法,具體操做取決於你本身的應用的需求。好比在個人應用中,須要保持一個必定長度的隊列,因此在Rediscli_default類中添加以下兩個方法:
/** 彈出鏈表頭元素 @param unknown $key,鏈表名 */ public function lpop($key) { return $this->_redis->lPop ( $key ); } /** 插入元素到表尾 @param unknown $key,鏈表名 @param unknown $value,待插入值 */ public function rpush($key, $value) { return $this->_redis->rPush ( $key, $value ); }
某個類須要調用該庫時只需在其構造函數中添加以下代碼:
$this->load->driver ( 'rediscli' ); // 加載redis自定義庫 $this->rediscli->default->is_supported ();//判斷是否支持redis並打開鏈接
則該類的每一個函數就均可以使用Rediscli_default類中的任一方法,示例以下:
$this->rediscli->default->lpop('delnews');//彈出名爲delnews的鏈表頭元素 $this->rediscli->default->rpush('delnews',$nid);//該鏈表加入尾元素$nid
對於咱們的APP來講,每一個請求都要判斷用戶是否已登錄,對於登錄的合法用戶正常顯示請求,對於未登陸的用戶提示「請先登陸」。通常的web應用採用cookie-session機制,通常的session都是以文件形式保存在服務器上,考慮到文件訪問慢於內存訪問,咱們能夠配置codeigniter的session保存於redis中。我這裏模仿這種機制:用戶正常login後返回一個特定的id和特定的token(你能夠自定義產生算法),服務器以id爲key、token爲value直接保存在redis中。之後的每次訪問APP都必須帶上用appsecret(預約義)加密後的參數id和token,服務器端校驗成功即正常返回數據,不然提示「請先登陸」。
那麼是否每一個類都須要寫一遍檢查登錄的代碼呢?固然不能這麼幹,咱們能夠自定義一個基類,在該基類的構造函數中檢查登錄狀態(還能夠在這裏加載經常使用的輔助函數和庫,好比上面的render_helper 和 rediscli)。而後其餘的業務邏輯的類就繼承該基類,並完成其自身邏輯便可。
具體操做就是在 application/core 中新建文件 MY_Controller.php,該文件對應MY_Controller類(繼承CI_Controller類)。該類只須要一個構造函數完成上述功能便可。
而後其它邏輯類只需繼承MY_Controller類就沒必要再次校驗登錄狀態,而只需完成自身邏輯。
Codeigniter是我最喜歡的一個PHP框架(相比於thinkPHP,Zend Framework等等),主要在於其易安裝,輕量,易自定製的優勢。把握好這些優勢,咱們就能寫出不遜於那些重量級框架寫出來的應用,而且省時省力。
做爲一個學生,在摸索學習的路上還有不少問題須要解決,本文的目的在於和你們分享,更重要的是你們有什麼建議或者批評請必定不吝賜教哈