• PHP 新特性:如何善用接口与Trait


    首先!

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

    案例:

    <?php
    interface a
    {
        public function foo();
    }
    
    interface b extends a
    {
        public function baz(Baz $baz);
    }
    
    // 正确写法
    class c implements b
    {
        public function foo()
        {
        }
    
        public function baz(Baz $baz)
        {
        }
    }

    然后!

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

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

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

    文档处理类实现

    <?php
    
    class DocumentStore{
    
    protected $data = [];
    
    /**
    
    * 参数限定为 Documentable 对象,这是一个接口
    
    */
    
    public function addDocument(Documentable $document){
    
    $key = $document->getId();
    
    $value = $document->getContent();
    
    $this->data[$key] = $value;
    
    }
    
    public function getDocuments(){
    
    return $this->data;
    
    }
    
    }

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

    <?php
    
    interface Documentable{
    
    public function getId();
    
    public function getContent();
    
    }

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

    <?php
    
    class HtmlDocument implements Documentable{
    
    protected $url;
    
    publicfunction__construct($url)
    
    {
    
    $this->url = $url;
    
    }
    
    public function getId()
    
    {
    
    return $this->url;
    
    }
    
    public function getContent()
    
    {
    
    $ch = curl_init();
    
    curl_setopt($ch, CURLOPT_URL, $this->url);
    
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
    
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    
    curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
    
    $html = curl_exec($ch);
    
    curl_close($ch);
    
    return $html;
    
    }
    
    }

    读取流数据的文档 实现:

    <?php
    
    class StreamDocument implements Documentable{
    
    protected $resource;
    
    protected $buffer;
    
    publicfunction__construct($resource, $buffer = 4096)
    
    {
    
    $this->resource = $resource;
    
    $this->buffer = $buffer;
    
    }
    
    public function getId()
    
    {
    
    return 'resource-' . (int)$this->resource;
    
    }
    
    public function getContent()
    
    {
    
    $streamContent = '';
    
    rewind($this->resource);
    
    while(feof($this->resource) === false) {
    
    $streamContent .= fread($this->resource, $this->buffer);
    
    }
    
    return $streamContent;
    
    }
    
    }

    具体使用 :

    <?php
    
    require 'Documentable.php';
    
    require 'DocumentStore.php';
    
    require 'HtmlDocument.php';
    
    require 'StreamDocument.php';
    
    require 'CommandOutputDocument.php';
    
    $documentStore = newDocumentStore();
    
    // Add HTML document
    
    $htmlDoc = new HtmlDocument('http://php.net');
    
    $documentStore->addDocument($htmlDoc);
    
    // Add stream document
    
    $streamDoc = new StreamDocument(fopen('stream.txt', 'rb'));
    
    $documentStore->addDocument($streamDoc);
    
    // Add terminal command document
    
    $cmdDoc = new CommandOutputDocument('cat /etc/hosts');
    
    $documentStore->addDocument($cmdDoc);
    
    print_r($documentStore->getDocuments());

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

    性状( trait )

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

    1表明类可以做什么;

    2 提供模块化实现;

    使用场景:

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

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

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

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

    定义性状:

    <?php
    
    // 推荐把性状当类看待,一个文件定义一个性状
    
    trait MyTrait {
    
    protected $p1;
    
    public $p2;
    
    public function f1(){
    
    }
    
    }

    使用性状:

    <?php
    
    class MyClass{
    
    use MyTrait;
    
    }

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

  • 相关阅读:
    html之长文本框置顶
    Red Hat Enterprise Linux Server 6.5安装GCC 4.9.2
    精通正则表达式
    解决UNION ALL合并两个结果集后排序的问题
    ELK搭建日志管理系统记录
    Spring Boot使用@ConfigurationProperties 读取自定义的properties的方法
    maven配置profile,按指定环境打包
    java自定义标签,tld文件,获取数据字典的值
    JAVA实现RSA签名、验签
    jquery.validate.js中的remote用法
  • 原文地址:https://www.cnblogs.com/laijinquan/p/11002856.html
Copyright © 2020-2023  润新知