インスタンスのクラスがインターフェースを実装しているかどうかを確認していますか?


148

クラスインスタンスが与えられた場合、それが特定のインターフェースを実装しているかどうかを判断することは可能ですか?私の知る限り、これを直接行うための組み込み関数はありません。どのようなオプションがありますか(ある場合)?

回答:


258
interface IInterface
{
}

class TheClass implements IInterface
{
}

$cls = new TheClass();
if ($cls instanceof IInterface) {
    echo "yes";
}

「instanceof」演算子を使用できます。これを使用するには、左側のオペランドがクラスインスタンスで、右側のオペランドがインターフェイスです。オブジェクトが特定のインターフェースを実装している場合はtrueを返します。


102

ここから指摘するように、あなたは使用することができますclass_implements()。Reflectionと同様に、これによりクラス名を文字列として指定でき、クラスのインスタンスを必要としません。

interface IInterface
{
}

class TheClass implements IInterface
{
}

$interfaces = class_implements('TheClass');

if (isset($interfaces['IInterface'])) {
    echo "Yes!";
}

class_implements() SPL拡張機能の一部です。

参照:http : //php.net/manual/en/function.class-implements.php

性能試験

いくつかの簡単なパフォーマンステストは、各アプローチのコストを示しています。

オブジェクトのインスタンスが与えられた

ループ外のオブジェクト構築(100,000反復)
 ____________________________________________
| class_implements | リフレクション| instanceOf |
| ------------------ | ------------ | ------------ |
| 140ミリ秒| 290ミリ秒| 35ミリ秒|
'--------------------------------------------'

ループ内のオブジェクト構築(100,000反復)
 ____________________________________________
| class_implements | リフレクション| instanceOf |
| ------------------ | ------------ | ------------ |
| 182ミリ秒| 340ミリ秒| 83ミリ秒| 安いコンストラクタ
| 431ミリ秒| 607ミリ秒| 338ミリ秒| 高価なコンストラクタ
'--------------------------------------------'

クラス名のみを指定

100,000回の反復
 ____________________________________________
| class_implements | リフレクション| instanceOf |
| ------------------ | ------------ | ------------ |
| 149ミリ秒| 295 ms | なし|
'--------------------------------------------'

高価な__construct()は次のとおりです。

public function __construct() {
    $tmp = array(
        'foo' => 'bar',
        'this' => 'that'
    );  

    $in = in_array('those', $tmp);
}

これらのテストは、この単純なコードに基づいています


56

nlaq instanceofは、オブジェクトがインターフェイスを実装するクラスのインスタンスであるかどうかをテストするために使用できることを指摘しています。

ただしinstanceof、クラスタイプとインターフェイスは区別されません。オブジェクトがたまたま呼び出されるクラスかどうかはわかりませんIInterface

PHPでリフレクションAPIを使用して、これをより具体的にテストすることもできます。

$class = new ReflectionClass('TheClass');
if ($class->implementsInterface('IInterface'))
{
  print "Yep!\n";
}

http://php.net/manual/en/book.reflection.phpを参照してください


2
これは「静的」クラスで使用できます
Znarkus


@therefromhere:ありがとう、良いヒント。これはSPL拡張機能の一部です。私の答えはReflection拡張機能を使用しました。
Bill Karwin

3
名前空間を使用すると、同じ名前のインターフェースとクラスのあいまいさがなくなり、安全にinstanceof再使用できます。
インフルエンザ

+1はclass_implements()、完全なリフレクションを作成する代わりに、class_implementsを呼び出してからin_arrayを呼び出す方が明らかに速いためです
Nickolaus

19

将来の検索を支援するためだけに、is_subclass_ofも適切なバリアントです(PHP 5.3.7以降の場合)。

if (is_subclass_of($my_class_instance, 'ISomeInterfaceName')){
    echo 'I can do it!';
}

5

次のこともできます

public function yourMethod(YourInterface $objectSupposedToBeImplementing) {
   //.....
}

がインターフェイスを$objectSupposedToBeImplementing実装していない場合は、回復可能なエラーがスローされYourInterfaceます。


3

更新

代わりに、is_a 関数がここにありません。

いくつかのパフォーマンステストを行って、記載されている方法のどれが最もパフォーマンスが高いかを確認しました。

10万回を超える結果

      instanceof [object] took   7.67 ms | +  0% | ..........
            is_a [object] took  12.30 ms | + 60% | ................
             is_a [class] took  17.43 ms | +127% | ......................
class_implements [object] took  28.37 ms | +270% | ....................................
       reflection [class] took  34.17 ms | +346% | ............................................

実際に違いを「感じる」ためにいくつかの点を追加しました。

これによって生成:https : //3v4l.org/8Cog7

結論

確認の対象がある場合は、instance of回答に記載されているように使用してください。

チェックするクラスがある場合は、を使用してくださいis_a

ボーナス

必要なインターフェースに基づいてクラスをインスタンス化したい場合は、を使用する方が適していますis_a。唯一の例外があります-コンストラクタが空の場合。

例: is_a(<className>, <interfaceName>, true);

戻りboolます。3番目のパラメーター「allow_string」により、クラスインスタンス化せずにクラス名を確認できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.