一、后期静态绑定
1.原理
后期静态绑定工作在: 静态继承上下文的环境中
new self
替换为new static
self
: 与定义类绑定static
: 与调用类绑定
不要再使用parent
演示:
<?php
// 动态绑定静态成员的调用上下文
class Ba
{
// 静态方法: 允许重写
public static function getpp()
{
return '当前调用方法: ' . __METHOD__;
}
public static function dupp()
{
// 后期静态绑定, 使用关键字: static, 将self 替换掉
// return new self();
// self: 与定义类绑定
// static: 与调用类绑定
return static::getpp();
}
}
class Con extends Ba
{
// 重写父类中的静态方法: index()
public static function getpp()
{
return '当前调用方法: ' . __METHOD__;
}
}
// 客户端
echo Ba::dupp();
echo '<hr>';
echo Con::dupp();
效果图:
二、属性重载/拦截器
演示:
<?php
// 拦截器: 属性拦截器, 方法拦截器
// 使用场景: 当用户访问一个不存在的或无权限访问属性/方法时, 自动调用(属性拦截器实质也是一个方法)
// 访问: 包括二个操作:就是读和写, 或者称为: 查询和设置
// 属性拦截器: __set(), __get(), __isset(), __unset()
class Staffs
{
private $name;
private $salary;
public function __construct($name, $salary)
{
$this->name = $name;
$this->salary = $salary;
}
// 1. 属性查询拦截器
// $property 参数,要获取的属性名称
public function __get($property)
{
// return $property === 'name' ? $this->name : '无权访问';
// 拦截转发器
// 1. 先事先约定一些方法专用于处理属性访问
$method = 'get' . ucfirst($property);
// 2. 转发访问请求
return method_exists($this, $method) ? $this->$method() : null;
}
private function getName()
{
return $this->name;
}
private function getSalary()
{
return $this->salary;
}
// 2. 属性设置拦截器
public function __set($property, $value)
{
$method = 'set' . ucfirst($property);
// 转发访问请求
return method_exists($this, $method) ? $this->$method($value) : null;
}
private function setName($value)
{
$this->name = trim($value);
}
private function setSalary($value)
{
if ($value === null) unset($this->salary);
else $this->salary = $value;
}
// 3. 属性检测拦截器
public function __isset($property)
{
return $property === 'name' ? isset($this->name) : false;
}
// 4. 属性销毁拦截器
public function __unset($property)
{
if ($property === 'salary') {
$method = 'set' . ucfirst($property);
// 转发访问请求
if (method_exists($this, $method)) return $this->$method(null) ;
}
}
}
// 客户端
$staffs = new Staffs('阮总', 98000);
// 访问了一个无访问权限的类属性
echo '姓名: ' .$staffs->name .'<br>';
echo '工资: ' .$staffs->salary;
echo '<hr>';
$staffs->name = '冯总';
$staffs->salary = 96000;
echo '姓名: ' .$staffs->name .'<br>';
echo '工资: ' .$staffs->salary;
echo '<hr>';
echo isset($staffs->name) ? '存在 <br>' : '不存在';
echo isset($staffs->salary) ? '存在 <br>' : '不存在';
echo '<hr>';
unset($staffs->name);
echo $staffs->name;
unset($staffs->salary);
echo $staffs->salary;
效果图:
三、方法重载/拦截器
演示:
<?php
// 方法拦截器, 其实比属性拦截器更有用
// __call(), __callStatic()
class User
{
// 方法拦截器
public function __call($name, $arr)
{
printf('方法名: %s , 参数: [%s]', $name, implode(', ', $arr));
}
// 静态方法拦截器
public static function __callStatic($name, $arr)
{
printf('静态方法名: %s , 参数: [%s]', $name, implode(', ', $arr));
}
}
$user = new User();
$user->khong(8, 9, 7, 8);
echo '<br>';
User::no(8,8,8,8);
效果图:
三、操作数据库构造器
<?php
// 方法拦截器实战:数据库查询构造器的实现
class Query
{
// 数据库连接
protected $db;
// 表名
protected $table;
// 字段列表
protected $field;
// 查询数量
protected $limit;
// 查询条件
protected $where;
// 构造方法完成数据库的连接
public function __construct($dsn, $username, $password)
{
$this->connect($dsn, $username, $password);
}
// PDO连接数据库的方法
private function connect($dsn, $username, $password)
{
$this->db = new PDO($dsn, $username, $password);
}
public function table($table)
{
$this->table = $table;
return $this;
}
public function field($field)
{
$this->field = $field;
return $this;
}
public function limit($limit)
{
$this->limit = $limit;
return $this;
}
public function id($id)
{
$this->id = $id;
return $this;
}
public function getSql()
{
return sprintf('SELECT %s FROM %s WHERE id > %u LIMIT %s', $this->field, $this->table, $this->id, $this->limit);
}
public function select()
{
return $this->db->query($this->getSql())->fetchAll(PDO::FETCH_ASSOC);
}
}
class DB
{
// 这里使用的静态方法拦截器
public static function __callStatic($name, $arguments)
{
$dsn = 'mysql:host=localhost;dbname=phpedu';
$query = new Query($dsn, 'root', 'root');
// return call_user_func(函数/方法, 函数参数列表)
// return call_user_func_array(函数/方法, 函数参数数组)
return call_user_func([$query, $name], ...$arguments);
}
}
$res=DB::table('staffs')->field('id, name, position')->id(3)->limit(5)->select();
print_r($res);
效果图:
总结:这个拦截器、拦截器是第一次接触,挺蒙的,刷了3-4遍视频才看明白——只是看明白,要撑握只能后面慢慢练习了。