php 重载与事件委托

[toc] //md 内容表

一. php 重载

1. php 重写

1.当一个父类和子类有一个方法,参数和名字完全一致,那么子类方法会覆盖父类的方法 2.在实行方法覆盖的时候,访问修饰符可以是不一样的,但是子类的访问范围必须大于等于父类的访问范围

parent::demo(); //demo 是属性名,只要子类里有 parent::返回的必定是父类

2. php 重载

  • 1.属性拦截器 是指动态地创建类属性和方法。我们是通过魔术方法(magic methods)来实现的。
  • 2.当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用。

重载方法其实就是魔术方法
所有的重载方法都必须被声明为 public
重写只存在于子类与父类中,重载存在于一个类中。
为不存在的属性赋值时会自动调用__set($name,$value)方法,()号内必须有属性和参数
访问不存在的属性时会自动调用__get($name)方法()号内必须有属性名

2.1 属性拦截器(__set($name,$value),__get($name))

  1. class Pero
  2. {
  3. private $idNum;
  4. private $sjNum;
  5. public function __construct($idNum,$sjNum)
  6. {
  7. $this->idNum = $idNum;
  8. $this->sjNum = $sjNum;
  9. }
  10. public function __set($name,$value)
  11. {
  12. // echo "设置不存在的属性$name 的值为 $value".'<br>';
  13. $this->$name = $value;
  14. return $this->$name;
  15. }
  16. public function __get($name)
  17. {
  18. // echo '当前访问的不存在的类属性'.$name.'<br>';
  19. return $this->$name;
  20. }
  21. }
  22. $c = new Credit('412702200010104567','13213145221');
  23. $c->name = '大帅哥';//__set
  24. echo $c->name;//__get
  25. echo $c->sjNum;
  26. echo $c->idNum;
  • 但是这样会有一个问题:因为魔术方法都是公开的,所以一些私有成员的不可见性就不会生效,别人可以随意篡改类,所以代码可以改为:
  1. //以中转站的方式解决 将不可见类属性的请求转向一个私有接口
  2. public function __set($name,$value)
  3. {
  4. // 对于访问未定义的属性
  5. if(!property_exists($this,$name)) echo 'Fatal Error: the property '.__CLASS__.'::'.$name . ' does not exist<br>';
  6. // 中转站 将访问不可见类属性的请求转向一个私有接口
  7. // 根据属性名称 生成对应的属性访问私有接口名称
  8. // set.ucfirst($name)
  9. $method = 'set'.ucfirst($name);
  10. // 判断方法存不存在
  11. return method_exists($this,$method) ? $this->$method($name,$value):null;
  12. }
  13. private function setsjNum($name,$value)
  14. {
  15. // 私有接口中检查是否存在该属性
  16. if(property_exists($this,$name))
  17. return $this->$name = strlen($value) == 11 ? $value : null;
  18. }
  19. private function setIdNum($name,$value)
  20. {
  21. // 私有接口中检查是否存在该属性
  22. if(property_exists($this,$name))
  23. return $this->$name = strlen($value) == 18 ? $value : null;
  24. }
  25. private function getsjNum($name)
  26. {
  27. // 只返回前三位后四位
  28. // 私有接口中检查是否存在该属性并且值不为空
  29. $flag = property_exists($this,$name) && !empty($this->$name);
  30. if($flag)
  31. {
  32. return mb_substr($this->$name,0,3).'****'.mb_substr($this->$name,-4,4);
  33. }else{
  34. return '手机号不合法<br>';
  35. }
  36. }
  37. public function __get($name)
  38. {
  39. $method = 'get' . ucfirst($name);
  40. return method_exists($this,$method) ? $this->$method($name) : null;
  41. }
  42. private function getIdNum($name)
  43. {
  44. // 只返回前六位后四位
  45. // 私有接口中检查是否存在该属性并且值不为空
  46. $flag = property_exists($this,$name) && !empty($this->$name);
  47. if($flag)
  48. {
  49. return mb_substr($this->$name,0,6).'********'.mb_substr($this->$name,-4,4);
  50. }else{
  51. return '身份证信息不合法<br>';
  52. }
  53. }
  • 然后重新写:
  1. $c = new Credit('412702202010104567','13213145221');
  2. $c->idNum = '412702202010104567';//__set
  3. echo $c->idNum;//__get 这时会返回412702********4567
  4. $c->sjNum = 13213145221;
  5. echo $c->sjNum; //这时会返回132****5221

2.2 方法拦截器(普通方法__call($name,$value),静态方法__callStaic($name))

  • 方法拦截器也叫方法重载或者事件委托
  1. class User
  2. {
  3. public function normal()
  4. {
  5. return __METHOD__;
  6. }
  7. // 访问当前环境下不存在或不可见的静态方法时 调用魔术方法__callStatic
  8. public static function __callStatic(string $method,array $args)
  9. {
  10. printf('调用的不存在静态方法是%s(),参数列表有[%s]<br>',$method,implode(',',$args));
  11. // echo 'The static method you are calling does not exsit or it can not be accessed';
  12. }
  13. public function __call(string $method,array $args){
  14. printf('调用的不存在方法是%s(),参数列表有[%s]<br>',$method,implode(',',$args));
  15. // echo 'The method you are calling '. __CLASS__.'::'.$method.' does not exsit or it can not be accessed';
  16. }
  17. }
  18. // User::demo(1,2,3);
  19. (new User)->index('刘亦菲','172cm','天仙');

2.3 事件委托

  • 请求委托 访问类中不存在的成员方法时, 会被魔术方法拦截, 把请求重定向到别的类的成员方法来处理
  • 委托是指一个对象转发或者委托一个请求给另一个对象,被委托的一方替原先对象处理请求。
  • 委托比继承更加灵活 父类与子类的关系是固定的,只能单继承,但是请求可以委托给多个对象

普通方法

  1. // 被委托的类
  2. class Base{
  3. public function write(...$args)
  4. {
  5. printf('调用的不存在的方法是%s(),参数列表有[%s]<br>',__METHOD__,implode(',',$args));
  6. }
  7. }
  8. //依赖注入
  9. class Work
  10. {
  11. //base属性 储存的是一个对象
  12. protected $Base;
  13. public function __construct(Base $Base)
  14. {
  15. $this->Base = $Base;
  16. }
  17. public function __call($method,$args)
  18. {
  19. //委托给Base类去处理
  20. $this->Base->$method(...$arg);
  21. }
  22. }
  23. $base = new Base;
  24. $work = new Work($base);
  25. $work->write(1,2,34);
  • 这个是传统的方法,可以用回调的方式,把 22 行改为:

call_user_func([$this->Base,$method],...$args);

静态方法 在此基础上可以给被委托的类加个静态方法

  1. public static function fetch(...$args)
  2. {
  3. printf('调用的不存在的静态方法是%s(),参数列表有[%s]<br>',__METHOD__,implode(',',$args));
  4. }

然后工作类里加上

  1. public static function __callStatic($method,$args)
  2. {
  3. call_user_func(['Base',$method],...$args);
  4. }

再然后:

Work::fetch(1,2,3);


二. 实例之数据库查询构造器

  1. // 被委托的类
  2. class Query{
  3. // 创建类的唯一实例 pdo对象
  4. private static $db;
  5. protected $table;
  6. protected $field;
  7. protected $limit;
  8. // private私有的 阻止此类在外部进行实例化
  9. private function __construct()
  10. {
  11. }
  12. static function connect($dsn,$username,$pwd)
  13. {
  14. //创建PDO类的唯一实例 pdo对象
  15. if(is_null(static::$db))
  16. {
  17. static::$db = new PDO($dsn,$username,$pwd);
  18. }
  19. // 返回query实例
  20. return new static();
  21. }
  22. public function table($table)
  23. {
  24. $this->table = $table;
  25. return $this;
  26. }
  27. public function field($field)
  28. {
  29. $this->field = $field;
  30. return $this;
  31. }
  32. public function limit($limit)
  33. {
  34. $this->limit = $limit;
  35. return $this;
  36. }
  37. public function getSql()
  38. {
  39. return sprintf('SELECT %s FROM %s LIMIT %d ',$this->field,$this->table,$this->limit);
  40. }
  41. public function select()
  42. {
  43. return static::$db->query($this->getSql())->fetchAll(PDO::FETCH_ASSOC);
  44. }
  45. }
  46. class Db
  47. {
  48. static function __callStatic($method,$args)
  49. {
  50. $dsn = 'mysql:host=39.105.79.62;dbname=news';
  51. $username = 'miujue';
  52. $pwd = 'zhoujielun521';
  53. // 获取到被委托的类query实例
  54. $query = Query::connect($dsn,$username,$pwd);
  55. return call_user_func([$query,$method],...$args);
  56. }
  57. }
  58. $res = Db::table('cate')->field('catname,catid')->limit(5)->select();
  59. echo '<pre>';
  60. print_r($res);

总结

  • die — 断点打印
  • __set(属性名,参数) — 为不存在的属性赋值时会自动调用
  • __get(属性名) — 访问不存在的属性时会自动调用
  • property_exists(类名,属性名) — 检查对象或类是否具有该属性
  • method_exists(类名,方法名) — 检查类的方法是否存在
  • interface_exists(接口名) — 检查接口是否已被定义
  • __call(方法名,参数名) — 访问当前环境下不存在或不可见的普通方法时,它将被触发
  • __callStaic(方法名,参数名) — 访问当前环境下不存在或不可见的静态方法/普通方法时,它将被触发

更多相关文章

  1. 判断是否为数组的 JavaScript 方法总结
  2. Windows还原系统后分区合并为一个分区恢复方法
  3. 补0816:拦截方法封装mysql查询语句
  4. opp基础:类与对象的 类的继承和调用 构造器 静态成员等
  5. 作业内容:oop基础:请举例实例演绎以下难点 1. 类(对象抽象化的结
  6. php面向对象之对象成员,静态成员,继承
  7. 快递100账户错误详解-接口账号,业务,增值服务,票据和其他常见问
  8. 快递100参数错误-面单类错误(电子面单/发货单/模板)常见问题和解
  9. 调用快递100接口物流信息错误常见问题和解决方法

随机推荐

  1. 关于Python的编码注释# -*- coding:utf-8
  2. Python列表以及列表的处理方法
  3. AttributeError:“MatrixFactorizationMo
  4. 小白学Python---面向对象02
  5. Spark学习,pyspark执行后默认启动Ipython
  6. 通过分隔符计数和位置从数据框中提取特定
  7. 安装python2.6.6到ubuntu12.04
  8. Java程序不像python程序那样工作,我不知道
  9. python中list的拷贝与numpy的array的拷贝
  10. Python之sorted内置函数