多个不相关接口的类型提示

Posted

技术标签:

【中文标题】多个不相关接口的类型提示【英文标题】:Type Hinting For Multiple Unrelated Interfaces 【发布时间】:2011-07-06 21:25:07 【问题描述】:

php 中有没有办法为两个不同的、不相关的接口输入提示?例如:

interface errorable 
   function error($msg);


interface recordable 
   ssh_for_recorder();


class uploader__module extends base__module implements errorable, recordable 
   public function ssh_for_recorder() 
      return new ssh2;
   
   public function error($msg) 
      $this->errors[] = $msg;
   

   public function upload() 
      $recorder = new recorder($this);
      $recorder->run();
   


class recorder 
   private $ssh2;
   private $module;
   private function upload() 
      if (!$this->ssh2) 
         $this->module->error("No SSH2 connection");
      
   
   public function __construct(recordable,errorable $module) 
      $this->module = $module;
      $this->ssh2 = $module->ssh_for_recorder();
   

正如您在上面的代码中看到的,记录器类希望其模块能够同时运行error()ssh_for_recorder(),但它们是由不同的接口定义的。 errorable 不一定是可记录的,反之亦然。

是否有执行此操作的最佳做​​法?我正在考虑创建一个从可记录和可错误扩展的接口并让 upload__module 实现它,但我不知道该怎么称呼它。

【问题讨论】:

这与类型提示有什么关系? 查看记录器的构造函数。我想输入既可记录又可出错的提示。 我认为@Hammish 很困惑,PHP 中的类型提示要求类是某种类型,而@tandu 需要检查多种类型的接口。 【参考方案1】:

不,这在 php 中是不可能的。

还有其他语言(主要是函数式)支持这种称为联合类型 (http://en.wikipedia.org/wiki/Sum_type) 的特性。

【讨论】:

你建议如何在 PHP 中解决这个问题? 好吧,创建一个既可记录又可出错的新界面。但是,您必须更改实现这两个接口的类来实现新接口。 如我所想。我最终得到了可记录的扩展错误,因此在我的应用程序中也解决了。【参考方案2】:

PHP 中唯一的 hack 是一个辅助函数,可以在方法中为您执行检查,如下所示:

function CheckInterfaces($object,array $interfaces)

    foreach($interfaces as $i)
    
         if(!is_a($object,$i))
         
             return false;
         
    
    return true;

然后在方法内做:

public function Something($object)

    if(CheckInterfaces($object,array("foo","bar")))
    
        throw new ArgumentException(gat_class($object) . " Must be a member of foo,bar to be passed to Something");
    

解决此问题的另一种方法是为您所需的接口创建联合接口,这里是快速示例

interface foobar extends foo,bar

那么您可以只要求foobar 用于该方法。

【讨论】:

#1 很有趣,但我认为它太过分了。我更喜欢#2。不过,请注意,接口扩展了其他接口,它们不实现它们。您的代码将导致语法错误。 虽然这是唯一合理的解决方案,但我不喜欢2,因为我还必须更改类来实现联合接口,而不是单独的单独接口 它是#2。就是这样。【参考方案3】:

即使您已经接受了一个答案,我还是决定回答这个问题,因为给出的答案都不是真正可以接受的。虽然公认的答案在技术上是正确的,但有办法绕过它。至于其他答案,他们的解决方法不优雅,也不完全令人满意。

PHP 支持一个相当模糊的特性,它允许一个接口从另一个接口继承,实际上一个接口能够从多个基本接口继承。

例如,以下是完全有效的:

interface iFoo

    public function doFoo ();


interface iBar

    public function doBar ();


interface iBaz extends iFoo, iBar

    // This interface implicitly has all the methods of iFoo and iBar

从语义上讲,如果您希望方法/函数只接受实现多个接口的参数,那么这往往表明您希望实现同一组多个接口的类实际上应该实现一个涵盖两者的接口您希望参数符合的接口。

在你的情况下,如果你想要一个既可出错又可记录的东西,那么你只需要添加以下接口:

interface RecordableErrorable extends Recordable, Errorable  

然后,您的 Recorder 类的构造函数将只期望该接口作为其参数。

public function __construct(RecordableErrorable $module)  

如果 Recordable 和 Errorable 都实现了同名的方法,一个可能的症结可能是。那里将发生需要解决的冲突。我确实相信 PHP 中有处理这种情况的机制,尽管我不能告诉你它们是什么。

【讨论】:

【参考方案4】:
public function __construct(recordable $recordable_module, errorable $errorable_module) 

  if($recordable_module == $errorable_module)
     $module = $recordable_module;
  
  $this->module = $module;
  $this->ssh2 = $module->ssh_for_recorder();

【讨论】:

以上是关于多个不相关接口的类型提示的主要内容,如果未能解决你的问题,请参考以下文章

go语言学习笔记 — 进阶 — 接口(3.2):接口与类型的关系 —— 多个类型可以实现一个(相同)接口

collection相关方法

如何在Java类中定义接口属性并如何使用接口的方法

Typescript、接口、类型、多个可选属性、以其他属性为条件的属性

PHP 7 接口,返回类型提示和自我

收到一条错误消息,提示“从“字符串”转换为不相关的类型 NSDictionary 总是失败”。我得到一个线程 1:EXC_BAD_INSTRUCTION