博客列表 >PHP 14 抽象类、接口、trait (0722wed)

PHP 14 抽象类、接口、trait (0722wed)

老黑
老黑原创
2020年07月23日 22:14:44500浏览

主要内容:

  1. 抽象类:部分做到“设计与实现”的分离
  2. 接口:完全做到“设计与实现”的分离
  3. 接口之间的继承(连续继承)
  4. trait:更为灵通的假“类”
  5. 实战,通过类实现数据增删改查

1. 抽象类:部分做到“设计与实现”的分离

  • 抽象类不能被直接实例化,是为子类服务的
  • 类似于将一些功能等隐藏到后台
  • 真正被实现的,或者叫干活的为子类
  • 抽象类中的抽象方法必须在子类中实现
  1. <?php
  2. // 父类: 设计类
  3. abstract class User
  4. {
  5. // 这里的访问控制符,如果这个成员允许在子类中使用,应该声明为protected,否则private
  6. protected $name = '超级用户';
  7. public function write1()
  8. {
  9. return '姓名: ' .$this->name;
  10. }
  11. // 抽象方法: 没有实现,只有声明, 子类中必须实现它
  12. abstract protected function write2();
  13. }
  14. // 子类:实现类, 工作类, 真正干活的是子类
  15. class Work extends User
  16. {
  17. protected $profession = '最大管理员';
  18. public function write2()
  19. {
  20. return parent::write1() . ', 职业: ' . $this->profession;
  21. }
  22. }
  23. // User类只当作父类就不应该允许被实例化
  24. // $user = new User();
  25. // 必须通过它的子类来调用抽象类中的方法
  26. // 客户端代码
  27. $work = new Work();
  28. // echo $work->write1();
  29. echo $work->write2();

2. 接口:完全做到“设计与实现”的分离

  • 类可以看作是对象的模板。接口有些时候甚至可以看作类的模板。
  • 估计意思是接口完全无法实例化。而且只能封装常量和方法 - 因为不允许有属性,而且禁止重写。
  • o:接口类似于更为严格的模板,因此也更安全一些。
  • o:关于类、接口传参这块不知道有无对应做法。后面可以摸索下。
  1. <?php
  2. // 1. 接口使用场景: 单接口(是否还有双接口,多接口?)
  3. interface iUser
  4. {
  5. // 在接口中所有成员都是抽象的
  6. // 接口成员的访问控制必须是public
  7. // 不允许有属性,但允许有接口常量, 禁止重写
  8. const NATION = 'CHINA';
  9. public function write();
  10. // 接口还可以有构造方法(后面讲)
  11. }
  12. // 2. 接口的实现类
  13. class User implements iUser
  14. {
  15. protected $profession = '最大管理员';
  16. // 接口中的抽象方法,实现类中必须实现
  17. public function write()
  18. {
  19. return '职业:'.$this->profession. ', 国籍: ' . iUser::NATION;
  20. }
  21. }
  22. // 客户端调用
  23. $user = new User();
  24. echo $user->write();

3. 接口之间的继承(连续继承)

  1. <?php
  2. // 接口应用场景2: 接口之间的继承
  3. // php中禁止多重继承: 单继承(一个接口只能继承一个接口,不能继承多接口)
  4. // 接口1
  5. interface iUser
  6. {
  7. const NATION = 'CHINA';
  8. }
  9. // 接口2
  10. interface iUser1 extends iUser
  11. {
  12. const USER_NAME = '机器猫';
  13. }
  14. // 接口3
  15. interface iUser2 extends iUser, iUser1
  16. {
  17. public function write();
  18. }
  19. // 实现类
  20. // class User implements iUser, iUser1, iUser2
  21. // iUser2已经继承了iUser, iUser1,所以只需要实现iUser2就可以了
  22. class User implements iUser2
  23. {
  24. // 必须实现接口中的抽象方法
  25. public function write()
  26. {
  27. return '姓名:'.iUser1::USER_NAME. ', 国籍: ' . iUser::NATION;
  28. }
  29. }
  30. // 调用
  31. echo (new User)->write();
  • 通过接口操作数据库的实战
  1. <?php
  2. // 接口应用场景3: 用抽象类来实现接口
  3. // ① 定义一个数据库的CURD接口
  4. interface iDbBase
  5. {
  6. // 新增
  7. public static function insert($db, $data);
  8. // 查询
  9. public static function select($db, $optoins=[]);
  10. // 更新
  11. public static function update($db, $options);
  12. // 删除
  13. public static function delete($db, $where);
  14. }
  15. // ② 实现类使用抽象类来充当
  16. abstract class aDb implements iDbBase
  17. {
  18. // 使用单例模式连接: 创建类的唯一实例,唯一对象
  19. protected static $db = null;
  20. // 抽象类充当接口实现类时, 不用必须实现接口中的抽象方法
  21. // 当实现类中的方法中有一些公共操作时,可以将这些操作放在中间的抽象类中实现它。例如这里的数据库连接。
  22. public static function connect($dsn, $username, $password)
  23. {
  24. if (is_null(self::$db)) {
  25. // 如果当前连接对象是null,表示未连接数据库
  26. self::$db = new PDO($dsn, $username, $password);
  27. }
  28. return self::$db;
  29. }
  30. }
  31. // ③ 类的真正实现类。实现一些具体的操作。
  32. class DB extends aDb
  33. {
  34. // 新增
  35. public static function insert($db, $data)
  36. {
  37. }
  38. // 查询
  39. public static function select($db, $optoins=[])
  40. {
  41. return $db->query('SELECT * FROM `users` LIMIT 3')->fetchAll(PDO::FETCH_ASSOC);
  42. }
  43. // 更新
  44. public static function update($db, $options)
  45. {
  46. }
  47. // 删除
  48. public static function delete($db, $where)
  49. {
  50. }
  51. }
  52. // 客户端代码
  53. // 连接参数
  54. $config = [
  55. // 类型
  56. 'type' => $type ?? 'mysql',
  57. // 默认数据库主机名(IP)
  58. 'host' => $host ?? 'localhost',
  59. // 默认数据库名
  60. 'dbname' => $type ?? 'phpedu',
  61. // 默认字符编码集
  62. 'charset' => $type ?? 'utf8',
  63. // 默认端口号
  64. 'port' => $type ?? '3306',
  65. // 默认用户名
  66. 'username' => $username ?? 'root',
  67. // 默认用户的密码
  68. 'password' => $password ?? 'root'
  69. ];
  70. $dsn = sprintf('%s:host=%s;dbname=%s;',$config['type'],$config['host'],$config['dbname']);
  71. $username = $config['username'];
  72. $password = $config['password'];
  73. $db =DB::connect($dsn, $username, $password);
  74. // 调用实现类DB中的select()进行查询
  75. foreach (DB::select($db) as $user) {
  76. print_r($user);
  77. }

4. trait:更为灵通的假“类”

  1. <?php
  2. // Trait: 特性
  3. // trait: 临时类,类中类, 可以嵌入到宿主类
  4. // trait: trait实现了一个类的横向功能扩展, 继承实现了类的垂直功能扩展
  5. // trait:可以使用类的语句,但不是类。因此不能实例化等。需要用use traitname去调用(有点像php文件间的require)。
  6. trait tDemo
  7. {
  8. // 1.常规成员
  9. protected $name = '机器猫';
  10. public function getName()
  11. {
  12. return $this->name;
  13. }
  14. // 2. 静态成员
  15. protected static $gender = '男';
  16. public static function getGender()
  17. {
  18. return self::$gender;
  19. }
  20. // 3. 抽象成员
  21. public static $age;
  22. abstract static function getAge();
  23. }
  24. // 在一个宿主类/工作类/实现类中使用
  25. class User
  26. {
  27. // 类中使用use 关键字引用trait成员
  28. use tDemo;
  29. // 在宿主类中还必须将trait中的抽象方法实现了
  30. static function getAge()
  31. {
  32. return self::$age;
  33. }
  34. }
  35. // 实例化
  36. $user = new User;
  37. User::$age = 39;
  38. echo $user->getName() . ': ' . $user->getGender(), ': ' .$user->getAge();

5. 实战 - 实现数据库增删该查

  1. <?php
  2. interface iDB{
  3. public static function insert($db, $data);
  4. public static function delete($db, $where);
  5. public static function update($db, $options);
  6. public static function select($db, $options);
  7. }
  8. abstract class aDB implements iDB{
  9. protected static $db = null;
  10. public static function connect($dsn, $username, $password)
  11. {
  12. if (is_null(self::$db)){
  13. self::$db = new PDO($dsn, $username, $password);
  14. }
  15. return self::$db;
  16. }
  17. }
  18. class cDB extends aDB
  19. {
  20. public static function insert($db, $data)
  21. {
  22. $sql = 'INSERT INTO `shao` (`date`, `title`, `label`, `others`) VALUES (?, ?, ?, ?)';
  23. $stmt = $db->prepare($sql);
  24. $stmt->execute($data);
  25. if ($stmt->rowCount() > 0) echo '新增成功 ' . $stmt->rowCount() . ' 条记录,主键id: ' . $db->lastInsertId();
  26. unset($db);
  27. }
  28. public static function delete($db, $where)
  29. {
  30. $sql = 'DELETE FROM `shao` WHERE id = ?';
  31. // 这个地方很有趣,只能传递已经有了的字段的值,不能传递字段名。例如将id也用?代替就不行。
  32. // 不过这块可以通过if条件来进行字段,及中间等号,大于号等的选择。
  33. $stmt = $db->prepare($sql);
  34. $stmt->execute($where);
  35. // if ($stmt->rowCount() > 0) echo '新增成功 ' . $stmt->rowCount() . ' 条记录,主键id: ' . $db->lastInsertId();
  36. // 删除成功后的提示,可以另外考虑。应该是删除前后的rowcount对比之类,或者查询之类的。
  37. unset($db);
  38. }
  39. public static function update($db, $options)
  40. {
  41. $sql = 'UPDATE `shao` SET `date`=?, `title`=?, `label`=?, `others`=? WHERE id = ?';
  42. $stmt = $db->prepare($sql);
  43. $stmt->execute($options);
  44. unset($db);
  45. }
  46. public static function select($db, $options=[])
  47. //这个地方也很奇怪,必须有=[],否则会报错。但其他的几个貌似都不需要。
  48. {
  49. $sql = 'SELECT * FROM `shao` WHERE id > ?';
  50. $stmt = $db->prepare($sql);
  51. $stmt->execute($options);
  52. return $stmt->fetchALL(PDO::FETCH_ASSOC);
  53. var_dump($stmt);
  54. unset($db);
  55. }
  56. }
  57. $config = [
  58. // 类型
  59. 'type' => $type ?? 'mysql',
  60. // 默认数据库主机名(IP)
  61. 'host' => $host ?? 'localhost',
  62. // 默认数据库名
  63. 'dbname' => $type ?? 'liangtest',
  64. // 默认字符编码集
  65. 'charset' => $type ?? 'utf8',
  66. // 默认端口号
  67. 'port' => $type ?? '3306',
  68. // 默认用户名
  69. 'username' => $username ?? 'liang',
  70. // 默认用户的密码
  71. 'password' => $password ?? 'xxxxxx'
  72. ];
  73. extract($config);
  74. $dsn= sprintf('%s:host=%s;dbname=%s;charset=%s;port=%s',$type,$host,$dbname,$charset,$port);
  75. $db = cDB::connect($dsn, $username, $password);
  76. //$data = ['2020-07-23','多test六下,没准你就成功了','努力,自我训练','NULL'];
  77. //cDB::insert($db,$data);
  78. //$where = ['28'];
  79. //cDB::delete($db,$where);
  80. //$options = ['2020-07-22', 'test八下,肯定会成功','个人,发展','NULL','22'];
  81. //cDB::update($db,$options);
  82. $options = ['25'];
  83. foreach (cDB::select($db,$options) as $item){
  84. print_r($item);
  85. }

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议