php 重载与事件委托 [toc] //md 内容表 一. php 重载 1. php 重写 1.当一个父类和子类有一个方法,参数和名字完全一致,那么子类方法会覆盖父类的方法 2.在实行方法覆盖的时候,访问修饰符
php 重载与事件委托
[toc] //md 内容表
一. php 重载
1. php 重写
1.当一个父类和子类有一个方法,参数和名字完全一致,那么子类方法会覆盖父类的方法 2.在实行方法覆盖的时候,访问修饰符可以是不一样的,但是子类的访问范围必须大于等于父类的访问范围
parent::demo(); //demo 是属性名,只要子类里有 parent::返回的必定是父类
2. php 重载
- 1.属性拦截器 是指动态地创建类属性和方法。我们是通过魔术方法(magic methods)来实现的。
- 2.当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用。
重载方法其实就是魔术方法
所有的重载方法都必须被声明为 public
重写只存在于子类与父类中,重载存在于一个类中。
为不存在的属性赋值时会自动调用__set($name,$value)
方法,()号内必须有属性和参数
访问不存在的属性时会自动调用__get($name)
方法()号内必须有属性名
__set($name,$value),__get($name)
)" class="reference-link">2.1 属性拦截器(__set($name,$value)
,__get($name)
)
-
class Pero
-
{
-
private $idNum;
-
private $sjNum;
-
public function __construct($idNum,$sjNum)
-
{
-
$this->idNum = $idNum;
-
$this->sjNum = $sjNum;
-
}
-
public function __set($name,$value)
-
{
-
// echo "设置不存在的属性$name 的值为 $value".'<br>';
-
$this->$name = $value;
-
return $this->$name;
-
}
-
public function __get($name)
-
{
-
// echo '当前访问的不存在的类属性'.$name.'<br>';
-
return $this->$name;
-
}
-
}
-
$c = new Credit('412702200010104567','13213145221');
-
$c->name = '大帅哥';//__set
-
echo $c->name;//__get
-
echo $c->sjNum;
-
echo $c->idNum;
- 但是这样会有一个问题:因为魔术方法都是公开的,所以一些私有成员的不可见性就不会生效,别人可以随意篡改类,所以代码可以改为:
-
//以中转站的方式解决 将不可见类属性的请求转向一个私有接口
-
public function __set($name,$value)
-
{
-
// 对于访问未定义的属性
-
if(!property_exists($this,$name)) echo 'Fatal Error: the property '.__CLASS__.'::'.$name . ' does not exist<br>';
-
// 中转站 将访问不可见类属性的请求转向一个私有接口
-
// 根据属性名称 生成对应的属性访问私有接口名称
-
// set.ucfirst($name)
-
$method = 'set'.ucfirst($name);
-
// 判断方法存不存在
-
return method_exists($this,$method) ? $this->$method($name,$value):null;
-
}
-
private function setsjNum($name,$value)
-
{
-
// 私有接口中检查是否存在该属性
-
if(property_exists($this,$name))
-
return $this->$name = strlen($value) == 11 ? $value : null;
-
}
-
private function setIdNum($name,$value)
-
{
-
// 私有接口中检查是否存在该属性
-
if(property_exists($this,$name))
-
return $this->$name = strlen($value) == 18 ? $value : null;
-
}
-
private function getsjNum($name)
-
{
-
// 只返回前三位后四位
-
// 私有接口中检查是否存在该属性并且值不为空
-
$flag = property_exists($this,$name) && !empty($this->$name);
-
if($flag)
-
{
-
return mb_substr($this->$name,0,3).'****'.mb_substr($this->$name,-4,4);
-
}else{
-
return '手机号不合法<br>';
-
}
-
}
-
public function __get($name)
-
{
-
$method = 'get' . ucfirst($name);
-
return method_exists($this,$method) ? $this->$method($name) : null;
-
}
-
private function getIdNum($name)
-
{
-
// 只返回前六位后四位
-
// 私有接口中检查是否存在该属性并且值不为空
-
$flag = property_exists($this,$name) && !empty($this->$name);
-
if($flag)
-
{
-
return mb_substr($this->$name,0,6).'********'.mb_substr($this->$name,-4,4);
-
}else{
-
return '身份证信息不合法<br>';
-
}
-
}
- 然后重新写:
-
$c = new Credit('412702202010104567','13213145221');
-
$c->idNum = '412702202010104567';//__set
-
echo $c->idNum;//__get 这时会返回412702********4567
-
$c->sjNum = 13213145221;
-
echo $c->sjNum; //这时会返回132****5221
__call($name,$value),静态方法__callStaic($name)
)" class="reference-link">2.2 方法拦截器(普通方法__call($name,$value)
,静态方法__callStaic($name)
)
- 方法拦截器也叫方法重载或者事件委托
-
class User
-
{
-
public function normal()
-
{
-
return __METHOD__;
-
}
-
// 访问当前环境下不存在或不可见的静态方法时 调用魔术方法__callStatic
-
public static function __callStatic(string $method,array $args)
-
{
-
printf('调用的不存在静态方法是%s(),参数列表有[%s]<br>',$method,implode(',',$args));
-
// echo 'The static method you are calling does not exsit or it can not be accessed';
-
}
-
public function __call(string $method,array $args){
-
printf('调用的不存在方法是%s(),参数列表有[%s]<br>',$method,implode(',',$args));
-
// echo 'The method you are calling '. __CLASS__.'::'.$method.' does not exsit or it can not be accessed';
-
}
-
}
-
// User::demo(1,2,3);
-
(new User)->index('刘亦菲','172cm','天仙');
2.3 事件委托
- 请求委托 访问类中不存在的成员方法时, 会被魔术方法拦截, 把请求重定向到别的类的成员方法来处理
- 委托是指一个对象转发或者委托一个请求给另一个对象,被委托的一方替原先对象处理请求。
- 委托比继承更加灵活 父类与子类的关系是固定的,只能单继承,但是请求可以委托给多个对象
普通方法
-
// 被委托的类
-
class Base{
-
public function write(...$args)
-
{
-
printf('调用的不存在的方法是%s(),参数列表有[%s]<br>',__METHOD__,implode(',',$args));
-
}
-
}
-
//依赖注入
-
class Work
-
{
-
//base属性 储存的是一个对象
-
protected $Base;
-
public function __construct(Base $Base)
-
{
-
$this->Base = $Base;
-
}
-
public function __call($method,$args)
-
{
-
//委托给Base类去处理
-
$this->Base->$method(...$arg);
-
}
-
}
-
$base = new Base;
-
$work = new Work($base);
-
$work->write(1,2,34);
- 这个是传统的方法,可以用回调的方式,把 22 行改为:
call_user_func([$this->Base,$method],...$args);
静态方法 在此基础上可以给被委托的类加个静态方法
-
public static function fetch(...$args)
-
{
-
printf('调用的不存在的静态方法是%s(),参数列表有[%s]<br>',__METHOD__,implode(',',$args));
-
}
然后工作类里加上
-
public static function __callStatic($method,$args)
-
{
-
call_user_func(['Base',$method],...$args);
-
}
再然后:
Work::fetch(1,2,3);
二. 实例之数据库查询构造器
-
// 被委托的类
-
class Query{
-
// 创建类的唯一实例 pdo对象
-
private static $db;
-
protected $table;
-
protected $field;
-
protected $limit;
-
// private私有的 阻止此类在外部进行实例化
-
private function __construct()
-
{
-
}
-
static function connect($dsn,$username,$pwd)
-
{
-
//创建PDO类的唯一实例 pdo对象
-
if(is_null(static::$db))
-
{
-
static::$db = new PDO($dsn,$username,$pwd);
-
}
-
// 返回query实例
-
return new static();
-
}
-
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 getSql()
-
{
-
return sprintf('SELECT %s FROM %s LIMIT %d ',$this->field,$this->table,$this->limit);
-
}
-
public function select()
-
{
-
return static::$db->query($this->getSql())->fetchAll(PDO::FETCH_ASSOC);
-
}
-
}
-
class Db
-
{
-
static function __callStatic($method,$args)
-
{
-
$dsn = 'mysql:host=39.105.79.62;dbname=news';
-
$username = 'miujue';
-
$pwd = 'zhoujielun521';
-
// 获取到被委托的类query实例
-
$query = Query::connect($dsn,$username,$pwd);
-
return call_user_func([$query,$method],...$args);
-
}
-
}
-
$res = Db::table('cate')->field('catname,catid')->limit(5)->select();
-
echo '<pre>';
-
print_r($res);
总结
-
die
— 断点打印 -
__set(属性名,参数)
— 为不存在的属性赋值时会自动调用 -
__get(属性名)
— 访问不存在的属性时会自动调用 -
property_exists(类名,属性名)
— 检查对象或类是否具有该属性 -
method_exists(类名,方法名)
— 检查类的方法是否存在 -
interface_exists(接口名)
— 检查接口是否已被定义 -
__call(方法名,参数名)
— 访问当前环境下不存在或不可见的普通方法时,它将被触发 -
__callStaic(方法名,参数名)
— 访问当前环境下不存在或不可见的静态方法/普通方法时,它将被触发