除了访问其中定义的任何常量或将其用于 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
See http://php.net/manual/en/language.oop5.interfaces.php
一般是什么意思针对接口进行编码 or 与界面交互基本上无非就是调用方法定义于实现它们的类中的接口。您调用的是实现,而不是定义。该定义只是指定对于每个实现该接口的类,必须有一个带有指定参数的特定方法。
考虑这些类:
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
因此必须有一个方法log($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
或任何其他混凝土记录仪。它只关心它得到any它可以调用记录器log()
在。 Foo 甚至对什么都不感兴趣log()
做。全部Foo
关心的是能否打电话log()
。你没有打电话log()
但在界面中。您在传递给的具体类中调用它Foo
,但在 UML 图中,您将像链接的页面中所示那样表示它,因为您只是针对接口进行编码.
这样做的主要优点是您的类的耦合度要低得多。您可以更轻松地交换依赖项,例如在单元测试中使用 Mocks 时,您的代码将更易于维护。
Basically, think of an interface as a conceptual standardization. For instance, when you buy a new DVD Player, you expect it to have a ► button that somehow (you don't care how, just that) makes the player play the DVD. When you press that button, you're not pressing the general abstract DVD interface specification that says a DVD player must have a play button, but you clicked the concrete implementation of a play button on this brand of player.