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:: 不再被解析为定义当前方法所在的类,
而是在实际运行时所计算的,以这样输出的结果业务逻辑就正确了。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号