## Model.php 部分源码分析 * public function db($baseQuery=true):获取查询对象,用在普通方法中; * public static function getDb():获取查询对象,用在静态方法中; * public function __call($method,$args):魔术调用不存在方法; * public static funciton __callStatic($method,$args):魔术静态调用不存在方法; >[info] 这些方法之间的相互配合,最终完成了模型到数据库查询的映射!所以,数据库查询操作是模型操作的基础: * 理达课堂数据库操作教程:http://www.kancloud.cn/ldkt/tp5_db :点击查看 * * * * * #### 1. Model类部分方法介绍 1. db()方法源码: * 功能:快速获取当前模型对应的数据库查询对象:Query。 * 备注:可以理解为【模型】与【数据库】之间的访问接口。 >[warning] 为了使学员更快的读懂源码,作者单独添加了大量注释 ~~~ /** * 获取当前模型的数据库查询对象 * 实现过程:通过Connect连接对象model方法获取Query对象,然后调用Query对象中 * 对应的方法如:setTable(设置默认表),name(设置无前缀表名),pk主键属性 * 注意:只需要设置【表名和主键】,就可实现与模型与对应表的绑定 * @access public * @param bool $baseQuery 是否调用全局查询范围 * @return Query */ public function db($baseQuery = true) { //先获取到当前模型对象的类名做为模型名 //如:你自定义的模型类为:Staff.php,那么 // $this->class 就等于 :Staff $model = $this->class; if (!isset(self::$links[$model])) { // 设置当前模型 确保查询返回模型对象 // Connection.php类中model方法:创建指定模型的查询对象 // Connection.php里model($model, $queryClass = '') // $model 模型类名称 $queryClass 查询对象类名 返回:Query $query = Db::connect($this->connection) //返回Connect类的对象例:创建连接 ->model($model, $this->query); // 设置当前数据表和模型名 if (!empty($this->table)) { $query->setTable($this->table); //设置表全名 } else { $query->name($this->name); //设置表简名(无后缀) } if (!empty($this->pk)) { //设置主键 $query->pk($this->pk); } //给数据库连接池中$model键赋值为当前对象 self::$links[$model] = $query; } // 全局作用域 if ($baseQuery && method_exists($this, 'base')) { call_user_func_array([$this, 'base'], [ & self::$links[$model]]); } // 返回当前模型的数据库查询对象 // 注意返回值写法:当前类的静态属性,返回值为所有模型对象共享 //以后就可以直接用: 模型::数据库连贯方法,例如:Staff::where()->find(); return self::$links[$model]; } ~~~ >[warning] 虽然通过db( )方法获取了到了数据库查询对象,但是所调用的数据操作连贯方法返回的仍然是模型对象?这是为什么呢?因为连贯方法中最后都是返回当前调用对象:return $this; 而此时,调用这些方法的是模型对象,因此返回的也是模型对象,所以在后面仍然可以接着调用模型方法! * * * * * 2. getDb( )方法源码 * 与db( )方法一样,也是返回一个数据库查询对象:Query >[info] 由于 getDb( )是静态方法,可以用在模型静态调用中。而前面介绍的db( )方法是普通方法,不能用在模型静态调用中。 ~~~ //与db()方法类似,同样返回一个数据库查询对象 protected static function getDb() { //获取调用该方法的模型类名:如User $model = get_called_class(); //如果在数据库对象池中存在这个模型类 if (!isset(self::$links[$model])) { //new static():获取当前模型对象,再调用db()方法创建查询对象 //本类静态属性$links[$model]中存入当前模型的查询对象 self::$links[$model] = (new static())->db(); } //返回与当前模型关联的数据库查询对象 // self::$links[$model] 数组元素值是一个查询对象:(new Query) return self::$links[$model]; } ~~~ * * * * * 3. __call( )方法 >[info] __call( )是PHP的魔术方法,当对象调用一个不存在的方法时,自动触发这个方法。该方法可以实现跨类动态调用,很实用。 ~~~ //__call:当调用不存在的方法时,自动调用 public function __call($method, $args) { $query = $this->db(); if (method_exists($this, 'scope' . $method)) { // 动态调用命名范围 $method = 'scope' . $method; array_unshift($args, $query); call_user_func_array([$this, $method], $args); return $this; } else { return call_user_func_array([$query, $method], $args); } } ~~~ * * * * * 4. __callStatic( ) >[info] 与__call( )一样,也是PHP魔术方法。当调用的静态方法不存在或权限不足时,自动调用。这个方法与call_user_func_array( )结合,简直太奇妙了! ~~~ public static function __callStatic($method, $params) { //getDb()方法可获取查询对象,这里为什么不用db()方法呢?因为这是静态魔术方法 //静态方法内部,只能调用静态方法,所以要用:getDb()方法 $query = self::getDb(); //call_user_func_array([类,方法],参数数组):实现动态方法调用 return call_user_func_array([$query, $method], $params); } ~~~ >[warning] 本章第3节有详细介绍,这里就不再多说了! * * * * * ### 总结: >[success] 本节精选了4个Model类的方法,很有代表性: > 1. 二个普通方法:db( ),__call( ),二个静态方法;getDb( )和__callStatic( ); > 2. 普通魔术方法__call( )中调用普通方法db( ),来获取查询对象; > 3. 静态魔术方法__callStatic( )中调用静态方法getDb( )来获取查询对象。