symfony/finder · error · InvalidArgumentException

Invalid PHP callback.

Error message

Invalid PHP callback.

What it means

CustomFilterIterator requires every entry of the $filters array to be a PHP callable; if any element is not callable it throws InvalidArgumentException('Invalid PHP callback.') before filtering begins. The library needs real callbacks to apply the custom acceptance logic.

Solutions

  1. Ensure each filter is callable: closure, 'function' name, ['Class','method'] / 'Class::method' existing, or invokable object
  2. Validate with is_callable($filter) before constructing
  3. If filters come from config, map/whitelist them to real PHP callables

Example fix

// before
$finder->filter(['nonexistent_function']);
// after
$finder->filter([static fn (\SplFileInfo $f) => $f->getExtension() === 'php']);
Defensive patterns

Strategy: type-guard

Validate before calling

foreach ($filters as $f) { if (!is_callable($f)) { throw new \InvalidArgumentException('Filter is not callable'); } }

Type guard

function allCallable(array $filters): bool { return array_all($filters, fn ($f) => is_callable($f)); }

Try / catch

try { $finder->filter($filters); } catch (\InvalidArgumentException $e) { /* handle non-callable filter */ }

Prevention

When it happens

Trigger: new CustomFilterIterator($iterator, ['strlen', 42]) or Finder::filter([null]) — passing an array containing a non-callable, a method string for a nonexistent method used as a single string, or an object without __invoke.

Common situations: Config-driven filters read as strings/arrays that aren't callables, typos in 'Class::method' strings, passing [object, 'method'] arrays where the method doesn't exist so is_callable fails.

Understand the failure class

Background: "must be a positive integer", "cannot be empty", "invalid argument": how invalid-argument errors work across open-source libraries — this error's family across 33 libraries.

Related errors


AI-assisted analysis of symfony/finder@4d6c057bfd (2026-09-13). Data as JSON: /api/errors/b8a05398b6304c7b. Report an issue: GitHub.

Appendix: source

Thrown at Iterator/CustomFilterIterator.php:38

 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @extends \FilterIterator<string, \SplFileInfo>
 */
class CustomFilterIterator extends \FilterIterator
{
    private array $filters = [];

    /**
     * @param \Iterator<string, \SplFileInfo> $iterator The Iterator to filter
     * @param callable[]                      $filters  An array of PHP callbacks
     *
     * @throws \InvalidArgumentException
     */
    public function __construct(\Iterator $iterator, array $filters)
    {
        foreach ($filters as $filter) {
            if (!\is_callable($filter)) {
                throw new \InvalidArgumentException('Invalid PHP callback.');
            }
        }
        $this->filters = $filters;

        parent::__construct($iterator);
    }

    /**
     * Filters the iterator values.
     */
    public function accept(): bool
    {
        $fileinfo = $this->current();

        foreach ($this->filters as $filter) {
            if (false === $filter($fileinfo)) {
                return false;
            }

View on GitHub (pinned to 4d6c057bfd)