除了访问接口中的任何已定义常量或将其用于TypeHints之外,您无法与接口进行交互.接口没有方法体.它们仅用于定义实现类必须遵守的合同.
interface Logger { const FOO = 1; public function log($msg); } echo Logger::FOO; // 1 Logger::log($msg); // Fatal error: Cannot call abstract method Logger::log() new Logger; // Fatal error: Cannot instantiate interface Logger
见http://php.net/manual/en/language.oop5.interfaces.php
当对接口进行编码或与接口交互时通常意味着什么只是调用实现它们的类中的接口中定义的方法.您调用实现,而不是定义.该定义仅指定对于实现接口的每个Class,必须有一个具有指定参数的特定方法.
考虑这些类:
Class DbLog implements Logger { public function log($msg) { /* log $msg to database */ } } Class FileLog implements Logger { public function log($msg) { /* log $msg to file */ } }
这两个类都实现了Logger,因此必须有一个方法日志($msg).你基本上是在说:“嘿,如果你想成为Logger,请确保我可以在你身上调用log().”现在代码中的某个地方你可能有一个需要记录器的类,比如
class Foo { protected $logger; public function __construct(Logger $logger) { $this->logger = $logger; $this->logger->log('I can haz logger! Yay!'); } }
Foo不关心它是否获得FileLog,DbLog或任何其他具体的记录器.它只关心它得到任何可以调用log()的Logger. Foo甚至对log()没有兴趣.所有Foo关心的是能够调用log().你不是在界面中调用log().您在传递给Foo的conrete类中调用它,但是在UML图中,您表示它就像它在您链接的页面中显示的那样,因为您只是编码了一个接口.
这样做的主要优点是你的课程耦合得更少.您可以更轻松地交换依赖关系,例如在单元测试中使用Mocks时,您的代码将更易于维护.
基本上,将接口视为概念标准化.例如,当你购买一台新的DVD播放器时,你希望它有一个►按钮,以某种方式(你不关心如何,只是这样)使播放器播放DVD.当你按下那个按钮时,你没有按下DVD播放器必须有一个播放按钮的一般抽象DVD接口规范,但你点击了这个品牌播放器上播放按钮的具体实现.