PHP 8.1.0 RC 2 available for testing

オブジェクト インターフェイス

オブジェクト インターフェイスを使うと、 メソッドの実装を定義せずに、 クラスが実装する必要があるメソッドを指定するコードを作成できます。 インターフェイス は クラス や トレイト と名前空間を共有するので、 それらと同じ名前を使ってはいけません。

インターフェイスは通常のクラスと同様に定義することができますが、 キーワード class のかわりに interface を用います。またメソッドの実装は全く定義しません。

インターフェイス内で宣言される全てのメソッドは public である必要があります。 これは、インターフェイスの特性によります。

インターフェイスには、ふたつの互いを補完する役割があります。

  • 同じインターフェイスを実装していることで、 開発者が交換可能な異なるクラスを作成できるようにします。 同じインターフェイスを持つクラスによくある例として、 複数のデータベースにアクセスするサービスや 決済のゲートウェイ、 異なるキャッシュ戦略が挙げられます。 実装が異なっていても、 それを使うコードに変更を加えることなく、それらを交換することができます。
  • メソッドや関数が、インターフェイスを満たす引数を受け付け、 操作できるようにします。 オブジェクトが何をするのかや、 どう実装されているのかを気にする必要はありません。 振る舞いの重要性を説明するために、 IterableCacheableRenderable のような名前が付けられることがよくあります。

インターフェイスは、 マジックメソッド を宣言しても問題ありません。

注意:

コンストラクタ をインターフェイスで宣言できますが、全くおすすめできません。 そうしてしまうと、 インターフェイスを実装するクラスの柔軟性が大きく損なわれる上、 コンストラクタには継承ルールが適用されないため、 一貫しない、予期せぬ結果を生む可能性があるからです。

implements

インターフェイスを実装するには、implements 演算子を使用し、 このインターフェイスに含まれる全てのメソッドを実装する必要があります。 実装されていない場合、致命的エラーとなります。 各インターフェイスをカンマで区切って指定することで、 クラスは複数のインターフェイスを実装することができます。

警告

クラスは、同じ名前のメソッドを定義した2つのインターフェイスを実装することが出来ます。 但し、両方のインターフェイスのメソッド宣言が同一な場合に限ります。

警告

インターフェイスを実装するクラスでは、 インターフェイス内の名前とは異なる名前を メソッドの引数に使うことができます。 しかし、PHP 8.0 以降では 名前付き引数 がサポートされています。 これは、メソッドをコールする側がインターフェイス内の名前に依存する可能性があるということです。 そうした理由から、開発者は実装されるインターフェイスと同じ引数名を使うことを強く推奨します。

注意:

クラスと同様、インターフェイスも extends 演算子で継承することができます。

注意:

インターフェイスを実装したクラスでは、 シグネチャの互換性に関するルール を守った形で、 インターフェイス内の全てのメソッドを宣言しなければいけません。

定数

インターフェイスに定数を持たせることもできます。 インターフェイス定数は クラス定数 とまったく同じように動作します。しかし、 そのインターフェイスを継承したクラスやインターフェイスから上書きすることはできません。

例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 
extends A
{
    public function 
baz(Baz $baz);
}

// これは動作します。
class implements B
{
    public function 
foo()
    {
    }

    public function 
baz(Baz $baz)
    {
    }
}

// これは動作せず、fatal error となります。
class implements B
{
    public function 
foo()
    {
    }

    public function 
baz(Foo $foo)
    {
    }
}
?>

例3 複数のインターフェイスの継承

<?php
interface A
{
    public function 
foo();
}

interface 
B
{
    public function 
bar();
}

interface 
extends AB
{
    public function 
baz();
}

class 
implements C
{
    public function 
foo()
    {
    }

    public function 
bar()
    {
    }

    public function 
baz()
    {
    }
}
?>

例4 インターフェイスでの定数

<?php
interface A
{
    const 
'Interface constant';
}

// Interface constant と表示します。
echo A::B;


// これは動作しません。定数をオーバーライドできないからです。
class implements A
{
    const 
'Class constant';
}
?>

例5 抽象クラスとインターフェイス

<?php
interface A
{
    public function 
foo(string $s): string;

    public function 
bar(int $i): int;
}

// 抽象クラスは、インターフェイスの一部のみを実装しても構いません。
// 抽象クラスを継承したクラスは、未実装の残りのメソッドを実装しなければなりません。
abstract class implements A
{
    public function 
foo(string $s): string
    
{
        return 
$s PHP_EOL;
    }
}

class 
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 UsableUpdatable
{
    
/* ... */
}
?>

インターフェイスと型宣言を組み合わせると、 特定のオブジェクトに特定のメソッドをうまく持たせることができます。 instanceof 演算子および 型宣言 を参照ください。

add a note add a note

User Contributed Notes 3 notes

up
18
thanhn2001 at gmail dot com
10 years ago
PHP prevents interface a contant to be overridden by a class/interface that DIRECTLY inherits it.  However, further inheritance allows it.  That means that interface constants are not final as mentioned in a previous comment.  Is this a bug or a feature?

<?php

interface a
{
    const
b = 'Interface constant';
}

// Prints: Interface constant
echo a::b;

class
b implements a
{
}

// This works!!!
class c extends b
{
    const
b = 'Class constant';
}

echo
c::b;
?>
up
1
williebegoode at att dot net
7 years ago
In their book on Design Patterns, Erich Gamma and his associates (AKA: "The Gang of Four") use the term "interface" and "abstract class" interchangeably. In working with PHP and design patterns, the interface, while clearly a "contract" of what to include in an implementation is also a helpful guide for both re-use and making changes. As long as the implemented changes follow the interface (whether it is an interface or abstract class with abstract methods), large complex programs can be safely updated without having to re-code an entire program or module.

In PHP coding with object interfaces (as a keyword) and "interfaces" in the more general context of use that includes both object interfaces and abstract classes, the purpose of "loose binding" (loosely bound objects) for ease of change and re-use is a helpful way to think about both uses of the  term "interface." The focus shifts from "contractual" to "loose binding" for the purpose of cooperative development and re-use.
up
-1
xedin dot unknown at gmail dot com
6 months ago
This page says that if extending multiple interfaces with the same methods, the signature must be compatible. But this is not all there is to it: the order of `extends` matters. This is a known issue, and while it is disputable whether or not it is a bug, one should be aware of it, and code interfaces with this in mind.

https://bugs.php.net/bug.php?id=67270
https://bugs.php.net/bug.php?id=76361
https://bugs.php.net/bug.php?id=80785
To Top