【CodeIgniter】CodeIgniterの動き
CodeIgniter Advent Calendar 2015 - Qiita 4日目の記事です。
まーくあっぷenジニアの です。
CodeIgniter3.0 の動き
概要
CodeIgniterってControllerに何か書くと動くけど中を読んでいないからどんな処理してるかわからない!読む時間無い!
という方の為のCodeIgniterのコードのざっくばらんとどんな処理してControllerが呼ばれているかという内容です。
※この記事はCodeIgniter 3.1.0-devを見て書きました。
1.index.phpの動き
1-1 CodeIgniterを設置したときの構成
githubからcloneしてCodeIgnierを設置したディレクトリを見ると
複数のファイルやディレクトリがありますがControllerが動くまでに重要なのは下の三つ。
CodeIgniter
├── application
├── index.php
└── system
CodeIgniterで一番最初に動くのがindex.phpです。
index.phpがどんな動きをしているかというとざっくりと
・system、applicationとかがどこにあるのかの設定(APPPATHとかの定数)
・system/core/CodeIgniter.phpを読み込み
を行っています。
index.phpで/system/core/CodeIgniter.phpを読み込んでいるので当たり前ですがapplication/core/MY_CodeIgniter.phpとファイルを作ってもoverride(置き換え)したりはしません。
2.core/CodeIgniter.phpの動き
index.phpでは/system/core/CodeIgniter.phpを読み込みます。(以下CodeIgniter.php)
CodeIgniter.phpではざっくりと以下の動きをします。
・環境の差分を吸収
・coreクラスの読み込み
・Controllerを動かす
・出力
余談ですが、動いているCodeIgniterのバージョンがわからなければCodeIgniter.phpを見れば定数としてバージョンが定義されています。
2-1 環境の差分を吸収
CodeIgniter.phpでは環境設定の差をある程度吸収しています。
我々ではなじみ深いmbstring系の関数「mb_strlen」では、マルチバイト文字列の文字数をカウントしてくれます。
mbstring系の関数が使えない環境でもエラーがでないように「mb_strlen」関数等が動くように定義されています。
mb_strlen以外にもCodeIgniterを動かす上で必要な差分をある程度吸収しています。
2-2 coreクラスの読み込み
CodeIgniter.phpではCodeIgniterを動かす上で必要なcoreクラスの読み込みを行っています。
もちろん、表でまとめられたcoreクラス ファイルはapplication/core/で上書きが行えます。
読み込み順から
Benchmark | パフォーマンス取る |
Hooks | いろいろなところに処理がはさめる |
Config | Configデータの管理 |
Utf8 | 文字コードのUTF-8をサポートしてくれる |
URI | URIのセグメントとかを管理 |
Router | どのコントローラーのどのメソッドを呼び出すとかのルーティングを管理 |
Output | どんな風に出力するを管理 |
Security | クロスサイトするクリプティングを抑制*1 |
Input | 入力データの管理 |
Lang | 言語設定の管理 |
Controller | 説明不要な便利なやつ |
を読み込んでいます。
また、クラスではないので表として記述してていませんがCommon.phpという物も読み込んでいます。
このCommon.phpは関数が多数定義されたファイルですが、core クラス ファイルを読み込む為に必要な関数以外にも便利な関数が揃っているので時間があれば読んでみると良いかもしれません。
2-3 Controllerを動かす
coreクラスを読み込みしたらControllerが動きます。
Controllerを動かすための動作:7
フローチャートっぽいもの
呼び出すメソッドの先頭が「_」じゃ無いかを見ているので「_」等をつける事でアクセスを防ぐ事もできますので是非とも活用して頂きたいです。
(例 : Form Validationクラスの独自ルールをController内のメソッドとして定義する場合)
2-4 出力
CodeIgniter.phpでは、Controllerの処理が完了するとOutputクラスを使って表示情報をレスポンスヘッダーと共に出力します。
このときの表示情報はLoaderでセットされた
<?php $this->load->view('hoge');
の値です。
上記の記述ではapplication/views/hoge.phpが呼ばれますが、Outputクラス*2に保存されます。
保存した内容やヘッダー情報等を、Outputクラスの_displayメソッドをCodeIgniter.phpが呼び出して出力しています。
その為、
<?php class Hoge extends CI_Controller{ public function index() { $this->load->view('hoge'); echo 'application/views/hoge.phpよりこの出力が先に表示されますよ'; } }
上記の様にviewメソッドの下にechoを書いても先に出力されるのは
echoの内容となります。
3. Controllerの動き
3-1 ControllerがLoaderを呼び出す。
CodeIgniterでmodelやlibrary、view等を読み込む時に大変便利なLoader クラス
このLoader クラスは先ほどのCodeIgniter.phpでは呼び出されません。
CI_Controllerのコンストラクタで呼び出されます。
CI_Controllerのコンストラクタの挙動は
です。
その為、CodeIgniterでApplicationを作成する時
<?php defined('BASEPATH') OR exit('No direct script access allowed'); //CI_Controllerをextendするよ class Hoge extends CI_Controller{ public function __construct() { //ここにload書いても、CI_Controllerのコンストラクタが走ってないから動かないよ! //$this->load->model('Foo_model'); //ここでcoreクラスやLoaderをCI_Controllerに読み込むよ parent::__construct(); //ここに書くと、CI_Controllerのコンストラクタが動いているからloaderが使えるよ! $this->load->model('Foo_model'); } }
このようにCI_Controllerのコンストラクタ読み込み後Loaderが使えるようになります。
また、CodeIgniter.phpで読み込まれたcoreクラスはLoaderで読み込むような記述は必要は無く、
$this->input->post('hoge');
と記述することができます。
3-2 get_instanceってなんだ!
CodeIgniterでは様々なところで
$CI =& get_instance();
というコードを見かけることがあると思います。
これは、Controllerのインスタンスを参照渡ししています。*3
<?php Hoge extends CI_Controller{ public function __construct() { parent::__construct(); //このthisはHoge Controllerです。 $this->load->model('Hoge_model'); } public function index() { //Hoge Controllere内のhoge_modelメンバ変数にインスタンス化されたHoge_modelのfooメソッド $this->hoge_model->foo(); } public function _controller_foo() { echo 'bar'; } }
<?php class Hoge_model extends CI_Model{ public function foo() { //これでも動くけど、ラッパーであるget_instance関数の使用 //CI_Controller::get_instance()->_controller_foo(); //Hoge Controllerの_controller_fooが動く get_instance()->_controller_foo(); } }
ModelのfooメソッドではControllerインスタンスの_controller_fooが読み込まれます。
内部的にnew Hoge();とControllerを新たにインスタンス化するような挙動はしません。
つまり
です。
Model内でthis->db->query等が動くのもget_instanceが理由です。
core/Model.php内のCI_Modelでは__getマジックメソッドを使いControllerのdbメンバ変数に入っているDBインスタンスを利用しているだけです。
<?php class CI_Model{ //モデル内で定義されていないメンバ変数が呼ばれたらControllerから取ってくる public function __get($key) { return get_instance()->{$key}; } }
*1:global_xss_filteringは使わない方が良いです。http://www.codeigniter.com/user_guide/installation/upgrade_300.html#step-13-check-for-usage-of-the-xss-clean-form-validation-rule
*2:final_outputメンバ変数
*3:デザインパターン:シングルトン https://ja.wikipedia.org/wiki/Singleton_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3