{"record":{"id":"fdf9cf5420e76758","repo":"symfony/finder","slug":"the-sortableiterator-takes-a-php-callable-or-a-valid-built","errorCode":null,"errorMessage":"The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.","messagePattern":"The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument\\.","errorType":"validation","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"Iterator/SortableIterator.php","lineNumber":83,"sourceCode":"\n                return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());\n            };\n        } elseif (self::SORT_BY_ACCESSED_TIME === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * ($a->getATime() - $b->getATime());\n        } elseif (self::SORT_BY_CHANGED_TIME === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * ($a->getCTime() - $b->getCTime());\n        } elseif (self::SORT_BY_MODIFIED_TIME === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * ($a->getMTime() - $b->getMTime());\n        } elseif (self::SORT_BY_EXTENSION === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * strnatcmp($a->getExtension(), $b->getExtension());\n        } elseif (self::SORT_BY_SIZE === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * ($a->getSize() - $b->getSize());\n        } elseif (self::SORT_BY_NONE === $sort) {\n            $this->sort = $order;\n        } elseif (\\is_callable($sort)) {\n            $this->sort = $reverseOrder ? static fn (\\SplFileInfo $a, \\SplFileInfo $b) => -$sort($a, $b) : $sort(...);\n        } else {\n            throw new \\InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');\n        }\n    }\n\n    public function getIterator(): \\Traversable\n    {\n        if (1 === $this->sort) {\n            yield from $this->iterator;\n\n            return;\n        }\n\n        $keys = $values = [];\n        foreach ($this->iterator as $key => $value) {\n            $keys[] = $key;\n            $values[] = $value;\n        }\n\n        if (-1 === $this->sort) {","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/symfony/finder/blob/4d6c057bfd67c5a93e8025c85ca9364cba7e260a/Iterator/SortableIterator.php#L65-L101","documentation":"SortableIterator accepts either a built-in sort constant (SORT_BY_NAME, SORT_BY_TYPE, SORT_BY_ACCESSED_TIME, SORT_BY_CHANGED_TIME, SORT_BY_MODIFIED_TIME, SORT_BY_NONE, and their _AS_STRING variants) or a PHP callable comparator; anything else throws InvalidArgumentException with this message.","triggerScenarios":"new SortableIterator($iterator, 'name') (string not a callable/constant), Finder::sort('bogus'), passing an int outside the defined constant range, or a non-callable value like an array of sort options.","commonSituations":"Passing 'name' as a string expecting it to map to SORT_BY_NAME, using removed/renamed constants after upgrading, config-driven sort values read as raw strings.","solutions":["Use class constants: SortableIterator::SORT_BY_NAME, or a closure fn (\\SplFileInfo $a, \\SplFileInfo $b) => ...","Replace string sort names with the corresponding constant or callable","Verify the sort int is one of the class's SORT_BY_* constants after a library upgrade"],"exampleFix":"// before\n$finder->sort('name'); // string is neither callable nor a valid algorithm\n// after\n$finder->sort(\\Symfony\\Component\\Finder\\Iterator\\SortableIterator::SORT_BY_NAME);","handlingStrategy":"type-guard","validationCode":"$valid = [SortableIterator::SORT_BY_NONE, SortableIterator::SORT_BY_NAME, SortableIterator::SORT_BY_TYPE, SortableIterator::SORT_BY_ACCESSED_TIME, SortableIterator::SORT_BY_CHANGED_TIME, SortableIterator::SORT_BY_MODIFIED_TIME]; if (!is_callable($sort) && !in_array($sort, $valid, true)) { throw new \\InvalidArgumentException('Invalid sort'); }","typeGuard":"function isValidSort(mixed $sort): bool { return is_callable($sort) || in_array($sort, [SortableIterator::SORT_BY_NONE, SortableIterator::SORT_BY_NAME, SortableIterator::SORT_BY_TYPE, SortableIterator::SORT_BY_ACCESSED_TIME, SortableIterator::SORT_BY_CHANGED_TIME, SortableIterator::SORT_BY_MODIFIED_TIME], true); }","tryCatchPattern":"try { $finder->sort($sort); } catch (\\InvalidArgumentException $e) { /* handle invalid sort */ }","preventionTips":["Use SortableIterator::SORT_BY_* constants instead of raw strings/ints","Pass closures typed as fn (\\SplFileInfo $a, \\SplFileInfo $b): int for custom sorts","Map config sort names ('name', 'size') to constants in one place","Re-check constant usage after Finder upgrades"],"tags":["sorting","invalid-argument","finder"],"backgroundTag":"invalid-argument-value","analyzedSha":"4d6c057bfd67c5a93e8025c85ca9364cba7e260a","analyzedAt":"2026-09-13T07:49:33.433Z","contentChangedAt":"2026-09-13T07:49:33.433Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}