0904作业
作业1:编程: 使用方法重载与call_user_func_array()模拟TP框架的链式查询
<?php /** * 数据库查询类 */ class Query { // 保存sql语句中的各个组成部分 // SELECT 字段列表 FROM 表名 WHERE 条件 private $sql = []; // 数据库的连接对象 private $pdo = null; //构造方法: 连接数据库 public function __construct() { // 连接数据库并返回pdo对象 $this->pdo = new PDO('mysql:host=127.0.0.1;dbname=php','root','root'); } // table()获取sql语句的表名 public function table($table) { $this->sql['table'] = $table; return $this; //返回当前类实例对象,便于链式调用该对象的其它方法 } // fields()获取sql语句的字段列表 public function fields($fields) { $this->sql['fields'] = $fields; return $this; } // where()获取sql语句的查询条件 public function where($where) { $this->sql['where'] = $where; return $this; } //执行查询,是一个终级方法 public function select() { //拼装SELECT查询语句 $sql = "SELECT {$this->sql['fields']} FROM {$this->sql['table']} WHERE {$this->sql['where']}"; $stmt = $this->pdo->prepare($sql); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_ASSOC); } }
点击 "运行实例" 按钮查看在线实例
<?php /** * 方法重载的实战案例: 模拟ThinkPHP5.1中的数据库链式操作 * 用方法重载实现方法跨类调用 */ echo '<h3 style="text-align: center">编程1:方法重载的实战案例: 模拟ThinkPHP5.1中的数据库链式操作</h3 style>'. // Db::table()->fields()->where()->select(); require 'Query.php'; // 数据库操作的入口类 class Db { public static function __callStatic($name, $arguments) { //call_user_func_array([类名, 方法],[])//执行类中的静态方法static //call_user_func_array([对象, 方法],[])//执行对象方法 return call_user_func_array([(new Query()),$name],$arguments); } } $result = Db::table('staff') ->fields('id,name,age,salary') ->where('age> 40 ') ->select(); //print_r($result); // 用表格将查询结果格式化输出 $table = '<table border="1" cellpadding="5" cellspacing="0" width="60%" align="center">'; $table .= '<caption style="font-size: 1.5rem;margin:15px;">员工信息表</caption>'; $table .= '<tr bgcolor="#90ee90"><th>ID</th><th>姓名</th><th>年龄</th><th>工资</th></tr>'; foreach ($result as $staff) { $table .= '<tr align="center">'; $table .= '<td>'.$staff['id'].'</td>'; $table .= '<td>'.$staff['name'].'</td>'; $table .= '<td>'.$staff['age'].'</td>'; $table .= '<td>'.$staff['salary'].'</td>'; $table .= '</tr>'; } $table .= '</table>'; $num = '<p style="text-align: center"> 共计: <span style="color:red">'.count($result).'</span> 条记录</p>'; echo '<h4 style="text-align: center">查询staff表的id,name,age,salary字段条件是 age> 40</h4 style>'.$table, $num;
点击 "运行实例" 按钮查看在线实例
2. 问答: 后期静态绑定的原理与使用场景分析
(1).后期静态绑定的原理
答:
1.准确说,后期静态绑定工作原理是存储了在上一个“非转发调用”的类名。
当进行静态方法调用时,该类名即为明确指定的那个(通常在 :: 运算符左侧部分,本题为two);
2.当进行非静态方法调用时,即为该对象所属的类。
所谓的“转发调用”(forwarding call)指的是通过以下几种方式进行的静态调用:self::,parent::,static::
以及 forward_static_call()。可用 get_called_class() 函数来得到被调用的方法所在的类名,
3.static:: 则指出了其范围。该功能从语言内部角度考虑被命名为“后期静态绑定”。
后期绑定”的意思是说,static:: 不再被解析为定义当前方法所在的类,而是在实际运行时计算的。
也可以称之为“静态绑定”,因为它可以用于(但不限于)静态方法的调用。
4.通过官方说明我们知道后期静态绑定的范围是继承范围内,
也就是我们看到static::A();时想要确定static是谁就从调用这个方法的类的继承链去找。
(2).使用场景分析:
问:若父类one创建一个静态方法A和静态方法B,但你想要用子类two去调用静态方法B,
本意是想调用子类中已重写的静态方法A,并不想调用父类的方法A,但是在父类却不能正确识别出你的调用者是哪个?
答:
1.子类需要继承父类并将父类中静态方法A进行重写
2.然后需要将父类里面的静态方法B去调用父类的静态方法A,
父类里面一个方法调用另一个方法时,如果被调用方法是普通方法,则默认使用$this作为调用者;
如果被调用方法时静态方法,则默认使用类/self::作为调用者。
这里显然是一个静态方法,所以需要使用self::作为调用者去调用静态方法A
3.后期[运行阶段]进行静态绑定/延迟静态绑定,当我们输出子类two的静态方法B时,但是发现业务逻辑说不当通,
所以接下来我们需要将self::换成 static::,这里static:: 不再被解析为定义当前方法所在的类,
而是在实际运行时所计算的,以这样输出的结果业务逻辑就正确了。