接口

介绍

接口是公共 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.