public function extract(
        FileIteratorInterface $files,
        SymbolFilterInterface $filter
    ): SymbolIteratorInterface {
        $symbols = [];

        foreach ($files as $file) {
            $parser = clone $this->parser;

            try {
                $size     = $file->getSize();
                $handle   = $file->openFile('rb');
                $contents = $size  > 0 ? $handle->fread($size) : '';

                if (empty($contents)) {
                    continue;
                }

                $statements = $parser->parse($contents);
            } catch (Error $e) {
                // Either not a file, file is not readable, not a PHP file or
                // the broken file should be detected by other tooling entirely.
                continue;
            }

            $tracker   = new SymbolTracker($filter);
            $traverser = new NodeTraverser();
            $traverser->addVisitor($tracker);
            $traverser->traverse($statements);

            foreach ($tracker->getSymbols() as $node) {
                $symbols[] = new Symbol($file, $node);
            }
        }

        return new SymbolIterator(...$symbols);
    }