接口
介绍
接口是公共 API 类必须实现的定义,以满足接口。他们的工作是合同,指定什么一组子类的做法,但并不怎么他们这样做。
接口定义与类定义非常相似,将关键字 class
更改为 interface
:
interface Foo {
}
接口可以包含方法和/或常量,但不包含任何属性。接口常量与类常量具有相同的限制。接口方法是隐式抽象的:
interface Foo {
const BAR = 'BAR';
public function doSomething($param1, $param2);
}
注意: 接口不能声明构造函数或析构函数,因为这些是类级别的实现细节。
实现
任何需要实现接口的类都必须使用 implements
关键字。为此,该类需要为接口中声明的每个方法提供一个实现,并遵循相同的签名。
单个类可以一次实现多个接口。
interface Foo {
public function doSomething($param1, $param2);
}
interface Bar {
public function doAnotherThing($param1);
}
class Baz implements Foo, Bar {
public function doSomething($param1, $param2) {
// ...
}
public function doAnotherThing($param1) {
// ...
}
}
当抽象类实现接口时,它们不需要实现所有方法。然后,必须通过扩展它的具体类来实现在基类中未实现的任何方法:
abstract class AbstractBaz implements Foo, Bar {
// Partial implementation of the required interface...
public function doSomething($param1, $param2) {
// ...
}
}
class Baz extends AbstractBaz {
public function doAnotherThing($param1) {
// ...
}
}
请注意,接口实现是一种继承的特性。在扩展实现接口的类时,你不需要在具体类中重新声明它,因为它是隐式的。
注意: 在 PHP 5.3.9 之前,类无法实现两个指定具有相同名称的方法的接口,因为它会导致歧义。只要重复的方法具有相同的签名 [1], 更新版本的 PHP 就允许这样做。
继承
与类一样,可以使用相同的关键字 extends
在接口之间建立继承关系。主要区别在于接口允许多重继承:
interface Foo {
}
interface Bar {
}
interface Baz extends Foo, Bar {
}
例子
在下面的示例中,我们有一个简单的车辆界面示例。车辆可以前进和后退。
interface VehicleInterface {
public function forward();
public function reverse();
...
}
class Bike implements VehicleInterface {
public function forward() {
$this->pedal();
}
public function reverse() {
$this->backwardSteps();
}
protected function pedal() {
...
}
protected function backwardSteps() {
...
}
...
}
class Car implements VehicleInterface {
protected $gear = 'N';
public function forward() {
$this->setGear(1);
$this->pushPedal();
}
public function reverse() {
$this->setGear('R');
$this->pushPedal();
}
protected function setGear($gear) {
$this->gear = $gear;
}
protected function pushPedal() {
...
}
...
}
然后我们创建两个实现接口的类:Bike 和 Car。Bike 和 Car 内部非常不同,但两者都是车辆,必须实现 VehicleInterface 提供的相同公共方法。
Typehinting allows methods and functions to request Interfaces. Let’s assume that we have a parking garage class, which contains vehicles of all kinds.
class ParkingGarage {
protected $vehicles = [];
public function addVehicle(VehicleInterface $vehicle) {
$this->vehicles[] = $vehicle;
}
}
Because addVehicle
requires a $vehicle
of type VehicleInterface
—not a concrete implementation—we can input both Bikes and Cars, which the ParkingGarage can manipulate and use.