CodeIgniter(이하 CI, 공식 홈페이지 및 차이나 스테이션)은 인기 있는 PHP 프레임워크로 작지만 강력하고 간단하며 가벼우며 확장성도 좋습니다. 국내에서 인기가 많아요. 반면 CI는 시대의 흐름을 따르지 못하고 PHP5.3 이후 일부 기능을 지원하지 않기 때문에 상대적으로 오래된 프로젝트에 더 적합합니다. 그럼에도 불구하고 CI는 여전히 훌륭한 프레임워크이며, 핵심이 작고 우아한 소스 코드를 갖고 있으며 학습에 적합합니다.
CI는 사용하기 쉽고 웹 애플리케이션을 쉽게 개발할 수 있습니다. 먼저 CI 워크플로 다이어그램을 살펴보겠습니다(여기 내용은 http://codeigniter.org.cn/user_guide/overview/appflow.html에서 인용)
,
1.index.php는 CodeIgniter를 실행하는 데 필요한 기본 리소스를 초기화하는 프런트 엔드 컨트롤러 역할을 합니다.
2. 라우터는 HTTP 요청을 확인하여 누가 요청을 처리해야 하는지 결정합니다.
3. 캐시 파일이 존재하는 경우 일반적인 시스템 실행 순서를 우회하고 브라우저로 직접 전송됩니다.
4. 보안. HTTP 요청과 사용자가 제출한 모든 데이터는 애플리케이션 컨트롤러가 로드되기 전에 필터링됩니다.
5. 컨트롤러는 특정 요청을 처리하는 데 필요한 모델, 핵심 라이브러리, 도우미 기능 및 기타 리소스를 로드합니다.
6. 최종 보기에서는 웹 브라우저로 전송된 콘텐츠를 렌더링합니다. 캐싱이 켜져 있으면 뷰가 먼저 캐시되어 향후 요청에 사용할 수 있습니다.
위에서는 일반적인 프로세스를 제공합니다. 그러면 브라우저에서 렌더링된 페이지를 볼 때 프로그램이 내부적으로 정확히 어떻게 작동합니까?
다음은 CI 프레임워크가 실행 순서대로 로드하는 주요 파일 목록과 해당 기능에 대한 간략한 소개입니다.
01.index.php
사용 환경(ENVIRONMENT), 프레임워크 경로(system_path, BASEPATH), 애플리케이션 디렉터리(application_folder), 애플리케이션 경로(APPPATH) 등을 정의하고 CI 코어 파일을 로드(require)합니다
02. BASEPATH/core/CodeIgniter.php (ps. 실제로 BASEPATH에는 최종 파일 구분 기호 '/'가 포함되어 있으며, 더 명확하게 표시하기 위해 여기에 추가 '/'가 추가됩니다.)
전체 프레임워크의 핵심 부분인 시스템 초기화 파일은 여기에 일련의 기본 클래스를 로드하고 이 요청을 실행합니다
03. BASEPATH/core/Common.php
공통 파일에는 load_class(), get_config() 등과 같이 전역적으로 사용할 수 있는 일련의 기본 및 공용 함수가 포함되어 있습니다.
04. 베이스패스/코어/벤치마크
이것은 기본적으로 애플리케이션의 각 단계의 실행 지점을 표시하여 실행 시간을 얻는 벤치마크 테스트 클래스입니다. 또한 모니터링 지점을 직접 정의할 수도 있습니다.
05. BASEPATH/core/Hooks.php
CI_Hooks는 프레임워크 확장의 핵심인 Hook 클래스로 프로그램에서 허용하는 다양한 단계에 Hook Point를 삽입하고 사용자 정의 클래스, 함수 등을 실행할 수 있습니다.
06. BASEPATH/core/Config.php
구성 파일 관리 클래스, 로드, 읽기 또는 구성 설정
07. BASEPATH/core/URI.php, BASEPATH/core/Router.php
URI 클래스는 요청된 URI를 구문 분석하는 데 도움을 주고 라우터 클래스에서 사용할 수 있도록 URI를 분할하는 일련의 기능을 제공합니다
08. BASEPATH/core/Router.php
라우팅 클래스는 요청된 URI와 사용자 구성 경로(APPPATH/config/routes.php 함수)를 통해 지정된 처리 기능(일반적으로 컨트롤러 인스턴스의 작업)에 사용자 요청을 배포합니다.
09. BASEPATH/core/Output.php, BASEPATH/core/Input.php
입력 클래스는 요청의 입력 매개변수를 처리하고 이를 얻는 안전한 방법을 제공합니다. 출력 클래스는 최종 실행 결과를 내보내고 캐싱 기능도 담당합니다
10. BASEPATH/core/Controller.php
싱글톤 모드를 사용하여 전체 애플리케이션의 핵심인 외부 세계에 인스턴스를 제공하는 컨트롤러 기본 클래스입니다. 이는 슈퍼 개체입니다. 애플리케이션 내에 로드된 클래스는 컨트롤러의 멤버 변수가 될 수 있습니다. 이는 매우 중요하며 나중에 설명합니다.
11. APPPATH/controllers/$RTR->fetch_directory().$RTR->fetch_class().'.php'
라우팅 기능을 통해 컨트롤러 이름을 얻고 실제 컨트롤러 클래스(서브클래스)를 인스턴스화합니다.
12. BASEPATH/core/Loader.php
CI_Loader는 다양한 클래스 라이브러리, 모델, 뷰, 데이터베이스, 파일 등을 애플리케이션에 로드하고 이를 컨트롤러의 멤버 변수로 설정하는 데 사용됩니다
13. call_user_func_array가 처리 함수를 호출합니다
라우팅을 통해 액션 함수명을 얻어 Controller->action() 함수를 호출하고, 실제 업무 처리 로직은 액션 함수에 작성됩니다.
14. $OUT->_display()는 콘텐츠를 출력합니다
위는 전체 지원서의 가장 기본적인 처리 흐름입니다. 아래에서는 CI에 대한 이해를 높이기 위해 핵심 콘텐츠 코드를 선택하고 설명합니다.
<?php //*BASEPATH/system/core/Common.php //引导文件中Benchmark,Hooks,Config等都是通过这个函数进行加载的 function &load_class($class, $directory = 'libraries', $prefix = 'CI_') { //记录加载过的类 static $_classes = array(); // 已经加载过,直接读取并返回 if (isset($_classes[$class])) { return $_classes[$class]; } $name = FALSE; // 在指定目录寻找要加载的类 foreach (array(APPPATH, BASEPATH) as $path) { if (file_exists($path.$directory.'/'.$class.'.php')) { $name = $prefix.$class; if (class_exists($name) === FALSE) { require($path.$directory.'/'.$class.'.php'); } break; } } // 没有找到 if ($name === FALSE) { exit('Unable to locate the specified class: '.$class.'.php'); } // 追踪记录下刚才加载的类,is_loaded()函数在下面 is_loaded($class); $_classes[$class] = new $name(); return $_classes[$class]; } // 记录已经加载过的类。函数返回所有加载过的类 function &is_loaded($class = '') { static $_is_loaded = array(); if ($class != '') { $_is_loaded[strtolower($class)] = $class; } return $_is_loaded; } //*BASEPATH/system/core/Controller.php class CI_Controller { private static $instance; public function __construct() { self::$instance =& $this; //将所有在引导文件中(CodeIgniter.php)初始化的类对象(即刚才4,5,6,7,8,9等步骤), //注册成为控制器类的成员变量,就使得这个控制器成为一个超级对象(super object) foreach (is_loaded() as $var => $class) { $this->$var =& load_class($class); } <span style="white-space:pre"> </span>//加载Loader对象,再利用Loader对象对程序内一系列资源进行加载<span style="white-space:pre"> </span> $this->load =& load_class('Loader', 'core'); $this->load->initialize(); log_message('debug', "Controller Class Initialized"); } //这个函数对外提供了控制器的单一实例 public static function &get_instance() { return self::$instance; } } //*BASEPATH/system/core/CodeIgniter.php // Load the base controller class require BASEPATH.'core/Controller.php'; //通过这个全局函数就得到了控制器的实例,得到了这个超级对象, //意味着在程序其他地方调用这个函数,就能得到整个框架的控制权 function &get_instance() { return CI_Controller::get_instance(); } // 加载对应的控制器类 // 注意:Router类会自动使用 router->_validate_request() 验证控制器路径 if ( ! file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php')) { show_error('Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.'); } include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php'); $class = $RTR->fetch_class(); //Controller class name $method = $RTR->fetch_method(); //action name //..... // 调用请求的函数 // uri中除了class/function之外的段也会被传递给调用的函数 call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2)); //输出最终的内容到浏览器 if ($EXT->_call_hook('display_override') === FALSE) { $OUT->_display(); } //*BASEPATH/system/core/Loader.php //看一个Loader类加载model的例子。这里只列出了部分代码 public function model($model, $name = '', $db_conn = FALSE) { $CI =& get_instance(); if (isset($CI->$name)) { show_error('The model name you are loading is the name of a resource that is already being used: '.$name); } $model = strtolower($model); //依次根据model类的path进行匹配,如果找到了就加载 foreach ($this->_ci_model_paths as $mod_path) { if ( ! file_exists($mod_path.'models/'.$path.$model.'.php')) { continue; } if ($db_conn !== FALSE AND ! class_exists('CI_DB')) { if ($db_conn === TRUE) { $db_conn = ''; } $CI->load->database($db_conn, FALSE, TRUE); } if ( ! class_exists('CI_Model')) { load_class('Model', 'core'); } require_once($mod_path.'models/'.$path.$model.'.php'); $model = ucfirst($model); //这里依然将model对象注册成控制器类的成员变量。Loader在加载其他资源的时候也会这么做 $CI->$name = new $model(); $this->_ci_models[] = $name; return; } // couldn't find the model show_error('Unable to locate the model you have specified: '.$model); } //*BASEPATH/system/core/Model.php //__get()是一个魔术方法,当读取一个未定义的变量的值时就会被调用 //如下是Model基类对__get()函数的一个实现,使得在Model类内,可以像直接在控制器类内一样(例如$this->var的方式)去读取它的变量 function __get($key) { $CI =& get_instance(); return $CI->$key; }