CodeIgniter 源码解读之模型
模型
啥是模型?模型是干嘛的?CI中的模型(Model)又是如何工作的?这篇我们就来看看吧~~
首先,我们习惯性的打开 core 目录,瞧瞧是否有个文件名有 model 的字段,哦豁~ 还真有(Model.php),赶紧双击打开看看吧。
class CI_Model {/*** Class constructor** @link https://github.com/bcit-ci/CodeIgniter/issues/5332* @return void*/public function __construct() {}/*** __get magic** Allows models to access CI's loaded classes using the same* syntax as controllers.** @param string $key*/# 这是个php的魔术方法,当对象获取一个不存在的类对象时,会自动调用该方法.# 这里的作用是,让模型中可以按 控制器 中的 调用方法的方式,如:$this->load->model()此类# 至于如何工作的,下面会说明public function __get($key){// Debugging note:// If you're here because you're getting an error message// saying 'Undefined Property: system/core/Model.php', it's// most likely a typo in your model code.return get_instance()->$key;}}
鉴于,模型基类太过简单,接下来我们看下:
1、我们在控制器中是如何加载模型及模型的加载原理。
2、模型连接数据库的原理
在实际项目中,我经常这样引用模型,下面我写了个Test控制器及Test_model模型,代码如下:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');class Test extends CI_Controller {/*** Test Page for this controller.* /public function __construct() {parent::__construct();# 加载模型$this->load->model('Test_model');}public function index(){echo $this->Test_model->list();}
}
<?phpdefined('BASEPATH') OR exit('No direct script access allowed');/**
* 测试模型
*/
class Test_model extends CI_Model
{function __construct(){parent::__construct();# 加载数据库$this->load->database();}# 返回列表public function list() {return 'list';}
}
我们先看控制器Test类中的构造方法有这么一行:$this->load->model(‘Test_model’),上一篇中的控制器中已经提到了 $this 这个超级对象(忘记的可以回到上一篇再看下),这里,我们可以看到它调用了load(Loader类实例)对象的model方法,代码走起~~
/*** Model Loader** Loads and instantiates models.** @param mixed $model Model name* @param string $name An optional object name to assign to* @param bool $db_conn An optional database connection configuration to initialize* @return object*/public function model($model, $name = '', $db_conn = FALSE){# 如果为空则返回if (empty($model)){return $this;}elseif (is_array($model)){# $model 可接受数组,所以这里循环数组调用了 model 方法foreach ($model as $key => $value){# 由于我们在控制器中加载模型时,可以给模型弄个别名# 所以这里加了一个判断,如果是普通数组的话则直接加载# 若是索引数组的话,他会将$key作为模型名,$value作为别名加载is_int($key) ? $this->model($value, '', $db_conn) : $this->model($key, $value, $db_conn);}return $this;}$path = '';// Is the model in a sub-folder? If so, parse out the filename and path.# 如果模型名中带有 / 则说明他是在 models目录的子目录中# 得到最后一个 / 所在的位置if (($last_slash = strrpos($model, '/')) !== FALSE){// The path is in front of the last slash# 分割出目录 如:blog/v1/$path = substr($model, 0, ++$last_slash);// And the model name behind it# 分割出模型名$model = substr($model, $last_slash);}# 将 $model 赋值给 $nameif (empty($name)){$name = $model;}# 若这个模型已经被加载则跳出函数if (in_array($name, $this->_ci_models, TRUE)){return $this;}# 调用 CodeIgniter.php 中的 get_instance() 方法,获取 超级对象$CI =& get_instance();# 判断当前需要加载的模型名是否存在于 超级 对象中# 若存在,则抛出异常:说明该名称已被框架核心类名占用if (isset($CI->$name)){throw new RuntimeException('The model name you are loading is the name of a resource that is already being used: '.$name);}# 是否自动连接数据库if ($db_conn !== FALSE && ! class_exists('CI_DB', FALSE)){if ($db_conn === TRUE){$db_conn = '';}# 连接数据库$this->database($db_conn, FALSE, TRUE);}// Note: All of the code under this condition used to be just://// load_class('Model', 'core');//// However, load_class() instantiates classes// to cache them for later use and that prevents// MY_Model from being an abstract class and is// sub-optimal otherwise anyway.# 加载模型基类及自定义的前缀模型(MY_开头的)if ( ! class_exists('CI_Model', FALSE)){$app_path = APPPATH.'core'.DIRECTORY_SEPARATOR;if (file_exists($app_path.'Model.php')){require_once($app_path.'Model.php');if ( ! class_exists('CI_Model', FALSE)){throw new RuntimeException($app_path."Model.php exists, but doesn't declare class CI_Model");}log_message('info', 'CI_Model class loaded');}elseif ( ! class_exists('CI_Model', FALSE)){require_once(BASEPATH.'core'.DIRECTORY_SEPARATOR.'Model.php');}# 尝试拼装自定义的模型类文件名,如(MY_Model),并尝试加载$class = config_item('subclass_prefix').'Model';if (file_exists($app_path.$class.'.php')){require_once($app_path.$class.'.php');if ( ! class_exists($class, FALSE)){throw new RuntimeException($app_path.$class.".php exists, but doesn't declare class ".$class);}log_message('info', config_item('subclass_prefix').'Model class loaded');}}# 模型类名首字母大写$model = ucfirst($model);if ( ! class_exists($model, FALSE)){foreach ($this->_ci_model_paths as $mod_path){if ( ! file_exists($mod_path.'models/'.$path.$model.'.php')){continue;}require_once($mod_path.'models/'.$path.$model.'.php');if ( ! class_exists($model, FALSE)){throw new RuntimeException($mod_path."models/".$path.$model.".php exists, but doesn't declare class ".$model);}break;}if ( ! class_exists($model, FALSE)){throw new RuntimeException('Unable to locate the model you have specified: '.$model);}}elseif ( ! is_subclass_of($model, 'CI_Model')){throw new RuntimeException("Class ".$model." already exists and doesn't extend CI_Model");}# 将模型名加入到数组中,方便调用$this->_ci_models[] = $name;# 实例化模型类$model = new $model();# 赋值,如加载Test_model 后,则可以使用 $this->Test_model->method() 方式$CI->$name = $model;log_message('info', 'Model "'.get_class($model).'" initialized');return $this;}
连接数据库代码如下:
/*** Database Loader** @param mixed $params Database configuration options* @param bool $return Whether to return the database object* @param bool $query_builder Whether to enable Query Builder* (overrides the configuration setting)** @return object|bool Database object if $return is set to TRUE,* FALSE on failure, CI_Loader instance in any other case*/public function database($params = '', $return = FALSE, $query_builder = NULL){// Grab the super object# 同样获取 超级 对象$CI =& get_instance();// Do we even need to load the database class?# 一系列的条件判断if ($return === FALSE && $query_builder === NULL && isset($CI->db) && is_object($CI->db) && ! empty($CI->db->conn_id)){return FALSE;}# 引入 DB 文件require_once(BASEPATH.'database/DB.php');# 如果$return为TRUE,表示需要返回数据库(DB)对象if ($return === TRUE){# 这里调用DB 方法进行初始化数据库连接对象return DB($params, $query_builder);}// Initialize the db variable. Needed to prevent// reference errors with some configurations$CI->db = '';// Load the DB class# 获取数据库连接对象,并赋值给$CI->db$CI->db =& DB($params, $query_builder);return $this;}
如果我们在控制器中加载模型时,使用 FALSE 标识后,我们可以在自己的模型文件的构造方法中,使用 $this->load-database()获取数据库实例:
<?phpdefined('BASEPATH') OR exit('No direct script access allowed');/**
* 测试模型
*/
class Test_model extends CI_Model
{function __construct(){parent::__construct();# 这里同样使用了 load 类的 database 方法$this->load->database();}public function list() {return 'list';}
}
好啦!这期的模型就讲完了,是不是很简单,哦,还有一点,CI加载数据库是,会根据 application\config\database.php配置去加载你配置的驱动类,根据不同的驱动是实现不同的数据库连接,这里你可以去看一下 system\database 目录的内容。
现在,我们总结一下,模型类在加载的时候,会做三件事:
1、加载框架的核心模型基类
2、实例化加载的模型,并将它赋值给 超级 对象,这样,我们就能通过 $this 去方便调用它
3、如果配置的 TRUE 标识,这会自动加载数据库连接,我一般都是手动加载的。
ok,我们下一期会带大家学习 CI 的 视图(View)是如何工作的?再会~~
CodeIgniter 源码解读之模型相关推荐
- Bert系列(二)——源码解读之模型主体
本篇文章主要是解读模型主体代码modeling.py.在阅读这篇文章之前希望读者们对bert的相关理论有一定的了解,尤其是transformer的结构原理,网上的资料很多,本文内容对原理部分就不做过多 ...
- CodeIgniter源码解读
优雅的 CodeIgniter CodeIgniter 是一个小巧但功能强大的 PHP 框架,作为一个简单而"优雅"的工具包,它可以为开发者们建立功能完善的 Web 应用程序. 大 ...
- SMPL模型及源码解读
Contents Preface 一.模型解读 二.源码解读 Citation Preface SMPL主要是人体三维重建常用模型,本文主要对模型及源码进行了解读(自己的理解不一定正确),为以后更好的 ...
- IOCP 网络通讯模型源码解读
From: http://hi.baidu.com/tsingsing/item/1aa5062fa27791fa50fd87b7 以前写服务器的时候用的是iocp,最近偶然发现windows的 网络 ...
- Pseudo-document-based Topic Model(基于伪文档的主题模型)的理解以及源码解读
本文作者:合肥工业大学 管理学院 钱洋 email:1563178220@qq.com 内容可能有不到之处,欢迎交流. 未经本人允许禁止转载. 论文来源 Zuo Y, Wu J, Zhang H, e ...
- PTMs:QLoRA技巧之源码解读(qlora.py文件)—解析命令与加载参数→数据预处理→模型训练+评估+推理
PTMs:QLoRA技巧之源码解读(qlora.py文件)-解析命令与加载参数→数据预处理→模型训练+评估+推理 目录 QLoRA技巧之源码解读(qlora.py文件)-解析命令与加载参数→数据预处理 ...
- Bert系列(三)——源码解读之Pre-train
https://www.jianshu.com/p/22e462f01d8c pre-train是迁移学习的基础,虽然Google已经发布了各种预训练好的模型,而且因为资源消耗巨大,自己再预训练也不现 ...
- PyTorch 源码解读之即时编译篇
点击上方"AI遇见机器学习",选择"星标"公众号 重磅干货,第一时间送达 作者丨OpenMMLab 来源丨https://zhuanlan.zhihu.com/ ...
- Alamofire源码解读系列(九)之响应封装(Response)
本篇主要带来Alamofire中Response的解读 前言 在每篇文章的前言部分,我都会把我认为的本篇最重要的内容提前讲一下.我更想同大家分享这些顶级框架在设计和编码层次究竟有哪些过人的地方?当然, ...
最新文章
- 【漫画】以后在有面试官问你AVL树,你就把这篇文章扔给他。
- 列举在移动Web开发中经常会设置的特殊样式!
- Java编程测试1M内存可用来缓存多少对象
- 雷达多普勒频率计算公式_智能驾驶之眼-毫米波雷达技术详解
- 【整理】爬取网页数据的方法汇总
- 极验验证——滑块拼图验证码
- 算法系列:Reservoir Sampling
- 数据管理平台(DMP)
- 【pyqt5学习】—— 滑动条Qslider、计数器QSpinBox学习
- 高通QCS603/QCS605物联网系统芯片介绍,QCS603/QCS605处理器参数比较
- Android - 简单的查看APP启动时间
- ESP8266-01s MQTT固件烧录
- Gym - 100519 B Bring Your Own Bombs 离散化+二分+思维
- CNMOOC-os- ch2硬件基础
- 期货中的正向交易与反向交易
- android中文件加密和解密的实现
- 解码聊天机器人技术:权威指南
- Tkinter布局grid、pack、place参数详解
- 安卓 Handler 消息机制(总)
- 45中漂亮的自由字体用于现代的设计趋势