オブジェクト インターフェイスを使うと、 メソッドの実装を定義せずに、 クラスが実装する必要があるメソッドを指定するコードを作成できます。 インターフェイス は クラス や トレイト と名前空間を共有するので、 それらと同じ名前を使ってはいけません。
インターフェイスは通常のクラスと同様に定義することができますが、
キーワード class
のかわりに interface
を用います。またメソッドの実装は全く定義しません。
インターフェイス内で宣言される全てのメソッドは public である必要があります。 これは、インターフェイスの特性によります。
インターフェイスには、ふたつの互いを補完する役割があります。
Iterable
や
Cacheable
、
Renderable
のような名前が付けられることがよくあります。
インターフェイスは、 マジックメソッド を宣言しても問題ありません。
注意:
コンストラクタ をインターフェイスで宣言できますが、全くおすすめできません。 そうしてしまうと、 インターフェイスを実装するクラスの柔軟性が大きく損なわれる上、 コンストラクタには継承ルールが適用されないため、 一貫しない、予期せぬ結果を生む可能性があるからです。
implements
インターフェイスを実装するには、implements
演算子を使用し、
このインターフェイスに含まれる全てのメソッドを実装する必要があります。
実装されていない場合、致命的エラーとなります。
各インターフェイスをカンマで区切って指定することで、
クラスは複数のインターフェイスを実装することができます。
クラスは、同じ名前のメソッドを定義した2つのインターフェイスを実装することが出来ます。 但し、両方のインターフェイスのメソッド宣言が同一な場合に限ります。
インターフェイスを実装するクラスでは、 インターフェイス内の名前とは異なる名前を メソッドの引数に使うことができます。 しかし、PHP 8.0 以降では 名前付き引数 がサポートされています。 これは、メソッドをコールする側がインターフェイス内の名前に依存する可能性があるということです。 そうした理由から、開発者は実装されるインターフェイスと同じ引数名を使うことを強く推奨します。
注意:
クラスと同様、インターフェイスも extends 演算子で継承することができます。
注意:
インターフェイスを実装したクラスでは、 シグネチャの互換性に関するルール を守った形で、 インターフェイス内の全てのメソッドを宣言しなければいけません。
定数
インターフェイスに定数を持たせることもできます。 インターフェイス定数は クラス定数 とまったく同じように動作します。 PHP 8.1.0 より前のバージョンでは、 そのインターフェイスを継承したクラスやインターフェイスから定数をオーバーライドすることができませんでした。
例1 Interface の例
<?php
// インターフェイス 'iTemplate' を宣言する
interface Template
{
public function setVariable($name, $var);
public function getHtml($template);
}
// インターフェイスを実装する。
// これは動作します。
class WorkingTemplate implements Template
{
private $vars = [];
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
public function getHtml($template)
{
foreach($this->vars as $name => $value) {
$template = str_replace('{' . $name . '}', $value, $template);
}
return $template;
}
}
// これは動作しません。
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (Template::getHtml)
class BadTemplate implements Template
{
private $vars = [];
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
}
?>
例2 インターフェイスの継承
<?php
interface A
{
public function foo();
}
interface B extends A
{
public function baz(Baz $baz);
}
// これは動作します。
class C implements B
{
public function foo()
{
}
public function baz(Baz $baz)
{
}
}
// これは動作せず、fatal error となります。
class D implements B
{
public function foo()
{
}
public function baz(Foo $foo)
{
}
}
?>
例3 複数のインターフェイスの継承
<?php
interface A
{
public function foo();
}
interface B
{
public function bar();
}
interface C extends A, B
{
public function baz();
}
class D implements C
{
public function foo()
{
}
public function bar()
{
}
public function baz()
{
}
}
?>
例4 インターフェイスでの定数
<?php
interface A
{
const B = 'Interface constant';
}
// Interface constant と表示します。
echo A::B;
class B implements A
{
const B = 'Class constant';
}
// Class constant と表示します。
// PHP 8.1.0 より前のバージョンでは、定数をオーバライドできなかったため、これは動作しませんでした。
echo B::B;
?>
例5 抽象クラスとインターフェイス
<?php
interface A
{
public function foo(string $s): string;
public function bar(int $i): int;
}
// 抽象クラスは、インターフェイスの一部のみを実装しても構いません。
// 抽象クラスを継承したクラスは、未実装の残りのメソッドを実装しなければなりません。
abstract class B implements A
{
public function foo(string $s): string
{
return $s . PHP_EOL;
}
}
class C extends B
{
public function bar(int $i): int
{
return $i * 2;
}
}
?>
例6 継承と実装を同時に行う
<?php
class One
{
/* ... */
}
interface Usable
{
/* ... */
}
interface Updatable
{
/* ... */
}
// ここでは、キーワードの順番が重要です。
// 'extends' を始めに置かなければいけません。
class Two extends One implements Usable, Updatable
{
/* ... */
}
?>
インターフェイスと型宣言を組み合わせると、 特定のオブジェクトに特定のメソッドをうまく持たせることができます。 instanceof 演算子および 型宣言 を参照ください。