在PHP 中, is_a函數用於判斷一個對像是否是某個類或其子類的實例。它非常適合做類型檢測。但如果想寫一個更靈活、可擴展的類型判斷器,可以結合閉包(匿名函數)來實現動態的判斷邏輯,從而避免寫一堆重複的if或switch語句。
下面我們一步步來看如何用is_a函數結合閉包寫一個靈活的類型判斷器。
<?php
class Animal {}
class Dog extends Animal {}
$dog = new Dog();
var_dump(is_a($dog, 'Dog')); // bool(true)
var_dump(is_a($dog, 'Animal')); // bool(true)
var_dump(is_a($dog, 'Cat')); // bool(false)
?>
is_a能判斷對像是否是某個類或其子類的實例,這為我們做類型判斷提供了基礎。
我們可以用閉包定義不同的判斷規則,再用一個統一接口調用它們。
<?php
$typeCheckers = [
'dog' => function($obj) {
return is_a($obj, 'Dog');
},
'animal' => function($obj) {
return is_a($obj, 'Animal');
},
'string' => function($obj) {
return is_string($obj);
}
];
// 使用示例
function checkType($obj, $type, $checkers) {
if (!isset($checkers[$type])) {
throw new InvalidArgumentException("未知類型: $type");
}
return $checkers[$type]($obj);
}
$dog = new Dog();
var_dump(checkType($dog, 'dog', $typeCheckers)); // bool(true)
var_dump(checkType($dog, 'animal', $typeCheckers)); // bool(true)
var_dump(checkType("hello", 'string', $typeCheckers));// bool(true)
?>
這樣一來,新增類型判斷只需在$typeCheckers數組中增加一個閉包即可,極大提高了代碼的靈活性。
有時我們需要根據類名動態創建判斷器,可以寫一個函數幫我們快速生成閉包:
<?php
function makeIsATypeChecker(string $className) {
return function($obj) use ($className) {
return is_a($obj, $className);
};
}
$typeCheckers['cat'] = makeIsATypeChecker('Cat');
// 測試
class Cat extends Animal {}
$cat = new Cat();
var_dump(checkType($cat, 'cat', $typeCheckers)); // bool(true)
?>
這讓我們的類型判斷器系統更加通用和易於維護。
有時我們需要判斷對像是否實現了某個接口或者繼承了某個父類,可以寫一個更通用的判斷器:
<?php
function makeClassOrInterfaceChecker(string $name) {
return function($obj) use ($name) {
return is_a($obj, $name) || in_array($name, class_implements($obj));
};
}
interface Pet {}
class Dog extends Animal implements Pet {}
$typeCheckers['pet'] = makeClassOrInterfaceChecker('Pet');
$dog = new Dog();
var_dump(checkType($dog, 'pet', $typeCheckers)); // bool(true)
?>
這樣,既判斷繼承關係,也判斷接口實現,非常靈活。
<?php
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
interface Pet {}
class DogPet extends Dog implements Pet {}
function checkType($obj, $type, $checkers) {
if (!isset($checkers[$type])) {
throw new InvalidArgumentException("未知類型: $type");
}
return $checkers[$type]($obj);
}
function makeIsATypeChecker(string $className) {
return function($obj) use ($className) {
return is_a($obj, $className);
};
}
function makeClassOrInterfaceChecker(string $name) {
return function($obj) use ($name) {
return is_a($obj, $name) || in_array($name, class_implements($obj));
};
}
$typeCheckers = [
'dog' => makeIsATypeChecker('Dog'),
'animal' => makeIsATypeChecker('Animal'),
'pet' => makeClassOrInterfaceChecker('Pet'),
'string' => function($obj) { return is_string($obj); },
];
// 測試
$dog = new Dog();
$cat = new Cat();
$dogPet = new DogPet();
var_dump(checkType($dog, 'dog', $typeCheckers)); // true
var_dump(checkType($cat, 'animal', $typeCheckers)); // true
var_dump(checkType($dogPet, 'pet', $typeCheckers)); // true
var_dump(checkType("hello", 'string', $typeCheckers));// true
?>
通過這種方式,你可以輕鬆構建一個靈活且易擴展的類型判斷器,適用於各種複雜的業務需求。