Types7 min readExamples run on PHP 8.5.10

is_countable()

Learn how PHP 8.4 is_countable() reports whether a value is an array or a Countable object, with examples, edge cases and common mistakes.

Signature

is_countable(mixed $value): bool
Available since PHP 7.3.07.48.08.18.28.38.48.5All versions →

Purpose

is_countable() answers one question: can this value safely be handed to count()? It returns true for arrays and for objects that implement the Countable interface. Everything else gives false.

The function is useful at boundaries where input is loosely typed. Examples are decoded JSON, results from a library that may return an array, a collection object or null, and helper functions that accept mixed. Because count() throws a TypeError in PHP 8 when given a non-countable value, a quick check lets you branch instead of handling an exception. According to the manual, the function was added in PHP 7.3.0.

Signature

Parameters and defaults

Parameter Type Default Meaning
$value mixed none (required) The value to inspect.

There is only one parameter and it has no default, so you must always pass a value. Any type is accepted, so the function never complains about its argument.

Return value and failure cases

The return type is bool:

  • true when $value is an array, including an empty one, or an object implementing Countable.
  • false for strings, integers, floats, booleans, null, resources, and objects that do not implement Countable.

The function does not raise an error for unsupported types; false is the normal answer. It also does not call count() for you and does not tell you how many elements there are. It only reports whether counting is allowed.

Example 1: scalars, null and arrays

This example runs several kinds of values through the check. An empty array is still countable, because its count is simply zero.

Example
<?php
$values = [
    'array' => [1, 2, 3],
    'empty array' => [],
    'string' => 'abc',
    'int' => 42,
    'null' => null,
];

$result = [];
foreach ($values as $label => $value) {
    $result[$label] = is_countable($value);
}

echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"array":true,"empty array":true,"string":false,"int":false,"null":false}

Note that a string is not countable, even though it has a length. Use strlen() for strings.

Example 2: objects and the Countable interface

For objects, the class decides. Built-in classes such as ArrayIterator implement Countable. A plain stdClass does not. Your own classes qualify once they implement the interface and its count() method. Generators are iterable but not countable.

Example
<?php
final class Basket implements Countable
{
    public function __construct(private array $items) {}

    public function count(): int
    {
        return count($this->items);
    }
}

function numbers()
{
    yield 1;
    yield 2;
}

$checks = [
    'ArrayIterator' => is_countable(new ArrayIterator(['a', 'b'])),
    'stdClass' => is_countable(new stdClass()),
    'Basket' => is_countable(new Basket(['pen', 'book'])),
    'Generator' => is_countable(numbers()),
];

echo json_encode($checks, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"ArrayIterator":true,"stdClass":false,"Basket":true,"Generator":false}

Example 3: a forgiving count helper

A small wrapper can return zero for anything that cannot be counted, which is handy when a value might be null or a string.

Example
<?php
function safeCount(mixed $value): int
{
    return is_countable($value) ? count($value) : 0;
}

echo json_encode([
    safeCount([1, 2, 3]),
    safeCount(new ArrayObject(['x' => 1])),
    safeCount('hello'),
    safeCount(null),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
[3,1,0,0]

Before using such a helper, decide whether silently returning 0 is right for your program. Sometimes a non-countable value signals a bug that should be reported.

Edge cases

  • Empty arrays are countable and count([]) is 0.
  • null is not countable. This matters for values that a function may or may not return.
  • Objects without Countable are not countable, even if they have public properties.
  • Iterables are not always countable. A value can be iterable, such as a generator, and still fail is_countable(). Use is_iterable() to test for iteration instead.
  • Countable does not guarantee a cheap count. The class decides what count() does, so a custom implementation might do real work.

Common mistakes

  1. Confusing countable with iterable. Arrays pass both checks, but generators pass only is_iterable().
  2. Using it as an array check. Because Countable objects also pass, use is_array() when you need a real array.
  3. Assuming a string is countable. Strings need strlen() or mb_strlen(), not count().
  4. Skipping the check before count(). In PHP 8, calling count(null) throws a TypeError.
  5. Expecting a count back. The function returns a boolean only.
  • count() returns the number of elements once you know the value is countable.
  • is_array() checks specifically for arrays.
  • is_object() checks for any object.
  • is_iterable() checks for arrays and Traversable objects.
  • is_bool() checks for booleans.

Recap

is_countable() takes one mixed value and returns true for arrays and Countable objects, false otherwise. Use it to guard calls to count() when a value's type is uncertain. Keep it distinct from is_array() and is_iterable(), because each answers a different question.

Tested examples

Checking scalars, null and arrays
<?php
$values = [
    'array' => [1, 2, 3],
    'empty array' => [],
    'string' => 'abc',
    'int' => 42,
    'null' => null,
];

$result = [];
foreach ($values as $label => $value) {
    $result[$label] = is_countable($value);
}

echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"array":true,"empty array":true,"string":false,"int":false,"null":false}
Objects, Countable and generators
<?php
final class Basket implements Countable
{
    public function __construct(private array $items) {}

    public function count(): int
    {
        return count($this->items);
    }
}

function numbers()
{
    yield 1;
    yield 2;
}

$checks = [
    'ArrayIterator' => is_countable(new ArrayIterator(['a', 'b'])),
    'stdClass' => is_countable(new stdClass()),
    'Basket' => is_countable(new Basket(['pen', 'book'])),
    'Generator' => is_countable(numbers()),
];

echo json_encode($checks, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"ArrayIterator":true,"stdClass":false,"Basket":true,"Generator":false}
A forgiving count helper
<?php
function safeCount(mixed $value): int
{
    return is_countable($value) ? count($value) : 0;
}

echo json_encode([
    safeCount([1, 2, 3]),
    safeCount(new ArrayObject(['x' => 1])),
    safeCount('hello'),
    safeCount(null),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
[3,1,0,0]