is_countable

Checks whether a value can be passed to count() — an array or a Countable object.

Signature
is_countable(mixed $value): bool
  • Added in PHP 7.3.0

Parameters

ParameterTypeDescription
$valuemixedThe value to check.

Return value

booltrue if $value is an array or an object implementing Countable, false otherwise.

Changelog

  • PHP 7.3.0is_countable() was added.

is_countable() tells you whether count() will work on a value. It is exactly equivalent to is_array($v) || $v instanceof Countable, packaged as one call.

It matters because count() stopped being forgiving. In PHP 7.2 counting a non-countable value became a warning, and since PHP 8.0 it throws a TypeError — count('abc') and count(null) are now fatal unless caught. Guarding with is_countable() turns that into a branch you control.

Countable is not the same as iterable

This is the part that surprises people. A Generator, an SplFileObject or any other Traversable that does not implement Countable can be looped over but has no size to report, so is_countable() returns false and count() throws. To size one of those you must consume it with iterator_count() or iterator_to_array() — and for a generator that also exhausts it, so you cannot then iterate it again.

When to reach for it

Use it in library code and in helpers that accept a mixed or union-typed value: a validator checking a minimum item count, a pagination helper, a template function deciding between "no results" and a list. It costs nothing and removes an entire class of PHP 8 fatal errors.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Guarding count() in a helper whose parameter is mixed, so PHP 8 does not throw a TypeError
  • Writing a template helper that shows 'no results' when a value is empty or not countable at all
  • Validating a minimum or maximum number of items when the input may be an array or an ArrayObject

Frequently asked questions

What is the difference between is_countable() and is_array()?

is_array() is true only for real arrays, while is_countable() is also true for objects implementing Countable such as ArrayObject. Use is_countable() when your next call is count().

Why is is_countable() false for a Generator?

Because a generator produces values lazily and has no known size, so it does not implement Countable. Use iterator_count() to count one, keeping in mind that doing so consumes it.

Do I still need is_countable() in PHP 8?

More than ever — counting a non-countable value throws a TypeError in PHP 8, whereas PHP 7.2 to 7.4 only emitted a warning. Guard any count() whose argument is mixed or nullable.

More examples

A count() that cannot fatal

The guarded helper returns 0 for the string and for null, while the unguarded count() throws a TypeError telling you it needs Countable|array. In PHP 7.x that same call was only a warning, which is why old code breaks on upgrade.

Example · php
<?php
function size(mixed $v): int {
    return is_countable($v) ? count($v) : 0;
}

echo size(['a', 'b']), "\n";
echo size(new ArrayObject([1, 2, 3])), "\n";
echo size('abc'), "\n";
echo size(null), "\n";

try {
    count('abc');
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}

Generators are iterable but not countable

The generator is iterable but not countable, so counting it requires iterator_count() — which consumes it. The fourth line needs a fresh generator, because the first one is exhausted; reusing $g would return 0.

Example · php
<?php
function rows(): Generator {
    yield 1;
    yield 2;
    yield 3;
}

$g = rows();

var_dump(is_countable($g));
var_dump(is_iterable($g));
var_dump(iterator_count($g));
var_dump(iterator_count(rows()));

Implementing Countable yourself

Adding the Countable interface and a count() method is all it takes to make an object work with both count() and is_countable(). A plain object without the interface stays false, no matter how many properties it has.

Example · php
<?php
class Basket implements Countable {
    public function __construct(private array $items) {}
    public function count(): int { return count($this->items); }
}

$b = new Basket(['apple', 'pear']);
$plain = new stdClass();

var_dump(is_countable($b), count($b));
var_dump(is_countable($plain));

Discussion

  • Be the first to comment on this lesson.