illuminate/database 使用 一

illuminate/database 是完整的php数据库工具包,即ORM(Object-Relational Mapping)类库。

提供丰富的查询构造器,和多个驱动的服务。作为Laravel的数据库层使用,也可以单独使用。

一 使用

加载composer之后,创建Illuminate\Database\Capsule\Manager对象,配置连接数据后可将其全局化,之后调用全局化的变量使用构造方法等进行查询。

二 代码

require_once './vendor/autoload.php';use Illuminate\Container\Container;
use Illuminate\Database\Capsule\Manager as DB;
use Illuminate\Events\Dispatcher;class BasedDB
{private $config;public function __construct($config){$this->config = ['driver' => 'mysql','host' => $config["host"],'database' => $config["database"],'username' => $config["username"],'password' => $config["password"],'charset' => $config["charset"],'collation' => $config["collation"],'prefix' => $config["prefix"],];$this->init();}public function init(){$db = new DB();$db->addConnection($this->config);$db->setEventDispatcher(new Dispatcher(new Container));$db->setAsGlobal(); //设置静态全局可用$db->bootEloquent();}}class TestDB extends BasedDB
{public function test1(){//构造查询$info = DB::table('userinfo')->where('id', '=', 2)->get();var_dump($info);}
}
$config = ['driver' => 'mysql','host' => 'localhost','database' => 'test','username' => 'root','password' => 'qwe110110','charset' => 'utf8','collation' => 'utf8_general_ci','prefix' => '',
];
$t = new TestDB($config);
$t->test1();

三 原理

从代码可见从Illuminate\Database\Capsule\Manager::addConnection($config)开始。

addConnection仅设置配置。该类的构造参数中包含Illuminate\Container\Container类,通过Manager::setupContainer()函数传入Container类对象,获取绑定的配置。

Container类中Container::bound()判断是否有绑定的内容。使用Container::bind()绑定内容,会删除共享实例中对应的别名内容。绑定时若为指定绑定类的具体类或者说闭包,会自动处理,若未执行则实际处理类为指定的类,利用反射返回对应实例,否则直接返回已有实例。

Manager::setEventDispatcher() 从字面意思是设置事件调度程序。传入参数Illuminate\Events\Dispatcher类实例。通过查看代码,Dispatcher可以用Dispatcher::listen()、Dispatcher::push()、Dispatcher::dispatch()、Dispatcher::until()可以设置监听或调度监听。

Manager::setAsGlobal()将Manager全局化,可以用调用静态对象方法调用。

Manager::bootEloquent()启动Eloquent,其中调用Manager::getEventDispatcher()获取默认的程序调度,Eloquent::setEventDispatcher设置Eloquent的事件调度。Manager::getEventDispatcher()获取绑定的events内容。

到此为止初始化结束,没有出现获取pdo的内容。

调用Manager::table()开始查询,通过调用Manager自己的静态类调用connection,即static::$instance->connection()。

之后调用DatabaseManager::connection()方法。

DatabaseManager通过解析传入的配置名获取配置。若配置名为空则默认为default,可以调用DatabaseManager::setDefaultConnection()设置默认配置名。根据配置名获取配置,通过\Illuminate\Database\Connectors\ConnectionFactory工厂类匹配对应驱动,返回对应pdo对象。

比如返回Illuminate\Database\MySqlConnector对象。该类处理对应驱动特殊处理方法,比如数据库连接、设置事务隔离级别等。

table方法最后调用的是Illuminate\Database\Connection::table(),其为MySqlConnector父类。DatabaseManager::__call($method, $parameters)处理传如的数据并执行,该方法实际返回ConnectionFactory类创建的Illuminate\Database\Query\Builder对象,模式构建器调用结束的时候,将构造器对象作为参数,整合成查询字符串执行查询。

四 源码

1、初始化

根据代码可以绑定config类,或者自定义配置;可以设置events。

//Illuminate\Database\Capsule\Manageruse Illuminate\Container\Container;class Manager
{use CapsuleManagerTrait;protected $manager;/*** Create a new database capsule manager.** @param  \Illuminate\Container\Container|null  $container* @return void*/public function __construct(Container $container = null){$this->setupContainer($container ?: new Container);// Once we have the container setup, we will setup the default configuration// options in the container "config" binding. This will make the database// manager work correctly out of the box without extreme configuration.$this->setupDefaultConfiguration();$this->setupManager();}/*** Register a connection with the manager.** @param  array  $config* @param  string  $name* @return void*/public function addConnection(array $config, $name = 'default'){$connections = $this->container['config']['database.connections'];$connections[$name] = $config;$this->container['config']['database.connections'] = $connections;}/*** Get the current event dispatcher instance.** @return \Illuminate\Contracts\Events\Dispatcher|null*/public function getEventDispatcher(){if ($this->container->bound('events')) {return $this->container['events'];}}/*** Setup the default database configuration options.** @return void*/protected function setupDefaultConfiguration(){$this->container['config']['database.fetch'] = PDO::FETCH_OBJ;$this->container['config']['database.default'] = 'default';}/*** Set the event dispatcher instance to be used by connections.** @param  \Illuminate\Contracts\Events\Dispatcher  $dispatcher* @return void*/public function setEventDispatcher(Dispatcher $dispatcher){$this->container->instance('events', $dispatcher);}/*** Bootstrap Eloquent so it is ready for usage.** @return void*/public function bootEloquent(){Eloquent::setConnectionResolver($this->manager);// If we have an event dispatcher instance, we will go ahead and register it// with the Eloquent ORM, allowing for model callbacks while creating and// updating "model" instances; however, it is not necessary to operate.if ($dispatcher = $this->getEventDispatcher()) {Eloquent::setEventDispatcher($dispatcher);}}
}//Illuminate\Support\Traits\CapsuleManagerTrait
trait CapsuleManagerTrait
{/*** Make this capsule instance available globally.** @return void*/public function setAsGlobal(){static::$instance = $this;}/*** Setup the IoC container instance.** @param  \Illuminate\Contracts\Container\Container  $container* @return void*/protected function setupContainer(Container $container){$this->container = $container;if (! $this->container->bound('config')) {$this->container->instance('config', new Fluent);}}
}//\Illuminate\Contracts\Container\Container
use Illuminate\Contracts\Container\Container as ContainerContract;
class Container implements ArrayAccess, ContainerContract
{/*** Determine if the given abstract type has been bound.** @param  string  $abstract* @return bool*/public function bound($abstract){return isset($this->bindings[$abstract]) ||isset($this->instances[$abstract]) ||$this->isAlias($abstract);}/*** Register a binding with the container.** @param  string  $abstract* @param  \Closure|string|null  $concrete* @param  bool  $shared* @return void** @throws \TypeError*/public function bind($abstract, $concrete = null, $shared = false){$this->dropStaleInstances($abstract);// If no concrete type was given, we will simply set the concrete type to the// abstract type. After that, the concrete type to be registered as shared// without being forced to state their classes in both of the parameters.if (is_null($concrete)) {$concrete = $abstract;}// If the factory is not a Closure, it means it is just a class name which is// bound into this container to the abstract type and we will just wrap it// up inside its own Closure to give us more convenience when extending.if (! $concrete instanceof Closure) {if (! is_string($concrete)) {throw new TypeError(self::class.'::bind(): Argument #2 ($concrete) must be of type Closure|string|null');}$concrete = $this->getClosure($abstract, $concrete);}$this->bindings[$abstract] = compact('concrete', 'shared');// If the abstract type was already resolved in this container we'll fire the// rebound listener so that any objects which have already gotten resolved// can have their copy of the object updated via the listener callbacks.if ($this->resolved($abstract)) {$this->rebound($abstract);}}/*** Register an existing instance as shared in the container.** @param  string  $abstract* @param  mixed  $instance* @return mixed*/public function instance($abstract, $instance){$this->removeAbstractAlias($abstract);$isBound = $this->bound($abstract);unset($this->aliases[$abstract]);// We'll check to determine if this type has been bound before, and if it has// we will fire the rebound callbacks registered with the container and it// can be updated with consuming classes that have gotten resolved here.$this->instances[$abstract] = $instance;if ($isBound) {$this->rebound($abstract);}return $instance;}/*** Remove an alias from the contextual binding alias cache.** @param  string  $searched* @return void*/protected function removeAbstractAlias($searched){if (! isset($this->aliases[$searched])) {return;}foreach ($this->abstractAliases as $abstract => $aliases) {foreach ($aliases as $index => $alias) {if ($alias == $searched) {unset($this->abstractAliases[$abstract][$index]);}}}}
}

2、构造器

//Illuminate\Database\Capsule\Manager
use Illuminate\Database\DatabaseManager;
class Manager
{protected $manager;/*** Create a new database capsule manager.** @param  \Illuminate\Container\Container|null  $container* @return void*/public function __construct(Container $container = null){$this->setupContainer($container ?: new Container);// Once we have the container setup, we will setup the default configuration// options in the container "config" binding. This will make the database// manager work correctly out of the box without extreme configuration.$this->setupDefaultConfiguration();$this->setupManager();}/*** Build the database manager instance.** @return void*/protected function setupManager(){$factory = new ConnectionFactory($this->container);$this->manager = new DatabaseManager($this->container, $factory);}/*** Dynamically pass methods to the default connection.** @param  string  $method* @param  array  $parameters* @return mixed*/public static function __callStatic($method, $parameters){return static::connection()->$method(...$parameters);}/*** Get a connection instance from the global manager.** @param  string|null  $connection* @return \Illuminate\Database\Connection*/public static function connection($connection = null){return static::$instance->getConnection($connection);}/*** Get a registered connection instance.** @param  string|null  $name* @return \Illuminate\Database\Connection*/public function getConnection($name = null){return $this->manager->connection($name);}/*** Get a fluent query builder instance.** @param  \Closure|\Illuminate\Database\Query\Builder|string  $table* @param  string|null  $as* @param  string|null  $connection* @return \Illuminate\Database\Query\Builder*/public static function table($table, $as = null, $connection = null){return static::$instance->connection($connection)->table($table, $as);}
}//Illuminate\Database\DatabaseManager
use Illuminate\Database\Connectors\ConnectionFactory;
/*** @mixin \Illuminate\Database\Connection*/
class DatabaseManager implements ConnectionResolverInterface
{public function __construct($app, ConnectionFactory $factory){$this->app = $app;$this->factory = $factory;$this->reconnector = function ($connection) {$this->reconnect($connection->getNameWithReadWriteType());};}/*** Get a database connection instance.** @param  string|null  $name* @return \Illuminate\Database\Connection*/public function connection($name = null){[$database, $type] = $this->parseConnectionName($name);$name = $name ?: $database;// If we haven't created this connection, we'll create it based on the config// provided in the application. Once we've created the connections we will// set the "fetch mode" for PDO which determines the query return types.if (! isset($this->connections[$name])) {$this->connections[$name] = $this->configure($this->makeConnection($database), $type);}return $this->connections[$name];}/*** Make the database connection instance.** @param  string  $name* @return \Illuminate\Database\Connection*/protected function makeConnection($name){$config = $this->configuration($name);// First we will check by the connection name to see if an extension has been// registered specifically for that connection. If it has we will call the// Closure and pass it the config allowing it to resolve the connection.if (isset($this->extensions[$name])) {return call_user_func($this->extensions[$name], $config, $name);}// Next we will check to see if an extension has been registered for a driver// and will call the Closure if so, which allows us to have a more generic// resolver for the drivers themselves which applies to all connections.if (isset($this->extensions[$driver = $config['driver']])) {return call_user_func($this->extensions[$driver], $config, $name);}return $this->factory->make($config, $name);}
}//Illuminate\Database\Connectors\ConnectionFactory
class ConnectionFactory
{/*** Establish a PDO connection based on the configuration.** @param  array  $config* @param  string|null  $name* @return \Illuminate\Database\Connection*/public function make(array $config, $name = null){$config = $this->parseConfig($config, $name);if (isset($config['read'])) {return $this->createReadWriteConnection($config);}return $this->createSingleConnection($config());}/*** Parse and prepare the database configuration.** @param  array  $config* @param  string  $name* @return array*/protected function parseConfig(array $config, $name){return Arr::add(Arr::add($config, 'prefix', ''), 'name', $name);}/*** Create a read / write database connection instance.** @param  array  $config* @return \Illuminate\Database\Connection*/protected function createReadWriteConnection(array $config){$connection = $this->createSingleConnection($this->getWriteConfig($config));return $connection->setReadPdo($this->createReadPdo($config));}/*** Create a read / write database connection instance.** @param  array  $config* @return \Illuminate\Database\Connection*/protected function createReadWriteConnection(array $config){$connection = $this->createSingleConnection($this->getWriteConfig($config));return $connection->setReadPdo($this->createReadPdo($config));}/*** Create a single database connection instance.** @param  array  $config* @return \Illuminate\Database\Connection*/protected function createSingleConnection(array $config){$pdo = $this->createPdoResolver($config);return $this->createConnection($config['driver'], $pdo, $config['database'], $config['prefix'], $config);}/*** Get the write configuration for a read / write connection.** @param  array  $config* @return array*/protected function getWriteConfig(array $config){return $this->mergeReadWriteConfig($config, $this->getReadWriteConfig($config, 'write'));}/*** Merge a configuration for a read / write connection.** @param  array  $config* @param  array  $merge* @return array*/protected function mergeReadWriteConfig(array $config, array $merge){return Arr::except(array_merge($config, $merge), ['read', 'write']);}/*** Get a read / write level configuration.** @param  array  $config* @param  string  $type* @return array*/protected function getReadWriteConfig(array $config, $type){return isset($config[$type][0])? Arr::random($config[$type]): $config[$type];}/*** Create a single database connection instance.** @param  array  $config* @return \Illuminate\Database\Connection*/protected function createSingleConnection(array $config){$pdo = $this->createPdoResolver($config);return $this->createConnection($config['driver'], $pdo, $config['database'], $config['prefix'], $config);}/*** Create a connector instance based on the configuration.** @param  array  $config* @return \Illuminate\Database\Connectors\ConnectorInterface** @throws \InvalidArgumentException*/public function createConnector(array $config){if (!isset($config['driver'])) {throw new InvalidArgumentException('A driver must be specified.');}if ($this->container->bound($key = "db.connector.{$config['driver']}")) {return $this->container->make($key);}switch ($config['driver']) {case 'mysql':return new MySqlConnector;case 'pgsql':return new PostgresConnector;case 'sqlite':return new SQLiteConnector;case 'sqlsrv':return new SqlServerConnector;}throw new InvalidArgumentException("Unsupported driver [{$config['driver']}].");}/*** Create a new connection instance.** @param  string  $driver* @param  \PDO|\Closure  $connection* @param  string  $database* @param  string  $prefix* @param  array  $config* @return \Illuminate\Database\Connection** @throws \InvalidArgumentException*/protected function createConnection($driver, $connection, $database, $prefix = '', array $config = []){if ($resolver = Connection::getResolver($driver)) {return $resolver($connection, $database, $prefix, $config);}switch ($driver) {case 'mysql':return new MySqlConnection($connection, $database, $prefix, $config);case 'pgsql':return new PostgresConnection($connection, $database, $prefix, $config);case 'sqlite':return new SQLiteConnection($connection, $database, $prefix, $config);case 'sqlsrv':return new SqlServerConnection($connection, $database, $prefix, $config);}throw new InvalidArgumentException("Unsupported driver [{$driver}].");}
}//Illuminate\Database\MySqlConnection
class MySqlConnection extends Connection
{
}//Illuminate\Database\Connection
use Illuminate\Database\Query\Builder as QueryBuilder;
class Connection implements ConnectionInterface
{/*** Begin a fluent query against a database table.** @param  \Closure|\Illuminate\Database\Query\Builder|string  $table* @param  string|null  $as* @return \Illuminate\Database\Query\Builder*/public function table($table, $as = null){return $this->query()->from($table, $as);}/*** Get a new query builder instance.** @return \Illuminate\Database\Query\Builder*/public function query(){return new QueryBuilder($this, $this->getQueryGrammar(), $this->getPostProcessor());}
}//Illuminate\Database\Query\Builder
class Builder
{/*** Set the table which the query is targeting.** @param  \Closure|\Illuminate\Database\Query\Builder|string  $table* @param  string|null  $as* @return $this*/public function from($table, $as = null){if ($this->isQueryable($table)) {return $this->fromSub($table, $as);}$this->from = $as ? "{$table} as {$as}" : $table;return $this;}/*** Determine if the value is a query builder instance or a Closure.** @param  mixed  $value* @return bool*/protected function isQueryable($value){return $value instanceof self ||$value instanceof EloquentBuilder ||$value instanceof Relation ||$value instanceof Closure;}/*** Makes "from" fetch from a subquery.** @param  \Closure|\Illuminate\Database\Query\Builder|string  $query* @param  string  $as* @return $this** @throws \InvalidArgumentException*/public function fromSub($query, $as){[$query, $bindings] = $this->createSub($query);return $this->fromRaw('('.$query.') as '.$this->grammar->wrapTable($as), $bindings);}……//之后都是构建构造器的 没调试 看的也不是太懂
}

注:

本地使用php版本7.4,illuminate/database为v8.83.27

illuminate/database composer地址:illuminate/database - Packagist

illuminate/database girbub地址:GitHub - illuminate/database: [READ ONLY] Subtree split of the Illuminate Database component (see laravel/framework)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/115679.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自然语言处理---迁移学习

fasttext介绍 作为NLP工程领域常用的工具包,fasttext有两大作用:进行文本分类、训练词向量。在保持较高精度的情况下,快速的进行训练和预测是fasttext的最大优势。fasttext优势的原因: fasttext工具包中内含的fasttext模型具有十分简单的网络…

01-React入门

React概述 react是什么? React用于构建用户界面的JS库。是一个将数据渲染为HTML视图的开源JS库。 为什么学? 1.原生JS操作DOM繁琐,效率低 2.使用JS直接操作DOM,浏览器会进行大量的重绘重排 3.原生JS没有组件化编码方案,代码…

2024 王道考研-数据结构

第二章 线性表算法题(线性表的顺序表示) 二、综合应用题 01.从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删元素的值。空出的位 置由最后一个元素填补,若顺序表为空,则显示出错信息并退出运行。 算法思想:搜索整个顺序表&#xf…

Python之PyMySQL操作详解

一、PyMysql简介 PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb。 Django中也可以使用PyMySQL连接MySQL数据库。 二、PyMySQL操作详解 2.1 PyMySQL安装 pip install pymysql2.2 PyMySQL应用 2.2.1 基本使用 # codingut…

【Leetcode】 213. 打家劫舍 II ?

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚…

sql server2014如何添加多个实例 | 以及如何删除多个实例中的单个实例

标题sql server2014如何添加多个实例 前提(已安装sql server2014 且已有默认实例MSSQLSERVER) 添加新的实例 其实就是根据安装步骤再安装一次(区别在过程中说明) 双击安装 选择“全新独立安装或添加现有功能” 然后下一步下一…

Apache Shiro 1.2.4反序列化漏洞(CVE-2016-4437)

介绍 Apache Shiro是一款开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用,同时也能提供健壮的安全性。 版本 Apache Shiro 1.2.4及以前版本中 原理 不安全的配置 默认账户在里面 Apache Shiro 1.2.4及以前版本中&#x…

C++学习之强制类型转换

强制类型转换运算符 带着三个疑问阅读: 出现的背景是什么?何时使用?如何使用? MSDN . 强制转换运算符 C中的四种强制类型转换符详解 static_cast (1) 使用场景 在基本数据类型之间转换,如把 int 转换为 char&#…

pkg-config使用

作用:pkg-config是linux中的应用程序,可以方便导入第三方模块的头文件和库文件。很多模块是支持pkg-config的,这些模块(如dpdk)在编译安装后会生成**.pc**后缀的文件,pkg-config通过pc文件可以知道模块的头…

Python 数组和列表:创建、访问、添加和删除数组元素

Python 没有内置支持数组,但可以使用 Python 列表来代替。 数组 本页将向您展示如何使用列表作为数组,但要在 Python 中使用数组,您需要导入一个库,比如 NumPy 库。数组用于在一个变量中存储多个值: 示例&#xff0…

大数据学习(17)-mapreduce task详解

&&大数据学习&& 🔥系列专栏: 👑哲学语录: 承认自己的无知,乃是开启智慧的大门 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一下博主哦&#x1f91…

重生奇迹mu宠物带来不一样的体验

重生奇迹mu宠物有什么作用? 全新版本中更是推出了各种宠物,在玩游戏时还可以带着宠物,一起疯狂的刷怪等等,可以为玩家带来非常不错的游戏体验,那么下面就来给大家说说各种宠物适合做什么事情。 1、强化恶魔适合刷怪 …

java头歌-java中的异常

文章目录 第一关第二关第三关第四关 第一关 第二关 题目要求: public static void main(String[] args) {Scanner sc new Scanner(System.in);try {int num1 sc.nextInt();int num2 sc.nextInt();/********* Begin *********/System.out.println(num1/num2);}…

【SA8295P 源码分析 (四)】21 - Android GVM 虚拟网络 vlan 配置

【SA8295P 源码分析】21 - Android GVM 虚拟网络 vlan 配置 一、Android GVM 虚拟网络 vlan 配置二、网络验证三、网桥配置:让 Android GVM 可以通过 emac 访问外网四、兼容前后排车机:使用 QNX 环境变量进行区分五、动态修改 mac 地址六、VLAN原理系列文章汇总见:《【SA829…

Redis | 在Java中操作Redis

在Java中操作Redis: 第一步: pom.xml文件中导入maven依赖第二步: 在application.yml配置文件中 配置Redis数据源第三步: 编写RedisConfiguration配置类,创建RedisTemplate对象第四步: 通过RedisTemplate对象操作Redis / Redis中的数据4.1 操作“字符串St…

CNN——卷积神经网络

文章目录 多层感知机(MLP,Multilayer Perceptron)神经网络定义MLP与神经网络的异同相同之处:不同之处:总结 为什么要使用神经网络CNN卷积层:池化层:全连接层: 卷积神经网络的优势pad…

Python---while循环的执行流程 解释

使用Debug调试工具&#xff0c;查看while循环的运行流程 代码 # ① 初始化计数器 i 1 # ② 编写循环条件&#xff08;判断计数器是否达到了100&#xff09; while i < 100:print(f{i 1}、老婆大人&#xff0c;我错了)# ③ 在循环体内部更新计数器i 1 ① 代码都是顺序执行…

基于LSTM的天气预测 - 时间序列预测 计算机竞赛

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 机器学习大数据分析项目 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/po…

如何为 Elasticsearch 创建自定义连接器

了解如何为 Elasticsearch 创建自定义连接器以简化数据摄取过程。 作者&#xff1a;JEDR BLASZYK Elasticsearch 拥有一个摄取工具库&#xff0c;可以从多个来源获取数据。 但是&#xff0c;有时你的数据源可能与 Elastic 现有的提取工具不兼容。 在这种情况下&#xff0c;你可…