博客列表 >PHP 17 访问拦截器(属性、方法)、事件委托(0727mon)

PHP 17 访问拦截器(属性、方法)、事件委托(0727mon)

老黑
老黑原创
2020年07月29日 20:03:39636浏览

主要内容:

  1. 静态绑定应用场景-调用上下文
  2. 魔术方法
  3. 重载(访问拦截器) - 属性、方法
  4. 事件委托:方法重新定向(o:让别的类去完成任务)
  5. 实战:链式查询(数据库查询构造器)

1. 静态绑定应用场景-调用上下文

  1. <?php
  2. // 后期静态绑应用场景: 静态继承的上下文
  3. // 调用上下文 ==== 调用者
  4. // 动态绑定静态成员的调用者/调用上下文
  5. // 父类
  6. class Base
  7. {
  8. public static function index()
  9. {
  10. return __METHOD__;
  11. }
  12. public static function fetch()
  13. {
  14. // return self::index();
  15. return static::index();
  16. }
  17. // 在父类中, 尽可能少写或不写self,而是用static来代替,以提升代码的通用性
  18. }
  19. echo Base::fetch();
  20. // 静态方法调用用:: 普通方法用->
  21. echo '<hr>';
  22. // 子类
  23. class User extends Base
  24. {
  25. public static function index()
  26. {
  27. return __METHOD__;
  28. }
  29. }
  30. // 子类调用
  31. echo User::fetch();

2. 魔术方法

  • 魔术方法: 由某一个事件/行为来自动的触发,不允许用户主动调用
  • 魔术方法的前面是两个下划线__
  1. <?php
  2. class Product
  3. {
  4. public $name = '手机';
  5. public $price = 5800;
  6. }
  7. // 类的实例被创建出来的时候,应该有一个确定的初始状态
  8. $product = new Product();
  9. echo $product->name . ': ' . $product->price . '<hr>';
  10. $product->name = '电脑';
  11. $product->price = 9000;
  12. echo $product->name . ': ' . $product->price . '<hr>';
  13. /* 应该有一个方法,可以在类中实现对类的实例的状态进行初始化,对象的初始状态
  14. 这个方法就是构造方法,并且这个方法还必须且只能在对象被new的时候自动调用
  15. */
  16. class Product1
  17. {
  18. public $name;
  19. public $price;
  20. // 构造方法: 魔术方法, 公共方法
  21. public function __construct($name, $price)
  22. {
  23. // 1. 生成一个对象。这个命令及第3个命令都是默认生成的,不需要写。
  24. // $this = new self($name, $price);
  25. // 2. 给这个对象的属性初始化
  26. $this->name = $name;
  27. $this->price = $price;
  28. // 实例化的同时,可以自动调用一些方法(例如这个里面自定义的方法getInfo)
  29. echo $this->getInfo();
  30. // 3. 返回这个新对象
  31. // return $this;
  32. }
  33. // 输出
  34. public function getInfo()
  35. {
  36. return $this->name . ': ' . $this->price;
  37. }
  38. }
  39. new Product1('显示器', 3500);
  40. //因为里面有直接返回及echo,所以直接new就可以展示出来。

3. 重载(访问拦截器) - 属性

  • 重载: “访问拦截器”
  • 类: 二类成员, 属性和方法,所以也有二种重载: 属性重载和方法重载
  • 换个叫法: 属性拦截器 和 方法拦截器
  • get(), set(), isset(), unset()

  • 四个步骤:

    1. 从类的外部访问类中不存在或者无权限访问的属性的时候,会被拒绝
    2. 如果类中存在__get($propName)魔术方法的时候会调用它来处理这个非法访问
    3. 属性访问拦截器就是借助了__get()方法,拦截了用户对类内部的属性的访问,动态生成访问接口/方法
    4. 再创建一个属性的访问方法,如getName(), getPrice(),这个方法名称应该有一定的规律
      总的如下:
      $product->price ====> __get() ===> 动态生成getPrice()类方法名称===>调用getPrice()方法来处理
  1. <?php
  2. class Product
  3. {
  4. private $name;
  5. private $price;
  6. // 不含税价
  7. private $taxRate = 0.06;
  8. // 构造方法
  9. public function __construct($name, $price)
  10. {
  11. $this->name = $name;
  12. $this->price = $price;
  13. }
  14. /*__get($name):
  15. 当外部访问一个不存在或者无权限访问的属性的时候会自动调用__get
  16. - 调用一个类内部的方法对外部的属性访问进行过滤(更安全)
  17. 1. 根据属性名称生成对应的属性访问接口方法
  18. name ===> get+ Name, price ===> get+ Price(首字母大写)
  19. 2. 调用这个处理属性访问的方法
  20. */
  21. public function __get($name)
  22. {
  23. $method = 'get' . ucfirst($name);//首字母大写
  24. return method_exists($this, $method) ? $this->$method() : null;
  25. }
  26. /* 使用__set()魔术方法可以将用户对属性的更新操作进行重定向
  27. 调用一个类内部的方法对外部的属性更新修改进行过滤
  28. 1. 根据属性名称生成对应的属性访问接口方法
  29. // name ===> set+ Name, price ===> set+ Price
  30. 2. 调用这个处理属性访问的方法
  31. */
  32. public function __set($name, $value) //多了value进行赋值
  33. {
  34. $method = 'set' . ucfirst($name);
  35. return method_exists($this, $method) ? $this->$method($value) : null;
  36. }
  37. // 类中为私有成员 提供了一个访问接口来过滤外部的访问请求
  38. // o: 这个地方应该是服务于上面的__get和__set
  39. private function getName()
  40. {
  41. return mb_substr($this->name, 0, 10); //从0开始取name的前10位字节
  42. }
  43. private function getPrice()
  44. {
  45. return $this->price + $this->price * $this->taxRate;
  46. }
  47. // 属性修改接口
  48. private function setName($value)
  49. {
  50. return $this->name = trim($value);
  51. }
  52. private function setPrice($value)
  53. {
  54. return $this->price = $value *(1-$this->taxRate);
  55. }
  56. }
  57. $product = new Product('显示器 27, 2020款, Dell, 144Hz', 3500);
  58. // echo $product->name . ': ' . $product->price;
  59. // 这个方法实际项目中应该在类的内部 调用
  60. // echo $product->getName();
  61. // 这种方法更直观
  62. echo $product->name , '... : 含税价: ' , $product->price, ' 元';
  63. $product->name = '外套';
  64. $product->price = 780;
  65. echo '<hr>';
  66. echo $product->name, ' : 含税价: ' , $product->price, ' 元';

4. 重载(访问拦截器) - 方法

  1. <?php
  2. // 方法拦截器,当从类的外部,访问类中不存在或无权限访问的方法的时候,会自动调用它
  3. class User
  4. {
  5. // 方法拦截器也是一个魔术方法__call(方法名称, 参数数组)
  6. public function __call(string $name, array $args)
  7. {
  8. printf('方法名: %s(), 参数 [%s]', $name, implode(', ', $args));
  9. //implode为将array转化为字符串。
  10. }
  11. // 静态方法拦截器: __callSatic(方法名称, 参数数组)
  12. public static function __callStatic(string $name, array $args)
  13. {
  14. printf('方法名: %s(), 参数 [%s]', $name, implode(', ', $args));
  15. }
  16. }
  17. $user = new User;
  18. $user->hello('a', 'b', 'c');
  19. echo '<hr>';
  20. User::demo(1,2,3,4);

5. 事件委托:方法重新定向

  1. <?php
  2. class Base
  3. {
  4. public function write(...$args) //...为展开
  5. {
  6. printf('方法名: %s(), 参数 [%s]',__METHOD__, implode(', ', $args));
  7. }
  8. public static function fetch(...$args)
  9. {
  10. printf('方法名: %s(), 参数 [%s]',__METHOD__, implode(', ', $args));
  11. }
  12. }
  13. // 工作类
  14. class Work
  15. {
  16. // 事件委托时,重定向到的目标类
  17. private $base;
  18. // 将$base初始化
  19. public function __construct(Base $base)
  20. {
  21. $this->base = $base;
  22. }
  23. // 方法拦截器,将$this->write()重定向到$this->base->write()
  24. public function __call($name, $args)
  25. {
  26. // 将$this->$name()重定向到$this->base->$name()
  27. if (method_exists($this->base, $name))
  28. // return $this->base->$name($name, $args); 这个也可以,但基本上不用
  29. // 用回调的方式来调用: call_user_func_array(函数, 参数数组)
  30. // 如果是一个对象的方法,应该使用数组的方式: [对象, '方法名']
  31. return call_user_func_array([$this->base, 'write'], $args);
  32. }
  33. // 方法拦截器,将self::fetch()重定向到Base::fetch()
  34. public static function __callStatic($name, $args)
  35. {
  36. if (method_exists('Base', $name))
  37. return call_user_func_array(['Base', 'fetch'], $args);
  38. // call_user_func_array()的介绍见下面
  39. }
  40. }
  41. $base = new Base();
  42. $work = new Work($base);
  43. $work->write(1,2,3);
  44. $work::fetch('abc', 'ppp', 'www');
  • call_user_func_array
    call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数
    call_user_func_array ( callable $callback , array $param_arr ) : mixed
    把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入。
    callback
    被调用的回调函数。
    param_arr
    要被传入回调函数的数组,这个数组得是索引数组。
    返回值
    返回回调函数的结果。如果出错的话就返回FALSE

6. 实战:链式查询(数据库查询构造器)

  • 方法委托/方法拦截器 实战: 数据库查询构造器(链式查询)
  1. <?php
  2. // 查询类
  3. class Query
  4. {
  5. // 连接对象
  6. protected $db;
  7. // 数据表
  8. protected $table;
  9. // 字段列表
  10. protected $field;
  11. // 记录数量
  12. protected $limit;
  13. // 构造方法: 连接数据库
  14. public function __construct($dsn, $username, $password)
  15. {
  16. $this->connect($dsn, $username, $password);
  17. }
  18. // 连接数据库
  19. private function connect($dsn, $username, $password)
  20. {
  21. $this->db = new PDO($dsn, $username, $password);
  22. }
  23. // 设置默认的数据表名称
  24. public function table($table)
  25. {
  26. $this->table = $table;
  27. return $this;
  28. }
  29. // 设置默认的字段名称
  30. public function field($field)
  31. {
  32. $this->field = $field;
  33. return $this;
  34. }
  35. // 链式方法: 设置查询数量
  36. public function limit($limit)
  37. {
  38. $this->limit = $limit;
  39. return $this;
  40. }
  41. // 生成查询语句
  42. protected function getSql()
  43. {
  44. return sprintf('SELECT %s FROM %s LIMIT %s', $this->field, $this->table, $this->limit);
  45. }
  46. // 执行查询
  47. public function select()
  48. {
  49. return $this->db->query($this->getSql())->fetchAll(PDO::FETCH_ASSOC);
  50. }
  51. }
  52. // 数据据操作类
  53. class DB
  54. {
  55. // 静态方法委托
  56. public static function __callStatic($name, $args)
  57. {
  58. // 获取到查询类的对象: new Query()
  59. $dsn = 'mysql:host=localhost;dbname=phpedu';
  60. $username = 'root';
  61. $password = 'root';
  62. $query = new Query($dsn, $username, $password);
  63. // 直接跳到Query类中的具体方法来调用
  64. return call_user_func([$query, $name], ...$args);
  65. }
  66. }
  67. $result = DB::table('users')
  68. // 字段列表
  69. ->field('id,name,email')
  70. ->limit(5)
  71. // 开始查询
  72. ->select();
  73. print_r($result);

7. 实战

  • select
  1. <?php
  2. // 0727作业
  3. // 1. 实例演示方法拦截器的__isset(), __unset()//时间问题,这个职能后面再做了。
  4. // 2. 实例演示查询构造器中的inset(),update(),delete()方法
  5. // 查询类
  6. class Query
  7. {
  8. protected $db;
  9. protected $table;
  10. protected $field;
  11. protected $limit;
  12. public function __construct($dsn, $username, $password)
  13. {
  14. $this->connect($dsn, $username, $password);
  15. }
  16. // 连接数据库
  17. private function connect($dsn, $username, $password)
  18. {
  19. $this->db = new PDO($dsn, $username, $password);
  20. }
  21. public function table($table)
  22. {
  23. $this->table = $table;
  24. return $this;
  25. }
  26. public function field($field)
  27. {
  28. $this->field = $field;
  29. return $this;
  30. }
  31. public function limit($limit)
  32. {
  33. $this->limit = $limit;
  34. return $this;
  35. }
  36. // 生成查询语句
  37. protected function getSql()
  38. {
  39. return sprintf('SELECT %s FROM %s LIMIT %s', $this->field, $this->table, $this->limit);
  40. }
  41. // 执行查询
  42. public function select()
  43. {
  44. return $this->db->query($this->getSql())->fetchAll(PDO::FETCH_ASSOC);
  45. }
  46. }
  47. // 数据据操作类
  48. class DB
  49. {
  50. // 静态方法委托
  51. public static function __callStatic($name, $args)
  52. {
  53. // 获取到查询类的对象: new Query()
  54. $dsn = 'mysql:host=localhost;dbname=liangtest';
  55. $username = 'liang';
  56. $password = '123456';
  57. $query = new Query($dsn, $username, $password);
  58. // 直接跳到Query类中的具体方法来调用
  59. return call_user_func([$query, $name], ...$args);
  60. }
  61. }
  62. $result = DB::table('my_list')
  63. // 字段列表
  64. ->field('id,name,age,phone')
  65. ->limit(6)
  66. // 开始查询
  67. ->select();
  68. print_r($result);

  • insert
  1. <?php
  2. // 0727作业
  3. // 1. 实例演示方法拦截器的__isset(), __unset()
  4. // 2. 实例演示查询构造器中的inset(),update(),delete()方法
  5. // 查询类
  6. class Query
  7. {
  8. protected $db;
  9. protected $table;
  10. protected $field;
  11. protected $limit;
  12. public function __construct($dsn, $username, $password)
  13. {
  14. $this->connect($dsn, $username, $password);
  15. }
  16. // 连接数据库
  17. private function connect($dsn, $username, $password)
  18. {
  19. $this->db = new PDO($dsn, $username, $password);
  20. }
  21. public function table($table)
  22. {
  23. $this->table = $table;
  24. return $this;
  25. }
  26. public function field($field)
  27. {
  28. $this->field = $field;
  29. return $this;
  30. }
  31. public function values($values)
  32. {
  33. $this->values = $values;
  34. return $this;
  35. }
  36. // 生成查询语句
  37. protected function getSql()
  38. {
  39. return sprintf('INSERT INTO %s (%s) VALUES(%s)', $this->table, $this->field, $this->values);
  40. }
  41. // 执行查询
  42. public function insert()
  43. {
  44. return $this->db->query($this->getSql());
  45. }
  46. }
  47. class DB
  48. {
  49. public static function __callStatic($name, $args)
  50. {
  51. $dsn = 'mysql:host=localhost;dbname=liangtest';
  52. $username = 'liang';
  53. $password = '123456';
  54. $query = new Query($dsn, $username, $password);
  55. return call_user_func([$query, $name], ...$args);
  56. }
  57. }
  58. $result = DB::table('my_list')
  59. ->field('id,name,age,phone')
  60. ->values("'202','王三元','19','234321'")//这个地方是大括号套小括号,好不容易试错试出来的。
  61. ->insert();
  62. print_r($result);

  • update
  1. <?php
  2. // 0727作业
  3. // 1. 实例演示方法拦截器的__isset(), __unset()
  4. // 2. 实例演示查询构造器中的inset(),update(),delete()方法
  5. // 查询类
  6. class Query
  7. {
  8. protected $db;
  9. protected $table;
  10. protected $field;
  11. protected $limit;
  12. public function __construct($dsn, $username, $password)
  13. {
  14. $this->connect($dsn, $username, $password);
  15. }
  16. // 连接数据库
  17. private function connect($dsn, $username, $password)
  18. {
  19. $this->db = new PDO($dsn, $username, $password);
  20. }
  21. public function table($table)
  22. {
  23. $this->table = $table;
  24. return $this;
  25. }
  26. public function field($field)
  27. {
  28. $this->field = $field;
  29. return $this;
  30. }
  31. public function values($values)
  32. {
  33. $this->values = $values;
  34. return $this;
  35. }
  36. // 生成查询语句
  37. protected function getSql()
  38. {
  39. return sprintf('UPDATE %s SET %s = %s', $this->table, $this->field, $this->values);
  40. }
  41. // 执行查询
  42. public function update()
  43. {
  44. return $this->db->query($this->getSql());
  45. }
  46. }
  47. class DB
  48. {
  49. public static function __callStatic($name, $args)
  50. {
  51. $dsn = 'mysql:host=localhost;dbname=liangtest';
  52. $username = 'liang';
  53. $password = '123456';
  54. $query = new Query($dsn, $username, $password);
  55. return call_user_func([$query, $name], ...$args);
  56. }
  57. }
  58. $result = DB::table('my_list')
  59. ->field('phone')
  60. ->values('234322')
  61. ->update();
  62. print_r($result);

  • delete
  1. <?php
  2. // 0727作业
  3. // 1. 实例演示方法拦截器的__isset(), __unset()
  4. // 2. 实例演示查询构造器中的inset(),update(),delete()方法
  5. // 查询类
  6. class Query
  7. {
  8. protected $db;
  9. protected $table;
  10. protected $field;
  11. protected $limit;
  12. public function __construct($dsn, $username, $password)
  13. {
  14. $this->connect($dsn, $username, $password);
  15. }
  16. // 连接数据库
  17. private function connect($dsn, $username, $password)
  18. {
  19. $this->db = new PDO($dsn, $username, $password);
  20. }
  21. public function table($table)
  22. {
  23. $this->table = $table;
  24. return $this;
  25. }
  26. public function field($field)
  27. {
  28. $this->field = $field;
  29. return $this;
  30. }
  31. public function values($values)
  32. {
  33. $this->values = $values;
  34. return $this;
  35. }
  36. // 生成查询语句
  37. protected function getSql()
  38. {
  39. return sprintf('DELETE FROM %s WHERE %s = %s', $this->table, $this->field, $this->values);
  40. }
  41. // 执行查询
  42. public function delete()
  43. {
  44. return $this->db->query($this->getSql());
  45. }
  46. }
  47. class DB
  48. {
  49. public static function __callStatic($name, $args)
  50. {
  51. $dsn = 'mysql:host=localhost;dbname=liangtest';
  52. $username = 'liang';
  53. $password = '123456';
  54. $query = new Query($dsn, $username, $password);
  55. return call_user_func([$query, $name], ...$args);
  56. }
  57. }
  58. $result = DB::table('my_list')
  59. ->field('phone')
  60. ->values('234321')
  61. ->delete();
  62. print_r($result);
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议