CodeIgniter(譯:程式碼_點燃器,下簡稱CI)是一種framework,以php的物件(object)為主要架構所製作而成的後台套件(又稱框架)。
框架會要求設計者依照其特定方式去安排檔案放置的位置,再以特定方式將前台的「面版(視界)」與後台的「控制指令」結合在一起,讓網頁的製作更有條理,將來需要維護修改時也會更加容易。
CI利用「網址列」來判讀使用者的操作內容,設計師再使用「控制檔」將使用者的請求組合成畫面回傳。控制檔能夠抓取資料庫資料與台台視圖重新運算建構成新的頁面傳給使用者。此方法能夠讓讓網頁的設計流程更容易被理解,此外,它也實現了讓使用者由單一窗口訪訪問所有頁面的功能。(也就是讓使用者永遠只訪問根目錄下的index.php)
Framework:習慣上翻譯成框架,此框架並不是指HTML中的框架(frame)。個人覺得翻譯成「架構」或「體系」更為貼切。 我們可以把框架(framework)視為是一個「套件模組」及「管理模式」,它提供許多實用的函數讓設計師直接套用,能幫設計師節省時間、提昇效率並且減少程式錯誤的發生。不過…… 框架本身其實也限縮程式的靈活性,它限制了原本語法的使用方式,設計師必需另外再學習框架本身的語法習慣。但比起重新架構一個網站而言,使用框架確實能夠加快製作效率。通常廣被使用的框架都會盡可能地兼顧製作效率及擴充的靈活性。 框架是從利用原本網頁設計的各種語法,製作並收集一系列實用的功能,並將它們組合成一套小型的程式組件,而CI框架屬於一般性網頁的框架,並不是為特定目的而設的專門框架,因此它有較大的靈活性,不過,需要自行撰寫的程式碼也會較多。 |
檔案夾內容
CI檔案夾中有2個主要的資料夾:「application」跟「system」。其中,「user_guide」是說明書檔,(若用不到可以刪掉它)
CI框架的一些前置設定及輔助函數都放在「system」資料夾裡面,一般不會去更動這資料夾裡的內容,僅會去裡面拿取工具來使用(或者延申裡面既定的類別)。設計師主要工作區在「application」資料夾裡。
為了增加網站的安全性,我們可以為system與application這兩個資料夾更名,更名後必需再到index.php檔中變更一下連結的設定。
application資料夾裡有三個子資料夾,即是主要的工作項目: 可以把controllers視為是models與views的中介,控制器利用模組裡的方法去資料庫拿資料後再去視圖選定視圖組合成新的頁面再呈現給使用者。 「視圖」:又稱面版、模版、版型。
|
註:為簡化說明,接下來統一以「SYS」表示「system資料夾」;
以「APP」表示「application資料夾」
根目錄的index.php
以3.1.6版為例:
首先,本頁定義ENVIRONMENT(環境常數),預設為'development';CI將根據環境常數的不同而改變錯誤訊息的層級。
define('ENVIRONMENT',
isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');
由上式中可以知道,環境常數是參考$_SERVER[‘CI_ENV’]的值來做設定的,除了預設值外,還有兩種設定值:
「testing」(測試級)、「production」(上線級)
接著,此頁將確認SYS、APP及views資料夾是否存在,若不存在則顯示錯誤訊息並中斷程式。若這些重要的資料夾都存在,則開始根據這些資料夾的路徑來「定義常數」。
當這些路徑都定義好後則改由CodeIgniter.php這個檔案出場囉!
require_once SYS/core/CodeIgniter.php
其實,index.php僅是確認資料夾是否存在並定義一些重要的路徑常數;而前置設定的工作是由CodeIgniter.php來完成。不過,它在過程中引入非常多的頁面,若沒時間了解的話可直接跳過,開始實作吧!
註:SELF、BASEPATH、FCPATH、SYSDIR、APPPATH這些字串都已被index.php定義為路徑常量囉!其中,BASEPATH代表絕對路徑到SYS資料夾;接下來的每個頁面都會先檢查BASEPATH這個常量是否存在,若它不存在則將直接終止程式囉!!
CodeIgniter.php做了什麼
(這部分太多太雜了,我並沒有全看完它,將來再逐步補充它吧!)
首先,定義一個常數來紀錄CI的版本:CI_VERSION = '3.1.6';
接著,引入常量定義的檔案「constants.php」。程式會到APP/config資料夾中尋找該檔,若裡面有著依「環境常數ENVIRONMENT」的內容命名的資料夾時,則以該資料夾中的「常量定義檔」為主,否則,將直接引入config資料夾中預設的constants.php檔。
然後,引進common.php,該檔案放在SYS/core裡面,CI有許多核心程式都放core裡。require_once(BASEPATH.'core/Common.php');
common.php的主要內容就是函數,不過它所設函數通常不是給設計師使用的,而是給自己接下來要預設環境時使用的。
值得注意的是,common.php定義了的load_class函式(載class函式),此函式會依序從APP及SYS裡面的libraries資料夾去尋找想要載入的class檔。若以上位置都沒找到該名稱的檔案時,則改到APP內指定的資料夾中尋找自定義檔(此次尋檔會附上預設的前綴詞)。
程式尋找自定檔時會在load_class()函式中附帶第二參數(路徑)。無論如何,CI都必需找到這存放類的檔案並將裡頭的類創建為物件並存於變數中。如果都沒找到所指示的檔案,則程式將回傳錯誤訊息。
註:librayies是函式庫,先以使用者自定的為主,若沒找到才採用預設的。
由於,Common.php是個必定會被引用的檔案,因此,可以把自定函式寫在這個檔案的後面,提供所有的頁面檔案使用。
載入common.php檔後,CodeIgniter.php會利用common.php提供的函式來進行php的版本判斷,再依據版本需要定義所需的全域變數。接著開始把SYS/core裡的所有檔案全都引用或者以load_class()轉為物件存放於變數中備用。
(包含子資料夾SYS/core/compat/中的檔案)。
CodeIgniter .php引入檔中,有個較特別的檔:core/Controller.php
1、 定義了一個類「CI_Controller」並將CodeIgniter.php先前建立的物件位址全都轉為CI_controller中的變數。其中,變數名即為類名(也是物件名),而變數值為該物件的參照位址。
因此,CI_Controller是個超級物件,它可以控制所有已建立的物件。
2、 眾多被生成的物件中有一個用來載入物件的物件:「load」。此物件是由core/loder.php裡的CI_loder所生成的物件(注意,它是物件不是函式)
load物件定義了許多嚴僅的函式(先不深究),總之,load有能力載入:模型、視圖、控制器、變數、資料庫、函式、檔案、資源、封包……。
註:超級物件CI_Controller會常常利用load來載入物件。
在新建CI_Controller物件時,它就以建構子載入初始化函式:
$this->load->initialize(); (初始化載入)
初始化函式將試圖include「autoload.php」,依序查找APP/config資料夾及環境變數資料夾,把此檔include進來。(註:若都有此檔,則兩個檔案都會引入,由於要使用的是裡面的變數,變數將會以後者覆蓋掉前者)
autoload.php中需設有變數$autoload(二維陣列),第一維以字串指定參數,第二維以array存放該參數的設定值。例如:
$autoload[項目]=array(設定值1,設定值2...)
共有七個項目可在autoload.php檔中預先自行設定:
packages、helper、lanuage、drivers、libriaies、model、config。
3、 最後CI_Controller中設有一個靜態函式,它把自己當作靜態物件回傳。
靜態變數 $instance=CI_controler。
取預設值的都是從「APP/config/」資料夾中引入,若有設定環境常數則以裡頭的環境變數名稱資料夾為主。如同autoload.php的作法,將兩個檔案都引入再利用後面的變數來取代前面的變數內容。接下來其它取預設值的方式都採類似的方式,為簡化說明,接下來會將這些資料夾簡稱CONFIG資料夾。 |
至此,CodeIgniter.php僅完成:定義版本常數及載入核心檔。
註:核心檔指的是APP/core裡的php檔,所有載入的核心檔都會被建立成物件並存放於CI_controller物件的某變數之中。其中Common.php、Loader.php、Config.php、Controller.php、Louter.php這些檔案特別重要,應再多花點心思去了解細節。(上列中僅Common.php不是個物件,而是個函式庫)
在CodeIgniter的物件變數中,$CFG是以Config所創建的物件,而$RTR是以Router所創建的物件。$CFG負責尋找初始值設定,而$RTR主要負者截取網址列上的訊息(也配合config設定初值)。
CI_Contorller的建構子方法使用Config物件來載入autoload.php檔案,此時僅是載入該檔中的初始設定值,並未開始製作視圖。
網頁的回應動作是在CodeIgniter.php的後段中比對$CFG與$RTR兩物件內部資訊後,才決定要採取哪個物件中的哪個方法來製作視圖回應使用者。CI習慣用下列函式來執行方法(此函式實在不常用它耶!):
call_user_func_array(array(&$CI, $method), $params);
用法:call_user_func_array(array(&物件名,方法名),帶入方法的參數值);
autoload['config’]這個項目的進一步說明:
autoload.php檔僅是紀錄自動載入項目與內容,而這些項目內容先以load->_ci_autoloader()來載入,該方法會根據$autoload[]的索引的不同而採取不同的函式來載入。
其中對於’config’這個索引的處理方式,配合函式轉換後如同於把autoload[‘config’]的元素值都放進$CFG->load()方法中做為參數。
$CFG->load()僅查訪CONFIG資料夾,因此$autoload[‘config’]裡的檔案都必需放在這些資料夾中才能被預載。
若該檔案先前尚未被載入過才會被include()進來,接著會查閱是否含有$config變數,其型態必需是array才會進行後續的設定動作。
註:程式預設都會載入APP/config/config.php。此檔可供設計師自定預設值,
例如:根目錄位址、首頁檔、語系設定、文字編碼、子類前綴…等。
common.php引入檔Router.php的進一步說明:
Router的建構子將配合config物件設法先製作出$routing變數。
$routing是個兩個元素的陣列,存放物件名($routing['controller'])及方法名($routing['function'] )。
而其預設做法也是到CONFIG裡尋找並引入route.php檔,接著查閱$route變數,將$route[‘default_controller’]元素值設為預設控制器,並存放在$RTR->default_controller這個變數中。
$RTR->default_controller存放的控制器名稱只是暫時性的,後續可能會因網址列的資訊而更改掉這個值。若此值無法以「/」拆分成兩段的話,則表示沒指定控制器方法,程式將默認其方法為「index」。
在$RTR中運作完建構子後,將可把底下兩個變數的值確定下來: $class=物件名;$method=方法名,此二變數將被傳到CodeIgniter.php中繼續運作,此時就是為了製作視圖了。
小結
以上我們知道CI希望以一個物件中的一個方法來完成一個頁面視圖,因此,指定物件與方法就變成CI的主要工作。當然,在製作上很難把工作都都簡化成這般,後續再進一步地展現其它CI的附加功能吧!
由於使用者初期的訪問網址就是根目錄下的index.php檔,此時網址列上並沒有其它進一步指示,CI仍究需要一種預設的回應方式,而前述那一系列的流程就是為了因應這個預設視圖。
CI產生預設視圖的方法就是到 APP/config資料夾中查找預設資料:
routes.php:設定默認控制器。config.php:通常只設定語言檔
autoload.php:設定「helper」:’url’、「libraries」:’database’,’session’
database.php:若有需要用到資料庫,這兒可預設連線資訊。
最後,利用默認控制器裡的方法$this-> load-> view(‘視圖檔案路徑’),
此方法會到 views資料夾中尋找視圖檔,並將它發佈給使用者。
實作一次默認視圖輸出
先做好一個控制檔,控制檔有幾項要求:
1、 檔案需要放在APP/controllers/底下,並且需為php檔
2、 檔名需要與裡面的類別同名,而類別名稱的首字必需大寫。
3、 類別必需設為CI_Controller的子類
可以參考底下原始檔中的默認控制器再作修改:
APP/config/routes.php
$route['default_controller'] = 'welcome'; //將它修改為自己的默認控制器
註: CI中的副檔名若為php則可省略。
設好控制檔(或稱控制器)後,裡面的類別中需給個控制方法,CI預設會找尋index()方法,在方法中參考以下的語法載入視圖:
$this->load->view('welcome_message');
註:welcome_message為視圖檔名,該方法的參數可以是檔名也可以是路徑,若是路徑的話,其相對位置是以APP/views資料夾為起點。換言之,CI的視圖規定必需放在views資料夾(含子資料夾)。
如果以上的設定都無誤的話,就可以發佈第一張自設的視圖囉!
以上幾個步驟,看起來像是瀏覽器進到了控制器,依照控制器的方法選擇了一張視圖來播放。不過,實際上為了產生這張視圖,CI已經把前面三頁說述的預載檔案都跑過了一次。
換句話說,使用者的瀏覽器只是用來操作網址列,CI會從網址列來判斷接下來的工作內容。一旦網址有所變動時,所有預載的動作都將再重新跑一次才能生成一個新頁面。
CI每次都要串連幾十個檔案並建立一堆物件後才能生成一個頁面視圖。可見得使用框架製作網頁肯定比較佔系統的運算資源。不過,選擇使用框架的用意就是想要以效能來換取製作上便利,而且框架也能讓後續的維護工作變得更加容易。幸好現在的電腦效能都很高,即便繞了一大圈也僅是一瞬間罷了並不會造成網頁載入延遲。
話雖如此,使用框架設計時應該盡可能地精簡,別把一些不相關的檔案都引用進來佔資源囉!
框架本身以較為嚴謹的套件程式碼,能幫設計師先做好初步的安全性把關。
補充:
發現common.php的許多函式前面都有一個「&」,例如:
function .&get_config() {... };或 $this->config =& get_config();
那是什麼意思呢?
它類似變數的傳址效果,而函式的傳址所傳的位址是函式回傳值的位址。當函式前做了如此設定時,則以下操作中:$this->config =& get_config();
其變數 $this->config與函式 get_config()的回傳值有著相同的位址。
雖然此時可以透過更改變數來變更改回傳值(偷改答案?),不過,沒事去更改回傳值實在沒什麼太大的意義,畢竟它只是個結果。(運算才是動點呀!)
由於傳值等同於再複製一份資料存放於記憶體中,而CI很多回傳值都是一大串的陣列,直接傳位址將可以提升執行效率也能節省記憶體的使用量。
關於Load->view()
View()方法寫在core/Loader.php中,是個用來載入視圖檔的方法。Loader物件存放在CI_controller物件中的$load變數中,因此當需要載入視圖時,我們需要寫為$this->load->view(路徑檔名)。
每個網頁最後都需要靠view()來呈現畫面,由於使用十分頻繁,即便它只是個方法而不是類,也有人會直接稱它為「視圖控制器」。
視圖控制器除了可以秀視圖之外,它的第二個參數(選用)可以用來掛載數據。如:$this->load->view('index/article.html', $data);
上例中的$data就是設計師所掛載的數據(必需是個array)。同一個頁面視圖中,若前面已經有用視圖控制器掛載了這個數據,其它的局部視圖就不需要再重複掛載同樣的數據了(都可以讀得到寫它)。
觀念
由於使用者自始至終所造訪的都是根目錄下的index.php檔,換言之,CI僅是透過一系列的方法來改造index.php的回傳內容。串連了許多的檔案就是為了改寫這個index.php。最後終究仍是必需打印出輸,輸出瀏覽器能夠看得懂的語法(HTML、CSS、JS…)才能成為網頁。視圖控制器正是用來完成這最後一步關鍵的動作。
所謂的MVC
M指的是模組(model或譯:模型),搭配的控制器(C)及視圖(V)即是所謂的MVC。
註:CI手冊中自稱模組M是個非必需的設定。由於,即使不使用模組而單純使用是C及V亦可完成同樣的工作。
模組存在的目的是針對某些特定工作,將它進一步地製作成系統化及套裝化組件。通常模組內含許多特定的前置設定及特定用途的函式庫,這些功能不見得會在其它頁面上使用到。模組先將它們套裝起來備用,設計師可以不載入它們以節省系統資源。此外,面對複雜或大型的工作時,模組也能讓程式碼變得更容易閱讀。
例如:資料庫操作模組。
雖然連接資料庫的動作也可以直接寫在控制器(C)中,可是這類的操作通常大同小異並且許多的控制器可能都需要進行同類的操作,於是,在設計效率上會考慮稍微增加一些程式判斷以擴大「方法」的適用範圍,並將這類的函數置於控制器外供所有控器使用,這就是模組。
換言之,模組即是置於控制器的外的函式庫,當控制器有需要時隨時可以載來使用。模組的基本原型如下:
class Model_name extends CI_Model {
function __construct()
{
parent::__construct();
}
}
使用helper裡的輔助函式庫
SYS/helper裡面有許多實用的函式庫可供使用,為加快網頁執行速度,通常不會把它們全都常駐;設計師可視需要再去載入它們。
載入help時,程式將依序查找APP/helpers及SYS/helpers;有找到即停止。換言之,helper的函式庫將優先採用自定義的函式庫。
載入方式可採自動載入或手動(單次)載入兩種方式,例如:
載入url_helper.php單次載入方式:$this->load->helper('url');
自動載入的方式其實就是利用autoload.php檔案來做的設定:
$autoload[‘helper’]=array(‘url’);
url_helper.php此函數庫提供一些關於路徑的實用函式。例如:
base_url()=根目錄;site_url()=根目錄/首頁檔。
上例函式的根目錄是指外部連結進伺服器的絕對網址,而不是由伺服器的角度而設的路徑。因此,它既不是相對路徑也不是絕對路徑。
例如:http://localhost/根目路/index.php;
base_url()連slash的方向都會幫忙轉向正確哦!!
輔助函數的特色是能夠獨立完成特定任務,不需再依賴其它函數。
關於輔助函式的一些特點
APP/helpers預設是空的,通常自設輔助函式庫會拿SYS/helper裡的函式再來作修改,畢竟系統提供的函式已經寫得十分嚴謹且實用,拿它們來做修改會比重新寫來得有效率。此外,自定輔助函式檔名名前面需要加上前綴,例如:MY_url_helper.php。
註:前綴設定於APP/config/config.php檔案中,如:
$config['subclass_prefix'] = 'MY_'; //別設為’CI_’以免造成自己混淆!
輔助函式是函式而不是方法(method)哦!
程式是採 include_once()的方式來載入該檔案。
想要載入的檔案名稱是url_helper.php,不過,載入時所使用的名稱僅需「url」即可(自定函式亦同),前綴後綴都由程式自動補上。
可以同時載入多個輔助函數,其方法如下:
$this->load->helper( array('helper1', 'helper2', 'helper3') );
此外,CI提供了輔助函式helper,當然也有提供輔助類庫(或稱為通用類庫)。
載入方式類似於輔助函式,例如,載入購物車物件:
$autoload[‘libraries’]=array(‘Cart’);
$this->load->library(‘Cart’)