CodeIgnitor 3.0.x 之 db 类实现机制

yizhihongxing
  • Codeignitor 的 db 类的说明,锻炼一下文字表达能力

  • 一般的使用场景:

class home extends Base_Controller
{    
    public function test()  
    {
        $this->load->model('my/User_model');
    }
}

class User_model extend CI_Model  
{
    public function __construct()  
    {
       $this->db = $this->load->database('my', TRUE);
    }
}

class CI_Model
{
    public function __get($key)  
    {  
        return get_instance()->$key;  
    }
}
  • 在 controller 中加载 model 类

  • 在 model 中加载 db,获得 db 对象,可以用来查询 sql

    • model 中的 load 对象是从 controller 中获取的
    • db 对象的类型是 CI_DB_mysqli_driver,这是 load 对象根据默认配置创建的 mysql 数据库查询对象
    • 默认配置文件在 /config/database.php,按照框架约定配置好数据库参数
  • database.php 内容如下:

$active_group = 'default';  
$query_builder = TRUE;
$db['default'] = array(
    $db['myche'] = array(  
         'dsn' => '',  
         'hostname' => $_SERVER['DB_MY_HOST'],  
         'username' => $_SERVER['DB_MY_USER'],  
         'password' => $_SERVER['DB_MY_PASS'],  
         'database' => $_SERVER['DB_MY_NAME'],  
         'dbdriver' => 'mysqli',  
         'dbprefix' => '',  
         'pconnect' => FALSE,  
         'db_debug' => (ENVIRONMENT !== 'production'),  
         'cache_on' => FALSE,  
         'cachedir' => '',  
         'char_set' => 'utf8',  
         'dbcollat' => 'utf8_general_ci',  
         'swap_pre' => '',  
         'encrypt' => FALSE,  
         'compress' => FALSE,  
         'stricton' => FALSE,  
         'failover' => array(),  
         'save_queries' => (ENVIRONMENT !== 'production')  
    );
);
  • CI_DB_mysqli_driver 继承自 CI_DBCI_DB 类使用了一种奇怪的方式实现的,这个类是在一个叫做DB的函数内声明的,根据 $query_builder=true 的配置来决定声明CI_DB的父类是CI_DB_driver还是CI_DB_query_builder,两者的区别就是后者继承自前者并在前者的基础上实现了常用语句的链式调用方法。按照声明处注释所说,CI_DB类可以理解为 CI_DB_driverCI_DB_query_builder 的别名。

  • CI_DB_mysqli_driver的创建过程:

    • 在 load 对象的 database 方法中调用 DB 函数
    • 在 DB 函数中
      • 声明 CI_DB,根据 $query_builder=true 的配置来决定CI_DB的父类是CI_DB_driver还是CI_DB_query_builder
      • 根据 dbdriver 配置加载数据库驱动类文件,并实例化 CI_DB_mysqli_driver,并返回此对象。
  • DB 函数的实现

function &DB($params = '', $query_builder_override = NULL)  
{
    require_once(BASEPATH.'database/DB_driver.php');
    
    if ( ! isset($query_builder) OR $query_builder === TRUE)
	{
		require_once(BASEPATH.'database/DB_query_builder.php');
		if ( ! class_exists('CI_DB', FALSE))
		{
			/**
			 * CI_DB
			 *
			 * Acts as an alias for both CI_DB_driver and CI_DB_query_builder.
			 *
			 * @see	CI_DB_query_builder
			 * @see	CI_DB_driver
			 */
			class CI_DB extends CI_DB_query_builder { }
		}
	}
	elseif ( ! class_exists('CI_DB', FALSE))
	{
		class CI_DB extends CI_DB_driver { }
	}
    
    // Load the DB driver  
    $driver_file = BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php';
    require_once($driver_file);
    
    // Instantiate the DB adapter
	$driver = 'CI_DB_'.$params['dbdriver'].'_driver';
	$DB = new $driver($params);
    
    return $DB;
}
  • CI_DB_mysqli_driver 最终是继承自 CI_DB_driver 这个抽象类。CI_DB_driver 定义了数据库驱动类需要实现的一些通用方法,具体的驱动类比如 CI_DB_mysqli_driver 则实现了这些方法。

  • CI_DB_driver 关键方法定义

abstract class CI_DB_driver {
    // db 连接
    function db_connect() {}
        
    // db 长连接
    function db_pconnect() {}
    
    // 设置连接字符集编码
    function _db_set_charset() {}
    
    // 选择数据库
    function db_select() {}
    
    // 开始事务
    function _trans_begin() {}
    
    // 回滚事务
    function _trans_rollback() {}
    
    // 提交事务
    function _trans_commit() {}
    
    // 执行查询
    function _execute($sql) {}
}

上面的描述总结为下图:

CodeIgnitor 3.0.x 之 db 类实现机制

  • CI_DB_mysqli_driver 的部分实现
class CI_DB_mysqli_driver extends CI_DB {
    // 连接数据库
    public function db_connect($persistent = FALSE)  
    {
        // Do we have a socket path?
		if ($this->hostname[0] === '/')
		{
			$hostname = NULL;
			$port = NULL;
			$socket = $this->hostname;
		}
		else
		{
			// Persistent connection support was added in PHP 5.3.0
			$hostname = ($persistent === TRUE && is_php('5.3'))
				? 'p:'.$this->hostname : $this->hostname;
			$port = empty($this->port) ? NULL : $this->port;
			$socket = NULL;
		}

		$client_flags = ($this->compress === TRUE) ? MYSQLI_CLIENT_COMPRESS : 0;
		$this->_mysqli = mysqli_init();

		$this->_mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 10);
        
        // ... 此处省略一些设置的代码
        
        if ($this->_mysqli->real_connect($hostname, $this->username, $this->password, $this->database, $port, $socket, $client_flags))
		{
			// Prior to version 5.7.3, MySQL silently downgrades to an unencrypted connection if SSL setup fails
			if (
				($client_flags & MYSQLI_CLIENT_SSL)
				&& version_compare($this->_mysqli->client_info, '5.7.3', '<=')
				&& empty($this->_mysqli->query("SHOW STATUS LIKE 'ssl_cipher'")->fetch_object()->Value)
			)
			{
				$this->_mysqli->close();
				$message = 'MySQLi was configured for an SSL connection, but got an unencrypted connection instead!';
				log_message('error', $message);
				return ($this->db->db_debug) ? $this->db->display_error($message, '', TRUE) : FALSE;
			}

			return $this->_mysqli;
		}

		return FALSE;
    }
}
  • 这里 mysqli_init 函数是 php 扩展自带的函数,返回的是 php 的 resource 类型的对象,即 mysqli 对象,这个对象可以用来查询数据库。

  • 再看下 CI_DB_query_builder 的部分实现,主要的功能是基于 driver 的方法,实现很多人性化的、可以链式调用的方法。

abstract class CI_DB_query_builder extends CI_DB_driver
{
    public function limit($value, $offset = 0)
	{
		is_null($value) OR $this->qb_limit = (int) $value;
		empty($offset) OR $this->qb_offset = (int) $offset;

		return $this;
	}
    
    public function offset($offset)
	{
		empty($offset) OR $this->qb_offset = (int) $offset;
		return $this;
	}
    
    public function get($table = '', $limit = NULL, $offset = NULL)
	{
		if ($table !== '')
		{
			$this->_track_aliases($table);
			$this->from($table);
		}

		if ( ! empty($limit))
		{
			$this->limit($limit, $offset);
		}

		$result = $this->query($this->_compile_select());
		$this->_reset_select();
		return $result;
	}
    
    function select() {}
    function distinct() {}
    function join() {}
    function from() {}
    function where() {}
    function or_where() {}
    function like() {}
    function group_by() {}
    function having() {}
    function update() {}
    
    // ...
}

原文链接:https://www.cnblogs.com/feiffy/p/codeignitor3-db-class.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:CodeIgnitor 3.0.x 之 db 类实现机制 - Python技术站

(0)
上一篇 2023年4月17日
下一篇 2023年4月17日

相关文章

  • php单一接口的实现方法

    PHP单一接口的实现方法是通过使用接口编程规范,将所有与类相关联的方法定义在一个接口中,从而达到代码复用和重构的目的。 以下是实现PHP单一接口的步骤: 定义一个接口:定义接口时是使用interface关键字。 接口应该描述了所有相关对象的一般性特征,而不是特定对象的细节 interface Shape { public function area(); p…

    PHP 2023年5月27日
    00
  • PHP定时执行任务的3种方法详解

    PHP定时执行任务的3种方法详解 在Web开发中,经常会需要定时执行某些任务,比如清理缓存、备份数据等。PHP作为一种流行的Web编程语言,自然也提供了实现定时任务的方法。本文将详细介绍PHP定时执行任务的3种方法,分别是: 1.使用PHP内置的定时器实现 2.使用Crontab实现 3.使用外部工具库实现 使用PHP内置的定时器实现 PHP提供了set_t…

    PHP 2023年5月23日
    00
  • PHP获取当前所在目录位置的方法

    当你在编写PHP脚本时,经常需要获取当前所在目录的位置,比如读取文件、打开文件等操作的时候。在PHP中,获取当前所在目录位置的方法有以下两个: 方法一:使用 DIR 魔术常量 在PHP中,__DIR__是一个魔术常量,它表示当前所在目录的路径。可以通过在脚本中使用__DIR__常量来获取当前目录位置。示例代码如下: <?php $current_dir…

    PHP 2023年5月26日
    00
  • php读取本地文件常用函数(fopen与file_get_contents)

    当我们需要在PHP中读取本地文件时,我们通常会使用两种不同的函数:fopen和file_get_contents。 fopen fopen函数用于打开一个文件,并返回其指针。我们可以使用这个指针来读取文件的内容,或者将内容写入文件中。以下是使用fopen函数读取本地文件的基本步骤: 打开文件:使用fopen函数打开文件,需要提供文件路径和打开方式(读、写、追…

    PHP 2023年5月26日
    00
  • 浅析php中array_map和array_walk的使用对比

    以下是“浅析PHP中array_map和array_walk的使用对比”的完整攻略。 概述 array_map 和 array_walk 都是 PHP 对数组进行处理的函数,它们分别有各自的优劣点,下面我们就来对它们进行详细的对比分析。 array_map 函数 语法 array_map (callable $callback, array …$arrs…

    PHP 2023年5月26日
    00
  • PHP创建自己的Composer包方法

    当我们编写PHP代码时,可能经常需要用到别人写的第三方库或者组建,这时候可以使用Composer来管理这些依赖软件包。在实际开发中,我们可能也会有自己写的一些通用性的代码,这时候可以将这些代码打包成一个Composer包进行管理,方便复用。 下面是创建自己的Composer包的基本步骤。 创建Composer包的基本步骤 步骤一:创建一个PHP项目 在你的本…

    PHP 2023年5月26日
    00
  • PHP中数据库单例模式的实现代码分享

    想要在PHP中使用单例模式来管理数据库连接,需要遵循以下步骤: 1. 定义一个单例类 首先,我们需要定义一个单例类来负责创建和维护数据库连接。这个类应该只有一个实例,并且应该提供一个方法来获得这个实例。以下是一个简单的示例代码: class Database { private static $instance = null; private $connec…

    PHP 2023年5月23日
    00
  • php foreach如何跳出两层循环(详解)

    在PHP中,可以使用for、while、do-while等多种循环结构循环遍历数组,但是foreach循环结构相比其他循环结构更加方便简洁。在某些情况下,我们需要从嵌套的foreach循环中跳出,具体细节如下: 使用break 2语句 在foreach循环中,我们可以使用break关键字来跳出当前的循环,但是如果有嵌套的循环,break只能跳出当前的循环。为…

    PHP 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部