Skip to content

Instantly share code, notes, and snippets.

@Pierstoval
Last active July 20, 2025 16:35
Show Gist options
  • Save Pierstoval/ed387a09d4a5e76108e60e8a7585ac2d to your computer and use it in GitHub Desktop.
Save Pierstoval/ed387a09d4a5e76108e60e8a7585ac2d to your computer and use it in GitHub Desktop.
`is_a()` vs `is_subclass_of()`

PHP is_a() vs is_subclass_of()

<?php

class A {}

class B extends A {}

interface I {}

trait T {}

class C extends B implements I {
    use T;
}
Operation is_a() is_subclass_of() instanceof
A of A
A of B
A of I
A of T
A of C
B of A
B of B
B of I
B of T
B of C
I of A
I of B
I of I
I of T
I of C
T of A
T of B
T of I
T of T
T of C
C of A
C of B
C of I
C of T
C of C
{
"require": {
"symfony/console": "^7.3"
}
}
<?php
<<<CONFIG
packages:
- "symfony/console: ^4.1"
CONFIG;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableStyle;
use Symfony\Component\Console\Output\ConsoleOutput;
require __DIR__.'/vendor/autoload.php';
class A
{
}
class B extends A
{
}
interface I
{
}
trait T {
}
class C extends B implements I {
use T;
}
$classes = [
'A',
'B',
'I',
'T',
'C',
];
$rows = [];
foreach ($classes as $class1) {
foreach ($classes as $class2) {
$rows[] = [
$class1.' of '.$class2,
is_a($class1, $class2, true) ? '<fg=green>true</>' : '<fg=red>false</>',
is_subclass_of($class1, $class2, true) ? '<fg=green>true</>' : '<fg=red>false</>',
class_exists($class1) && (new $class1()) instanceof $class2 ? '<fg=green>true</>' : '<fg=red>false</>',
];
}
}
$table = new Table(new ConsoleOutput());
$table->setHeaders(['Operation', 'is_a()', 'is_subclass_of()', 'instanceof']);
$table->setRows($rows);
$table->render();
@gggeek
Copy link

gggeek commented Feb 3, 2023

Small change, adding instanceof to the mix

foreach ($classes as $class1) {
    if ($class1 == 'It' || $class1 == 'T') {
        continue;
    }
    $obj1 = new $class1();
    foreach ($classes as $class2) {
        $rows[] = [
            $class1.' of '.$class2,
            is_a($obj1, $class2, true) ? '<fg=green>true</>' : '<fg=red>false</>',
            is_subclass_of($obj1, $class2, true) ? '<fg=green>true</>' : '<fg=red>false</>',
            $obj1 instanceof $class2 ? '<fg=green>true</>' : '<fg=red>false</>',
        ];
    }
}

In case anyone is wondering about the result: instanceof gives the same results as is_a. It is marginally faster, but it is also more limited in scope (it only accepts an instance as first argument and not a string, and does not accept a variable value as 2nd argument)

@serious-angel
Copy link

serious-angel commented Jul 16, 2025

Small change, adding instanceof to the mix...
~ @gggeek

Let's add the check but also leave the initials.

#! /usr/bin/env php
<?php

<<<CONFIG
packages:
    - "symfony/console: ^4.1"
CONFIG;

use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableStyle;
use Symfony\Component\Console\Output\ConsoleOutput;

require __DIR__.'/vendor/autoload.php';

class A
{
}

class B extends A
{
}

interface It
{
}

trait T {
}

class C extends B implements It {
    use T;
}

$classes = [
    'A',
    'B',
    'It',
    'T',
    'C',
];

$rows = [];

foreach ($classes as $class1) {
    foreach ($classes as $class2) {
        $instanceOf = '';

        if (class_exists($class1)) {
            $instanceOf = (new $class1()) instanceof $class2 ? '<fg=green>true</>' : '<fg=red>false</>';
        }

        $rows[] = [
            $class1.' of '.$class2,
            is_a($class1, $class2, true) ? '<fg=green>true</>' : '<fg=red>false</>',
            is_subclass_of($class1, $class2, true) ? '<fg=green>true</>' : '<fg=red>false</>',
            $instanceOf,
        ];
    }
}

$table = new Table(new ConsoleOutput());

$table->setHeaders(['Operation', 'is_a()', 'is_subclass_of()', 'instanceof']);
$table->setRows($rows);

$table->render();
+-----------+--------+------------------+------------+
| Operation | is_a() | is_subclass_of() | instanceof |
+-----------+--------+------------------+------------+
| A of A    | true   | false            | true       |
| A of B    | false  | false            | false      |
| A of It   | false  | false            | false      |
| A of T    | false  | false            | false      |
| A of C    | false  | false            | false      |
| B of A    | true   | true             | true       |
| B of B    | true   | false            | true       |
| B of It   | false  | false            | false      |
| B of T    | false  | false            | false      |
| B of C    | false  | false            | false      |
| It of A   | false  | false            |            |
| It of B   | false  | false            |            |
| It of It  | true   | false            |            |
| It of T   | false  | false            |            |
| It of C   | false  | false            |            |
| T of A    | false  | false            |            |
| T of B    | false  | false            |            |
| T of It   | false  | false            |            |
| T of T    | true   | false            |            |
| T of C    | false  | false            |            |
| C of A    | true   | true             | true       |
| C of B    | true   | true             | true       |
| C of It   | true   | true             | true       |
| C of T    | false  | false            | false      |
| C of C    | true   | false            | true       |
+-----------+--------+------------------+------------+

@Pierstoval
Copy link
Author

@serious-angel Done!

I even updated the display a bit :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment