web-dev-qa-db-ja.com

PHP特性のinstanceof

クラスが特定の特性を使用しているかどうかを確認する適切な方法は何ですか?

24
xpedobearx

特性でinstanceofを使用することを妨げるものは何もありませんが、推奨されるアプローチは、特性とインターフェースをペアにすることです。だからあなたは持っているだろう:

class Foo implements MyInterface
{
    use MyTrait;
}

ここで、MyTraitMyInterfaceの実装です。次に、次のような特性の代わりにインターフェースを確認します。

if ($foo instanceof MyInterface) {
    ...
}

また、ヒントを入力することもできますが、これは特性ではできません。

function bar(MyInterface $foo) {
    ...
}

クラスが特定の特性または実装を使用しているかどうかを絶対に知る必要がある場合は、実装に基づいて異なる値を返す別のメソッドをインターフェイスに追加するだけです。

32
Kuba Birecki

class_uses関数を使用して、クラスで使用されるすべての特性の配列を取得できます。

次に、この配列に、テストする特性と同じ名前のキーがあるかどうかを確認します。

もしそうなら、あなたのクラスはあなたの特性を使用しています。そうでない場合、それはそれを使用していません。

27
Rod Elias

それは本当にきれいではありませんし、あなたの場合に適切なソリューションではないかもしれません。しかし、別の方法は、オブジェクトまたはクラスがTraitのメソッドを実装しているかどうかを確認することです(通常、既存のメソッドをTraitで上書きしないため)

if (method_exists($my_object, 'MyTraitSpecificMethod')){
    ...
}
8
thesailorbreton

Laravelがこれを解決する方法を見つけたので、ここで共有すると思いました。class_usesの下にあるが、すべての特性を再帰的に見つけるためにすべての親を通過します。

class_uses_recursive と呼ばれるヘルパー関数を定義します:

function class_uses_recursive($class)
{
    if (is_object($class)) {
        $class = get_class($class);
    }

    $results = [];

    foreach (array_reverse(class_parents($class)) + [$class => $class] as $class) {
        $results += trait_uses_recursive($class);
    }

    return array_unique($results);
}

function trait_uses_recursive($trait)
{
    $traits = class_uses($trait);

    foreach ($traits as $trait) {
        $traits += trait_uses_recursive($trait);
    }

    return $traits;
}

そして、次のように使用できます:

in_array(MyTrait::class, class_uses_recursive($class));

モデルがSoftDeletes特性を実装しているかどうかを確認するためにどのように使用されるかを見ることができます here

public function throughParentSoftDeletes()
{
    return in_array(SoftDeletes::class, class_uses_recursive($this->throughParent));
}
0
solarc