Gor*_*don 15
除了访问接口中的任何已定义常量或将其用于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
Run Code Online (Sandbox Code Playgroud)
见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 */ }
}
Run Code Online (Sandbox Code Playgroud)
两个类都实现Logger,因此必须有一个方法log($msg).你基本上是在说:"嘿,如果你想成为Logger,请确保我可以在你身上调用log()." .现在代码中的某个地方你可能有一个需要记录器的类,比如
class Foo
{
protected $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger;
$this->logger->log('I can haz logger! Yay!');
}
}
Run Code Online (Sandbox Code Playgroud)
Foo不关心它是否得到FileLog,DbLog或任何其他具体的记录器.它只关心它可以调用任何 Logger log().Foo甚至对什么都不感兴趣log().所有Foo关心的事情都可以打电话log().你不是log()在界面中打电话.您在传递给的conrete类中调用它Foo,但在UML图中,您表示它就像它在您链接的页面中显示的那样,因为您只是编码了一个接口.
这样做的主要优点是你的课程耦合得更少.您可以更轻松地交换依赖关系,例如在单元测试中使用Mocks时,您的代码将更易于维护.
基本上,将接口视为概念标准化.例如,当你购买一台新的DVD播放器时,你希望它有一个►按钮,不知何故(你不关心如何,只是这样)让播放器播放DVD.当你按下那个按钮时,你没有按下DVD播放器必须有一个播放按钮的一般抽象DVD接口规范,但你点击了这个品牌播放器上播放按钮的具体实现.