phalcon/cphalcon · error · InvalidArgumentException

The sort callback must be callable or null

Error message

The sort callback must be callable or null

What it means

Support\Collection::sort(var callback = null, int order = 4) accepts null (built-in asort/arsort by order) or a callable passed to uasort. A non-null value that fails is_callable() throws InvalidArgumentException('The sort callback must be callable or null') before any sorting happens.

Source

Thrown at phalcon/Support/Collection.zep:551

    /**
     * Returns a new collection sorted by value. Keys are preserved. When a
     * callback is supplied, `uasort` is used. Without a callback, the
     * comparison direction is controlled by the `$order` argument
     * (`SORT_ASC` or `SORT_DESC`).
     *
     * @phpstan-return static<T>
     *
     * @param callable|null $callback
     */
    public function sort(var callback = null, int order = 4) -> <static>
    {
        var result;

        let result = this->data;

        if (null !== callback) {
            if unlikely true !== is_callable(callback) {
                throw new InvalidArgumentException(
                    "The sort callback must be callable or null"
                );
            }

            uasort(result, callback);
        } elseif (order === SORT_DESC) {
            arsort(result);
        } else {
            asort(result);
        }

        return this->cloneEmpty(result);
    }

    /**
     * Returns the object in an array format
     *
     * @phpstan-return array<array-key, T>

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Use a closure or canonical array syntax: $collection->sort(fn($a, $b) => $a <=> $b) or $collection->sort([$this, 'compareByName'])
  2. Validate dynamic callbacks before use: if ($cb !== null && !is_callable($cb)) { throw new InvalidArgumentException(...); }
  3. After renames, grep for string callback references; ensure the method is accessible (public)

Example fix

// before
$collection->sort([$this, 'compareByName']); // method renamed -> not callable

// after
$collection->sort(fn(array $a, array $b): int => $a['name'] <=> $b['name']);
Defensive patterns

Strategy: type-guard

Validate before calling

if ($callback !== null && !is_callable($callback)) {
    throw new InvalidArgumentException('Provided sort callback is not callable');
}
$sorted = $collection->sort($callback);

Type guard

function isSortCallback(mixed $callback): bool
{
    return $callback === null || is_callable($callback);
}

Prevention

When it happens

Trigger: A string function name that does not exist (typo like 'strcomp'); wrong method-reference syntax such as $this->compare instead of [$this, 'compare']; 'self::compare' as a plain string where the class is namespaced without a leading backslash; a callback name from config/request input that was never defined; the comparison method was renamed or made private during refactor.

Common situations: Dynamic comparator names driven by configuration; refactors renaming compare methods; closures transported via serialization losing callability; first-class callable syntax confusion producing a string instead of a Closure.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/ca9d6f4a30bd117f. Report an issue: GitHub.