Current Location: Home> Latest Articles> Use closure functions combined with is_a() to achieve flexible judges

Use closure functions combined with is_a() to achieve flexible judges

M66 2025-05-29

In PHP, the is_a function is used to determine whether an object is an instance of a class or its subclass. It is very suitable for type detection. But if you want to write a more flexible and extensible type judge, you can combine closures (anonymous functions) to implement dynamic judgment logic, thereby avoiding writing a bunch of duplicate if or switch statements.

Let's take a step-by-step look at how to write a flexible type judge using the is_a function combined with the closure.


1. A simple is_a usage review

 <?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 can determine whether an object is an instance of a certain class or its subclass, which provides the basis for us to judge type.


2. Use closure encapsulation type to judge logic

We can use closures to define different judgment rules and then call them with a unified interface.

 <?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);
    }
];

// Example of usage
function checkType($obj, $type, $checkers) {
    if (!isset($checkers[$type])) {
        throw new InvalidArgumentException("Unknown type: $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)
?>

In this way, adding new type judgment only requires adding a closure to the $typeCheckers array, greatly improving the flexibility of the code.


3. Support class name parameters and dynamic expansion

Sometimes we need to dynamically create a judge based on the class name, and we can write a function to help us quickly generate closures:

 <?php
function makeIsATypeChecker(string $className) {
    return function($obj) use ($className) {
        return is_a($obj, $className);
    };
}

$typeCheckers['cat'] = makeIsATypeChecker('Cat');

// test
class Cat extends Animal {}
$cat = new Cat();
var_dump(checkType($cat, 'cat', $typeCheckers)); // bool(true)
?>

This makes our type judge system more versatile and easy to maintain.


4. Combining interface and parent class multi-condition judgment

Sometimes we need to determine whether the object implements a certain interface or inherits a certain parent class, and we can write a more general judge:

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

In this way, it is very flexible to judge both the inheritance relationship and the interface implementation.


5. Comprehensive sample code

 <?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("Unknown type: $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); },
];

// test
$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
?>

In this way, you can easily build a flexible and scalable type judge for a variety of complex business needs.