當前位置: 首頁> 最新文章列表> 使用閉包函數結合is_a() 實現靈活判斷器

使用閉包函數結合is_a() 實現靈活判斷器

M66 2025-05-29

在PHP 中, is_a函數用於判斷一個對像是否是某個類或其子類的實例。它非常適合做類型檢測。但如果想寫一個更靈活、可擴展的類型判斷器,可以結合閉包(匿名函數)來實現動態的判斷邏輯,從而避免寫一堆重複的ifswitch語句。

下面我們一步步來看如何用is_a函數結合閉包寫一個靈活的類型判斷器。


1. 簡單的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能判斷對像是否是某個類或其子類的實例,這為我們做類型判斷提供了基礎。


2. 用閉包封裝類型判斷邏輯

我們可以用閉包定義不同的判斷規則,再用一個統一接口調用它們。

 <?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數組中增加一個閉包即可,極大提高了代碼的靈活性。


3. 支持類名參數,動態擴展

有時我們需要根據類名動態創建判斷器,可以寫一個函數幫我們快速生成閉包:

 <?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)
?>

這讓我們的類型判斷器系統更加通用和易於維護。


4. 結合接口和父類多條件判斷

有時我們需要判斷對像是否實現了某個接口或者繼承了某個父類,可以寫一個更通用的判斷器:

 <?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)
?>

這樣,既判斷繼承關係,也判斷接口實現,非常靈活。


5. 綜合示例代碼

<?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
?>

通過這種方式,你可以輕鬆構建一個靈活且易擴展的類型判斷器,適用於各種複雜的業務需求。