首先!

接口也可以继承,通过使用 extends 操作符。

案例:

  1. <?php
  2. interface a
  3. {
  4. public function foo();
  5. }
  6.  
  7. interface b extends a
  8. {
  9. public function baz(Baz $baz);
  10. }
  11.  
  12. // 正确写法
  13. class c implements b
  14. {
  15. public function foo()
  16. {
  17. }
  18.  
  19. public function baz(Baz $baz)
  20. {
  21. }
  22. }

然后!

我们在来说说我们的主题!

接口不是新特性但是很重要,接口是两个php对象的契约。其目的不是让一个对象依赖另一个对象的身份,而是依赖另一个对象的能力。接口把我们的代码和依赖解耦,而且允许我们的代码依赖任何实现了预期接口的第三方代码。我们不关心第三方代码如何实现接口,只去关心他有没有去实现接口。

如果我们写的类去处理特定的对象, 那么类的功能就被限定了,只能处理那个类。但是我们的对象如果是处理的接口,那么代码立即就能知道如何处理实现这一接口的任何对象,我们的代码不管接口如何实现只需要关心有没有实现。

文档处理类实现

  1. <?php
  2.  
  3. class DocumentStore{
  4.  
  5. protected $data = [];
  6.  
  7. /**
  8.  
  9. * 参数限定为 Documentable 对象,这是一个接口
  10.  
  11. */
  12.  
  13. public function addDocument(Documentable $document){
  14.  
  15. $key = $document->getId();
  16.  
  17. $value = $document->getContent();
  18.  
  19. $this->data[$key] = $value;
  20.  
  21. }
  22.  
  23. public function getDocuments(){
  24.  
  25. return $this->data;
  26.  
  27. }
  28.  
  29. }

这个是我们的文档处理类,它面向的是接口操作 Documentable 实现:

  1. <?php
  2.  
  3. interface Documentable{
  4.  
  5. public function getId();
  6.  
  7. public function getContent();
  8.  
  9. }

具体实现接口的类,比如是从html获得的文档 实现:

  1. <?php
  2.  
  3. class HtmlDocument implements Documentable{
  4.  
  5. protected $url;
  6.  
  7. publicfunction__construct($url)
  8.  
  9. {
  10.  
  11. $this->url = $url;
  12.  
  13. }
  14.  
  15. public function getId()
  16.  
  17. {
  18.  
  19. return $this->url;
  20.  
  21. }
  22.  
  23. public function getContent()
  24.  
  25. {
  26.  
  27. $ch = curl_init();
  28.  
  29. curl_setopt($ch, CURLOPT_URL, $this->url);
  30.  
  31. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  32.  
  33. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
  34.  
  35. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  36.  
  37. curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
  38.  
  39. $html = curl_exec($ch);
  40.  
  41. curl_close($ch);
  42.  
  43. return $html;
  44.  
  45. }
  46.  
  47. }

读取流数据的文档 实现:

  1. <?php
  2.  
  3. class StreamDocument implements Documentable{
  4.  
  5. protected $resource;
  6.  
  7. protected $buffer;
  8.  
  9. publicfunction__construct($resource, $buffer = 4096)
  10.  
  11. {
  12.  
  13. $this->resource = $resource;
  14.  
  15. $this->buffer = $buffer;
  16.  
  17. }
  18.  
  19. public function getId()
  20.  
  21. {
  22.  
  23. return 'resource-' . (int)$this->resource;
  24.  
  25. }
  26.  
  27. public function getContent()
  28.  
  29. {
  30.  
  31. $streamContent = '';
  32.  
  33. rewind($this->resource);
  34.  
  35. while(feof($this->resource) === false) {
  36.  
  37. $streamContent .= fread($this->resource, $this->buffer);
  38.  
  39. }
  40.  
  41. return $streamContent;
  42.  
  43. }
  44.  
  45. }

具体使用 :

  1. <?php
  2.  
  3. require 'Documentable.php';
  4.  
  5. require 'DocumentStore.php';
  6.  
  7. require 'HtmlDocument.php';
  8.  
  9. require 'StreamDocument.php';
  10.  
  11. require 'CommandOutputDocument.php';
  12.  
  13. $documentStore = newDocumentStore();
  14.  
  15. // Add HTML document
  16.  
  17. $htmlDoc = new HtmlDocument('http://php.net');
  18.  
  19. $documentStore->addDocument($htmlDoc);
  20.  
  21. // Add stream document
  22.  
  23. $streamDoc = new StreamDocument(fopen('stream.txt', 'rb'));
  24.  
  25. $documentStore->addDocument($streamDoc);
  26.  
  27. // Add terminal command document
  28.  
  29. $cmdDoc = new CommandOutputDocument('cat /etc/hosts');
  30.  
  31. $documentStore->addDocument($cmdDoc);
  32.  
  33. print_r($documentStore->getDocuments());

需要说明的是参数类型 addDocument 参数类型限定为 Documentable 实现该接口的对象都可以做参数。

性状( trait )

性状是类的部分实现,可以混入一个或者多个现有的类实现中,有两个作用:

1表明类可以做什么;

2 提供模块化实现;

使用场景:

我们做面向对象的开发的时候都会通过基类实现基本功能,完后子类具体实现详细的功能,各类之间有明显的自然的继承关系,如果有一个逻辑既不属于A类也不属于B类,那么在性状出现之前我们怎么解决:

解决办法一:做一个父类 让A, B都继承,这样做的缺点是,强制把两个不相关的类继承同一父类,结构混乱破坏了封装。

解决方法二:做一个接口,让A, B都去实现这个接口,强于上一个方法,但是缺点是相同的逻辑会在多个类中实现,代码逻辑冗余,加大维护成本。

解决办法三:使用性状(trait)推荐做法。

定义性状:

  1. <?php
  2.  
  3. // 推荐把性状当类看待,一个文件定义一个性状
  4.  
  5. trait MyTrait {
  6.  
  7. protected $p1;
  8.  
  9. public $p2;
  10.  
  11. public function f1(){
  12.  
  13. }
  14.  
  15. }

使用性状:

  1. <?php
  2.  
  3. class MyClass{
  4.  
  5. use MyTrait;
  6.  
  7. }

之后实例对象就可以使用性状里的属性方法就像使用本类的一样;php解释器会把性状的代码复制到类定义中,有点像c语言中的宏。

PHP 新特性:如何善用接口与Trait的更多相关文章

  1. 乐字节-Java8新特性之函数式接口

    上一篇小乐带大家学过 Java8新特性-Lambda表达式,那什么时候可以使用Lambda?通常Lambda表达式是用在函数式接口上使用的.从Java8开始引入了函数式接口,其说明比较简单:函数式接口 ...

  2. 现代 PHP 新特性系列(三) —— Trait 概览

    Trait是PHP 5.4引入的新概念,看上去既像类又像接口,其实都不是,Trait可以看做类的部分实现,可以混入一个或多个现有的PHP类中,其作用有两个:表明类可以做什么:提供模块化实现.Trait ...

  3. Java8 新特性之默认接口方法

    摘要: 从java8开始,接口不只是一个只能声明方法的地方,我们还可以在声明方法时,给方法一个默认的实现,我们称之为默认接口方法,这样所有实现该接口的子类都可以持有该方法的默认实现. · 待定 一. ...

  4. Java 8新特性-1 函数式接口

    Java 8 引入的一个核心概念是函数式接口(Functional Interfaces). 通过在接口里面添加一个抽象方法,这些方法可以直接从接口中运行. 如果一个接口定义个唯一一个抽象方法,那么这 ...

  5. Java8新特性之四:接口默认方法和静态方法

    在JDK1.8以前,接口(interface)没有提供任何具体的实现,在<JAVA编程思想>中是这样描述的:"interface这个关键字产生了一个完全抽象的类,它根本就没有提供 ...

  6. Java8新特性:Function接口和Lambda表达式参考

    Lambda基本:https://blog.csdn.net/wargon/article/details/80656575 https://www.cnblogs.com/hyyq/p/742566 ...

  7. [译]java9新特性:在接口中用pirvate方法让default(java8接口特性)更简练

    Java8 带来了许多改变,其中之一就是default修饰的接口方法. 这些方法改变了我们已知的接口,现在我们能够在接口中定义默认实现方法.默认实现方法的不同之处在于,在接口中用default修饰抽象 ...

  8. Java8新特性之函数式接口

    <Java 8 实战>学习笔记系列 定义 函数式接口只定义一个抽象方法,可以有多个默认方法 函数式接口的接口名上,会被@FunctionalInterface标注 作用 函数式接口的方法可 ...

  9. Java(44)JDK新特性之函数式接口

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201667.html 博客主页:https://www.cnblogs.com/testero ...

随机推荐

  1. 数字反转 NOIp普及组2011

    当数字位数不确定时,如何反转呢? 本文为博客园ShyButHandsome原创作品,转载请注明出处 使用右侧目录快速浏览文章 题目描述 给定一个整数,请将该数各个位上数字反转得到一个新数. 新数也应满 ...

  2. 通用mapper常用注解

    通用mapper的作用: 自动实现单表的增删改查 常用注解使用 @Table 作用:建立实体类和数据库表之间的对应关系. 默认规则:实体类类名首字母小写作为表名.Employee 类→employee ...

  3. Javascript/Jquery实现日期前一天后一天

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  4. js函数基础回顾

    回头又跑去看了下尚硅谷的js基础视频 https://www.bilibili.com/video/av22958172/?p=51. 便做了如下笔记: 1.函数也是一个对象 2.函数可以封装一些功能 ...

  5. python中的列表和元组都有哪些区别

    列表(list)和元组(tuple)的一些基础 list和tuple都是一个可以放置任意数据类型的有序集合,都是既可以存放数字.字符串.对象等 list和tuple都支持负索引 In [8]: num ...

  6. STM32F103C8T6最小系统开发板原理图

    1.

  7. P1627 [CQOI2009]中位数 题解

    CSDN同步 原题链接 简要题意: 给定一个 \(1\) ~ \(n\) 的排列,求以 \(b\) 为中位数的 连续子序列且长度为奇数 的个数. 显然这段序列包含 \(b\). 中位数的定义:排序后在 ...

  8. VAuditDemo-任意文件读取

    任意文件读取是属于文件操作漏洞的一种. 一般任意文件读取漏洞可以读取配置信息.甚至系统重要文件. 严重的话,就可能导致SSRF,进而漫游内网. 文件操作漏洞 任意文件删除--删除lock 任意文件复制 ...

  9. Array(数组)对象-->数组遍历

    1.数组的遍历: 方法1:使用for循环语句 /*定义数组*/ var arr=[1,2,3,4,5]; /*遍历*/ for (var i = 0;i<arr.length;i++){ con ...

  10. C++线性表的链式存储结构

    C++实现线性表的链式存储结构: 为了解决顺序存储不足:用线性表另外一种结构-链式存储.在顺序存储结构(数组描述)中,元素的地址是由数学公式决定的,而在链式储存结构中,元素的地址是随机分布的,每个元素 ...