• illuminate/database 使用 一


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

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

    一 使用

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

    二 代码

    1. require_once './vendor/autoload.php';
    2. use Illuminate\Container\Container;
    3. use Illuminate\Database\Capsule\Manager as DB;
    4. use Illuminate\Events\Dispatcher;
    5. class BasedDB
    6. {
    7. private $config;
    8. public function __construct($config)
    9. {
    10. $this->config = [
    11. 'driver' => 'mysql',
    12. 'host' => $config["host"],
    13. 'database' => $config["database"],
    14. 'username' => $config["username"],
    15. 'password' => $config["password"],
    16. 'charset' => $config["charset"],
    17. 'collation' => $config["collation"],
    18. 'prefix' => $config["prefix"],
    19. ];
    20. $this->init();
    21. }
    22. public function init()
    23. {
    24. $db = new DB();
    25. $db->addConnection($this->config);
    26. $db->setEventDispatcher(new Dispatcher(new Container));
    27. $db->setAsGlobal(); //设置静态全局可用
    28. $db->bootEloquent();
    29. }
    30. }
    31. class TestDB extends BasedDB
    32. {
    33. public function test1()
    34. {
    35. //构造查询
    36. $info = DB::table('userinfo')->where('id', '=', 2)->get();
    37. var_dump($info);
    38. }
    39. }
    40. $config = [
    41. 'driver' => 'mysql',
    42. 'host' => 'localhost',
    43. 'database' => 'test',
    44. 'username' => 'root',
    45. 'password' => 'qwe110110',
    46. 'charset' => 'utf8',
    47. 'collation' => 'utf8_general_ci',
    48. 'prefix' => '',
    49. ];
    50. $t = new TestDB($config);
    51. $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对象,模式构建器调用结束的时候,将构造器对象作为参数,整合成查询字符串执行查询。

    四、构造调用

    以例子中代码为例,数据库静态类为DB。

    1. //$columns 数组 $column 字符串 $groups 数组 $type 包括asc(正序)和desc(倒叙)
    2. $obj = DB::table("table_name")->select($columns)
    3. ->distinct()->addSelect($column)->where($where)
    4. ->groupBy($groups)->having($having)
    5. ->orderBy($column,$type);
    6. $info = $obj->get()
    7. //返回为Illuminate\Support\Collection对象
    8. //select 包含子集
    9. $query = "avg(age)";
    10. $info = DB::table('userinfo')->selectSub($query, 'avg')->get();
    11. $query = "avg(age)+:num as avg";
    12. $info = Capsule::table('userinfo')->selectRaw($query, ['num' => 1])->get();
    13. //join
    14. function test8()
    15. {
    16. Capsule::enableQueryLog();
    17. $info1 = Capsule::table('userinfo')
    18. ->select('id', Capsule::raw('MAX(age) as max_age'))
    19. ->where('age', '>', 1)
    20. ->whereRaw('LENGTH(name)>= ? ', [5], "or")
    21. ->groupBy('id');
    22. $info2 = Capsule::table('userinfo', "u")->select(['u.*'])->joinSub($info1, 'tab1', function ($join) {
    23. $join->on('u.id', '=', 'tab1.id');
    24. })->get();
    25. //var_dump($info2->all());
    26. $logs = Capsule::getQueryLog();
    27. var_dump(end($logs));
    28. }
    29. test8();
    30. //输出结果
    31. array(3) {
    32. 'query' =>
    33. string(184) "select `u`.* from `userinfo` as `u` inner join (select `id`, MAX(age) as max_age from `userinfo` where `age` > ? or LENGTH(name)>= ? group by `id`) as `tab1` on `u`.`id` = `tab1`.`id`"
    34. 'bindings' =>
    35. array(2) {
    36. [0] =>
    37. int(1)
    38. [1] =>
    39. int(5)
    40. }
    41. 'time' =>
    42. double(7.27)
    43. }

    使用Builder对象就需要遵守它的规则,比如写了max()这种统计查询的内容,必须使用groupBy()查询,不然报错”In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'test.userinfo.id';  this is incompatible with sql_mode=only_full_group_by in“。

    相对起来,使用复杂查询,用查询构造还是比较麻烦。

    五 源码

    5.1 初始化

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

    1. //Illuminate\Database\Capsule\Manager
    2. use Illuminate\Container\Container;
    3. class Manager
    4. {
    5. use CapsuleManagerTrait;
    6. protected $manager;
    7. /**
    8. * Create a new database capsule manager.
    9. *
    10. * @param \Illuminate\Container\Container|null $container
    11. * @return void
    12. */
    13. public function __construct(Container $container = null)
    14. {
    15. $this->setupContainer($container ?: new Container);
    16. // Once we have the container setup, we will setup the default configuration
    17. // options in the container "config" binding. This will make the database
    18. // manager work correctly out of the box without extreme configuration.
    19. $this->setupDefaultConfiguration();
    20. $this->setupManager();
    21. }
    22. /**
    23. * Register a connection with the manager.
    24. *
    25. * @param array $config
    26. * @param string $name
    27. * @return void
    28. */
    29. public function addConnection(array $config, $name = 'default')
    30. {
    31. $connections = $this->container['config']['database.connections'];
    32. $connections[$name] = $config;
    33. $this->container['config']['database.connections'] = $connections;
    34. }
    35. /**
    36. * Get the current event dispatcher instance.
    37. *
    38. * @return \Illuminate\Contracts\Events\Dispatcher|null
    39. */
    40. public function getEventDispatcher()
    41. {
    42. if ($this->container->bound('events')) {
    43. return $this->container['events'];
    44. }
    45. }
    46. /**
    47. * Setup the default database configuration options.
    48. *
    49. * @return void
    50. */
    51. protected function setupDefaultConfiguration()
    52. {
    53. $this->container['config']['database.fetch'] = PDO::FETCH_OBJ;
    54. $this->container['config']['database.default'] = 'default';
    55. }
    56. /**
    57. * Set the event dispatcher instance to be used by connections.
    58. *
    59. * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher
    60. * @return void
    61. */
    62. public function setEventDispatcher(Dispatcher $dispatcher)
    63. {
    64. $this->container->instance('events', $dispatcher);
    65. }
    66. /**
    67. * Bootstrap Eloquent so it is ready for usage.
    68. *
    69. * @return void
    70. */
    71. public function bootEloquent()
    72. {
    73. Eloquent::setConnectionResolver($this->manager);
    74. // If we have an event dispatcher instance, we will go ahead and register it
    75. // with the Eloquent ORM, allowing for model callbacks while creating and
    76. // updating "model" instances; however, it is not necessary to operate.
    77. if ($dispatcher = $this->getEventDispatcher()) {
    78. Eloquent::setEventDispatcher($dispatcher);
    79. }
    80. }
    81. }
    82. //Illuminate\Support\Traits\CapsuleManagerTrait
    83. trait CapsuleManagerTrait
    84. {
    85. /**
    86. * Make this capsule instance available globally.
    87. *
    88. * @return void
    89. */
    90. public function setAsGlobal()
    91. {
    92. static::$instance = $this;
    93. }
    94. /**
    95. * Setup the IoC container instance.
    96. *
    97. * @param \Illuminate\Contracts\Container\Container $container
    98. * @return void
    99. */
    100. protected function setupContainer(Container $container)
    101. {
    102. $this->container = $container;
    103. if (! $this->container->bound('config')) {
    104. $this->container->instance('config', new Fluent);
    105. }
    106. }
    107. }
    108. //\Illuminate\Contracts\Container\Container
    109. use Illuminate\Contracts\Container\Container as ContainerContract;
    110. class Container implements ArrayAccess, ContainerContract
    111. {
    112. /**
    113. * Determine if the given abstract type has been bound.
    114. *
    115. * @param string $abstract
    116. * @return bool
    117. */
    118. public function bound($abstract)
    119. {
    120. return isset($this->bindings[$abstract]) ||
    121. isset($this->instances[$abstract]) ||
    122. $this->isAlias($abstract);
    123. }
    124. /**
    125. * Register a binding with the container.
    126. *
    127. * @param string $abstract
    128. * @param \Closure|string|null $concrete
    129. * @param bool $shared
    130. * @return void
    131. *
    132. * @throws \TypeError
    133. */
    134. public function bind($abstract, $concrete = null, $shared = false)
    135. {
    136. $this->dropStaleInstances($abstract);
    137. // If no concrete type was given, we will simply set the concrete type to the
    138. // abstract type. After that, the concrete type to be registered as shared
    139. // without being forced to state their classes in both of the parameters.
    140. if (is_null($concrete)) {
    141. $concrete = $abstract;
    142. }
    143. // If the factory is not a Closure, it means it is just a class name which is
    144. // bound into this container to the abstract type and we will just wrap it
    145. // up inside its own Closure to give us more convenience when extending.
    146. if (! $concrete instanceof Closure) {
    147. if (! is_string($concrete)) {
    148. throw new TypeError(self::class.'::bind(): Argument #2 ($concrete) must be of type Closure|string|null');
    149. }
    150. $concrete = $this->getClosure($abstract, $concrete);
    151. }
    152. $this->bindings[$abstract] = compact('concrete', 'shared');
    153. // If the abstract type was already resolved in this container we'll fire the
    154. // rebound listener so that any objects which have already gotten resolved
    155. // can have their copy of the object updated via the listener callbacks.
    156. if ($this->resolved($abstract)) {
    157. $this->rebound($abstract);
    158. }
    159. }
    160. /**
    161. * Register an existing instance as shared in the container.
    162. *
    163. * @param string $abstract
    164. * @param mixed $instance
    165. * @return mixed
    166. */
    167. public function instance($abstract, $instance)
    168. {
    169. $this->removeAbstractAlias($abstract);
    170. $isBound = $this->bound($abstract);
    171. unset($this->aliases[$abstract]);
    172. // We'll check to determine if this type has been bound before, and if it has
    173. // we will fire the rebound callbacks registered with the container and it
    174. // can be updated with consuming classes that have gotten resolved here.
    175. $this->instances[$abstract] = $instance;
    176. if ($isBound) {
    177. $this->rebound($abstract);
    178. }
    179. return $instance;
    180. }
    181. /**
    182. * Remove an alias from the contextual binding alias cache.
    183. *
    184. * @param string $searched
    185. * @return void
    186. */
    187. protected function removeAbstractAlias($searched)
    188. {
    189. if (! isset($this->aliases[$searched])) {
    190. return;
    191. }
    192. foreach ($this->abstractAliases as $abstract => $aliases) {
    193. foreach ($aliases as $index => $alias) {
    194. if ($alias == $searched) {
    195. unset($this->abstractAliases[$abstract][$index]);
    196. }
    197. }
    198. }
    199. }
    200. }

    5.2 构造器

    1. //Illuminate\Database\Capsule\Manager
    2. use Illuminate\Database\DatabaseManager;
    3. class Manager
    4. {
    5. protected $manager;
    6. /**
    7. * Create a new database capsule manager.
    8. *
    9. * @param \Illuminate\Container\Container|null $container
    10. * @return void
    11. */
    12. public function __construct(Container $container = null)
    13. {
    14. $this->setupContainer($container ?: new Container);
    15. // Once we have the container setup, we will setup the default configuration
    16. // options in the container "config" binding. This will make the database
    17. // manager work correctly out of the box without extreme configuration.
    18. $this->setupDefaultConfiguration();
    19. $this->setupManager();
    20. }
    21. /**
    22. * Build the database manager instance.
    23. *
    24. * @return void
    25. */
    26. protected function setupManager()
    27. {
    28. $factory = new ConnectionFactory($this->container);
    29. $this->manager = new DatabaseManager($this->container, $factory);
    30. }
    31. /**
    32. * Dynamically pass methods to the default connection.
    33. *
    34. * @param string $method
    35. * @param array $parameters
    36. * @return mixed
    37. */
    38. public static function __callStatic($method, $parameters)
    39. {
    40. return static::connection()->$method(...$parameters);
    41. }
    42. /**
    43. * Get a connection instance from the global manager.
    44. *
    45. * @param string|null $connection
    46. * @return \Illuminate\Database\Connection
    47. */
    48. public static function connection($connection = null)
    49. {
    50. return static::$instance->getConnection($connection);
    51. }
    52. /**
    53. * Get a registered connection instance.
    54. *
    55. * @param string|null $name
    56. * @return \Illuminate\Database\Connection
    57. */
    58. public function getConnection($name = null)
    59. {
    60. return $this->manager->connection($name);
    61. }
    62. /**
    63. * Get a fluent query builder instance.
    64. *
    65. * @param \Closure|\Illuminate\Database\Query\Builder|string $table
    66. * @param string|null $as
    67. * @param string|null $connection
    68. * @return \Illuminate\Database\Query\Builder
    69. */
    70. public static function table($table, $as = null, $connection = null)
    71. {
    72. return static::$instance->connection($connection)->table($table, $as);
    73. }
    74. }
    75. //Illuminate\Database\DatabaseManager
    76. use Illuminate\Database\Connectors\ConnectionFactory;
    77. /**
    78. * @mixin \Illuminate\Database\Connection
    79. */
    80. class DatabaseManager implements ConnectionResolverInterface
    81. {
    82. public function __construct($app, ConnectionFactory $factory)
    83. {
    84. $this->app = $app;
    85. $this->factory = $factory;
    86. $this->reconnector = function ($connection) {
    87. $this->reconnect($connection->getNameWithReadWriteType());
    88. };
    89. }
    90. /**
    91. * Get a database connection instance.
    92. *
    93. * @param string|null $name
    94. * @return \Illuminate\Database\Connection
    95. */
    96. public function connection($name = null)
    97. {
    98. [$database, $type] = $this->parseConnectionName($name);
    99. $name = $name ?: $database;
    100. // If we haven't created this connection, we'll create it based on the config
    101. // provided in the application. Once we've created the connections we will
    102. // set the "fetch mode" for PDO which determines the query return types.
    103. if (! isset($this->connections[$name])) {
    104. $this->connections[$name] = $this->configure(
    105. $this->makeConnection($database), $type
    106. );
    107. }
    108. return $this->connections[$name];
    109. }
    110. /**
    111. * Make the database connection instance.
    112. *
    113. * @param string $name
    114. * @return \Illuminate\Database\Connection
    115. */
    116. protected function makeConnection($name)
    117. {
    118. $config = $this->configuration($name);
    119. // First we will check by the connection name to see if an extension has been
    120. // registered specifically for that connection. If it has we will call the
    121. // Closure and pass it the config allowing it to resolve the connection.
    122. if (isset($this->extensions[$name])) {
    123. return call_user_func($this->extensions[$name], $config, $name);
    124. }
    125. // Next we will check to see if an extension has been registered for a driver
    126. // and will call the Closure if so, which allows us to have a more generic
    127. // resolver for the drivers themselves which applies to all connections.
    128. if (isset($this->extensions[$driver = $config['driver']])) {
    129. return call_user_func($this->extensions[$driver], $config, $name);
    130. }
    131. return $this->factory->make($config, $name);
    132. }
    133. }
    134. //Illuminate\Database\Connectors\ConnectionFactory
    135. class ConnectionFactory
    136. {
    137. /**
    138. * Establish a PDO connection based on the configuration.
    139. *
    140. * @param array $config
    141. * @param string|null $name
    142. * @return \Illuminate\Database\Connection
    143. */
    144. public function make(array $config, $name = null)
    145. {
    146. $config = $this->parseConfig($config, $name);
    147. if (isset($config['read'])) {
    148. return $this->createReadWriteConnection($config);
    149. }
    150. return $this->createSingleConnection($config());
    151. }
    152. /**
    153. * Parse and prepare the database configuration.
    154. *
    155. * @param array $config
    156. * @param string $name
    157. * @return array
    158. */
    159. protected function parseConfig(array $config, $name)
    160. {
    161. return Arr::add(Arr::add($config, 'prefix', ''), 'name', $name);
    162. }
    163. /**
    164. * Create a read / write database connection instance.
    165. *
    166. * @param array $config
    167. * @return \Illuminate\Database\Connection
    168. */
    169. protected function createReadWriteConnection(array $config)
    170. {
    171. $connection = $this->createSingleConnection($this->getWriteConfig($config));
    172. return $connection->setReadPdo($this->createReadPdo($config));
    173. }
    174. /**
    175. * Create a read / write database connection instance.
    176. *
    177. * @param array $config
    178. * @return \Illuminate\Database\Connection
    179. */
    180. protected function createReadWriteConnection(array $config)
    181. {
    182. $connection = $this->createSingleConnection($this->getWriteConfig($config));
    183. return $connection->setReadPdo($this->createReadPdo($config));
    184. }
    185. /**
    186. * Create a single database connection instance.
    187. *
    188. * @param array $config
    189. * @return \Illuminate\Database\Connection
    190. */
    191. protected function createSingleConnection(array $config)
    192. {
    193. $pdo = $this->createPdoResolver($config);
    194. return $this->createConnection(
    195. $config['driver'], $pdo, $config['database'], $config['prefix'], $config
    196. );
    197. }
    198. /**
    199. * Get the write configuration for a read / write connection.
    200. *
    201. * @param array $config
    202. * @return array
    203. */
    204. protected function getWriteConfig(array $config)
    205. {
    206. return $this->mergeReadWriteConfig(
    207. $config, $this->getReadWriteConfig($config, 'write')
    208. );
    209. }
    210. /**
    211. * Merge a configuration for a read / write connection.
    212. *
    213. * @param array $config
    214. * @param array $merge
    215. * @return array
    216. */
    217. protected function mergeReadWriteConfig(array $config, array $merge)
    218. {
    219. return Arr::except(array_merge($config, $merge), ['read', 'write']);
    220. }
    221. /**
    222. * Get a read / write level configuration.
    223. *
    224. * @param array $config
    225. * @param string $type
    226. * @return array
    227. */
    228. protected function getReadWriteConfig(array $config, $type)
    229. {
    230. return isset($config[$type][0])
    231. ? Arr::random($config[$type])
    232. : $config[$type];
    233. }
    234. /**
    235. * Create a single database connection instance.
    236. *
    237. * @param array $config
    238. * @return \Illuminate\Database\Connection
    239. */
    240. protected function createSingleConnection(array $config)
    241. {
    242. $pdo = $this->createPdoResolver($config);
    243. return $this->createConnection(
    244. $config['driver'], $pdo, $config['database'], $config['prefix'], $config
    245. );
    246. }
    247. /**
    248. * Create a connector instance based on the configuration.
    249. *
    250. * @param array $config
    251. * @return \Illuminate\Database\Connectors\ConnectorInterface
    252. *
    253. * @throws \InvalidArgumentException
    254. */
    255. public function createConnector(array $config)
    256. {
    257. if (!isset($config['driver'])) {
    258. throw new InvalidArgumentException('A driver must be specified.');
    259. }
    260. if ($this->container->bound($key = "db.connector.{$config['driver']}")) {
    261. return $this->container->make($key);
    262. }
    263. switch ($config['driver']) {
    264. case 'mysql':
    265. return new MySqlConnector;
    266. case 'pgsql':
    267. return new PostgresConnector;
    268. case 'sqlite':
    269. return new SQLiteConnector;
    270. case 'sqlsrv':
    271. return new SqlServerConnector;
    272. }
    273. throw new InvalidArgumentException("Unsupported driver [{$config['driver']}].");
    274. }
    275. /**
    276. * Create a new connection instance.
    277. *
    278. * @param string $driver
    279. * @param \PDO|\Closure $connection
    280. * @param string $database
    281. * @param string $prefix
    282. * @param array $config
    283. * @return \Illuminate\Database\Connection
    284. *
    285. * @throws \InvalidArgumentException
    286. */
    287. protected function createConnection($driver, $connection, $database, $prefix = '', array $config = [])
    288. {
    289. if ($resolver = Connection::getResolver($driver)) {
    290. return $resolver($connection, $database, $prefix, $config);
    291. }
    292. switch ($driver) {
    293. case 'mysql':
    294. return new MySqlConnection($connection, $database, $prefix, $config);
    295. case 'pgsql':
    296. return new PostgresConnection($connection, $database, $prefix, $config);
    297. case 'sqlite':
    298. return new SQLiteConnection($connection, $database, $prefix, $config);
    299. case 'sqlsrv':
    300. return new SqlServerConnection($connection, $database, $prefix, $config);
    301. }
    302. throw new InvalidArgumentException("Unsupported driver [{$driver}].");
    303. }
    304. }
    305. //Illuminate\Database\MySqlConnection
    306. class MySqlConnection extends Connection
    307. {
    308. }
    309. //Illuminate\Database\Connection
    310. use Illuminate\Database\Query\Builder as QueryBuilder;
    311. class Connection implements ConnectionInterface
    312. {
    313. /**
    314. * Begin a fluent query against a database table.
    315. *
    316. * @param \Closure|\Illuminate\Database\Query\Builder|string $table
    317. * @param string|null $as
    318. * @return \Illuminate\Database\Query\Builder
    319. */
    320. public function table($table, $as = null)
    321. {
    322. return $this->query()->from($table, $as);
    323. }
    324. /**
    325. * Get a new query builder instance.
    326. *
    327. * @return \Illuminate\Database\Query\Builder
    328. */
    329. public function query()
    330. {
    331. return new QueryBuilder(
    332. $this, $this->getQueryGrammar(), $this->getPostProcessor()
    333. );
    334. }
    335. }
    336. //Illuminate\Database\Query\Builder
    337. class Builder
    338. {
    339. /**
    340. * Set the table which the query is targeting.
    341. *
    342. * @param \Closure|\Illuminate\Database\Query\Builder|string $table
    343. * @param string|null $as
    344. * @return $this
    345. */
    346. public function from($table, $as = null)
    347. {
    348. if ($this->isQueryable($table)) {
    349. return $this->fromSub($table, $as);
    350. }
    351. $this->from = $as ? "{$table} as {$as}" : $table;
    352. return $this;
    353. }
    354. /**
    355. * Determine if the value is a query builder instance or a Closure.
    356. *
    357. * @param mixed $value
    358. * @return bool
    359. */
    360. protected function isQueryable($value)
    361. {
    362. return $value instanceof self ||
    363. $value instanceof EloquentBuilder ||
    364. $value instanceof Relation ||
    365. $value instanceof Closure;
    366. }
    367. /**
    368. * Makes "from" fetch from a subquery.
    369. *
    370. * @param \Closure|\Illuminate\Database\Query\Builder|string $query
    371. * @param string $as
    372. * @return $this
    373. *
    374. * @throws \InvalidArgumentException
    375. */
    376. public function fromSub($query, $as)
    377. {
    378. [$query, $bindings] = $this->createSub($query);
    379. return $this->fromRaw('('.$query.') as '.$this->grammar->wrapTable($as), $bindings);
    380. }
    381. ……
    382. //之后都是构建构造器的 没调试 看的也不是太懂
    383. }

    注:

    本地使用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)

  • 相关阅读:
    Web3 游戏周报(3.24-3.30)
    java串口通讯开发rxtxSerial.dll的闪退问题解决
    Serverless之Knative部署应用实例;
    “中国国安部紧急警告”!境外公司利用加密货币诱使人员非法采集空间数据!当心不慎成“帮凶”!
    【人工智能基础】人工神经网络
    Vue 访问外链失败问题
    6.DesignForPlacement\ExportHighlightedList
    百度百科小程序源码 基于uniapp开发的zblog多端小程序开源源码
    在线表单设计器都有哪些优秀的功能?
    如何定义版本号?
  • 原文地址:https://blog.csdn.net/lsswear/article/details/133989234