Blogger Information
Blog 16
fans 0
comment 0
visits 11215
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
php 重载与事件委托
逃逃
Original
512 people have browsed it

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(方法名,参数名) — 访问当前环境下不存在或不可见的静态方法/普通方法时,它将被触发
Correcting teacher:PHPzPHPz

Correction status:qualified

Teacher's comments:
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post