PHPでは、 IS_A()関数は、オブジェクトが特定のクラスに属するか、インターフェイスを実装するかを判断するためによく使用されますが、オブジェクトが特定の特性を使用するかどうかを判断するために使用すると、結果が期待を満たしていないことがよくあります。この記事では、この問題の根本原因を掘り下げ、いくつかの可能な解決策を提供します。
IS_A()関数は、オブジェクトが指定されたクラスのインスタンスであるかどうか、またはクラスのサブクラスであるかどうかを確認するために使用されます。典型的な使用法は次のとおりです。
if (is_a($obj, 'SomeClass')) {
// $obj はい SomeClass またはそのサブクラスのインスタンス
}
IS_A()関数の基礎となる層は、実際にはオブジェクトのクラス継承チェーンとインターフェイスの実装を判断することです。
特性は、PHP 5.4で導入されたコード再利用メカニズムであり、複数のクラスでコードブロックを「コピー」することができます。特性は、自然のクラスやインターフェースではありません。個別にインスタンス化することはできず、継承チェーンには表示されません。
簡単な例を見てみましょう:
trait Logger {
public function log($msg) {
echo $msg;
}
}
class User {
use Logger;
}
ユーザークラスはロガーの特性を使用していますが、ロガーはクラスではないため、オブジェクトの継承構造には表示されません。
IS_A()はオブジェクトを決定するクラスまたはインターフェイスの関係であり、特性はクラスまたはインターフェイスではないため、 IS_A($ obj、 'logger')はfalseを返します。
$user = new User();
var_dump(is_a($user, 'Logger')); // false
これは、ロガーが$ユーザーオブジェクトのクラスやインターフェイスではなく、継承チェーンにもないためです。
IS_A()で特性を判断することは不可能であるため、一般的な代替手段は、Class_USES()関数と組み合わせてPHPの反射メカニズムを使用することです。
class_uses()クラスで使用されるすべての特性(継承された特性を含む)の配列を返します。
if (in_array('Logger', class_uses($user))) {
echo "User 使用済み Logger trait";
}
ただし、 class_uses()は、デフォルトで現在のクラスで使用されている特性を直接返すだけであり、親クラスで使用される特性は含まれていないことに注意してください。すべての親クラスで使用される特性を取得する必要がある場合は、カスタム関数を使用して再帰的に取得できます。
function class_uses_recursive($class) {
$traits = [];
do {
$traits = array_merge($traits, class_uses($class));
} while ($class = get_parent_class($class));
return array_unique($traits);
}
if (in_array('Logger', class_uses_recursive($user))) {
echo "User 使用済み Logger trait(親クラスを含む)";
}
<?php
trait Logger {
public function log($msg) {
echo $msg;
}
}
class Base {
use Logger;
}
class User extends Base {}
$user = new User();
// 使用 is_a 判断 trait 結果は次のとおりです false
var_dump(is_a($user, 'Logger')); // bool(false)
// 使用 class_uses_recursive 判断 trait
function class_uses_recursive($class) {
$traits = [];
do {
$traits = array_merge($traits, class_uses($class));
} while ($class = get_parent_class($class));
return array_unique($traits);
}
if (in_array('Logger', class_uses_recursive($user))) {
echo "User 使用済み Logger trait";
} else {
echo "User 使用されていません Logger trait";
}
IS_A()は、特性がクラスやインターフェイスではないため、特性を判断するために使用できません。
特性を使用するかどうかを判断するには、 class_uses()関数を使用できます。
親クラスが使用する特性を確認する必要がある場合は、すべての親クラスの特性を再帰的に取得する必要があります。
この方法はシンプルで効率的で、毎日の使用に適しています。
特性とPHPタイプシステムの性質を理解することにより、オブジェクトと特性の関係を判断する方法を合理的に選択し、 IS_A()の誤用によって引き起こされる論理エラーを回避できます。