the following code performs checks to see if the url exists. how can i improve the speed?

<?php

declare(strict_types=1);

namespace App\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;

#[AsCommand(
    name: 'app:check-genius-sports-urls',
    description: 'Generates letter combinations for URLs and checks them concurrently.',
)]
class CheckGeniusSportsUrlsCommand extends Command
{
    private HttpClientInterface $httpClient;
    private CacheInterface $cache;
    private const string BASE_URL = 'https://hosted.dcd.shared.geniussports.com/{letters}/';
    private ?SymfonyStyle $io = null;

    public function __construct(HttpClientInterface $httpClient, CacheInterface $cache)
    {
        parent::__construct();
        $this->httpClient = $httpClient;
        $this->cache = $cache;
    }

    protected function configure(): void
    {
        $this
            ->addArgument('length', InputArgument::REQUIRED, 'The number of capital letters for the combinations (e.g., 2 for AA-ZZ).')
            ->addOption('batch-size', 'b', InputOption::VALUE_OPTIONAL, 'Number of URLs to process concurrently in a batch.', 100)
            ->addOption('batch-delay', null, InputOption::VALUE_OPTIONAL, 'Delay in microseconds between processing batches (e.g., 100000 for 0.1s).', 0)
            ->addOption('timeout', null, InputOption::VALUE_OPTIONAL, 'Request timeout in seconds for each request.', 2)
            ->addOption('cache-lifetime', null, InputOption::VALUE_OPTIONAL, 'Cache lifetime in seconds for each URL result.', 7 * 24 * 60 * 60);
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $this->io = new SymfonyStyle($input, $output);
        $length = (int)$input->getArgument('length');
        $batchSize = (int)$input->getOption('batch-size');
        $batchDelay = (int)$input->getOption('batch-delay');
        $timeout = (float)$input->getOption('timeout');
        $cacheLifetime = (int)$input->getOption('cache-lifetime');

        if ($length <= 0) {
            $this->io->error('Length must be a positive integer.');
            return Command::INVALID;
        }
        if ($batchSize <= 0) {
            $this->io->error('Batch size must be a positive integer.');
            return Command::INVALID;
        }

        if ($length > 5) { // Increased threshold slightly, but concurrency helps
            $this->io->warning("Warning: Length {$length} can generate a very large number of URLs (26^{$length}). This might take an extremely long time and consume significant resources, though concurrency will help.");
            if (!$this->io->confirm('Do you want to continue?', false)) {
                $this->io->note('Operation cancelled by the user.');
                return Command::SUCCESS;
            }
        }

        $successfulUrls = [];
        $characters = range('A', 'Z');
        $numChars = count($characters);

        $estimatedTotalIterations = pow($numChars, $length);

        if ($estimatedTotalIterations > 20000 && $estimatedTotalIterations / $batchSize > 100) { // Adjusted threshold for confirmation
            $this->io->warning("This command will attempt to check approximately " . number_format($estimatedTotalIterations) . " URLs in batches of {$batchSize}.");
            if (!$this->io->confirm('This could take a very long time. Are you sure you want to proceed?', false)) {
                $this->io->note('Operation cancelled by the user.');
                return Command::SUCCESS;
            }
        }

        $maxProgressSteps = 0;
        if (is_finite($estimatedTotalIterations) && $estimatedTotalIterations > 0 && $estimatedTotalIterations <= PHP_INT_MAX) {
            $maxProgressSteps = (int)$estimatedTotalIterations;
        }
        $this->io->progressStart($maxProgressSteps);

        $indices = array_fill(0, $length, 0);
        $keepGenerating = $length > 0;
        $urlBatch = [];

        while ($keepGenerating) {
            $currentCombination = '';
            foreach ($indices as $index) {
                $currentCombination .= $characters[$index];
            }

            // Advance progress for each generated combination
            if ($maxProgressSteps > 0) $this->io->progressAdvance(); else $this->io->progressAdvance(0);

            $urlBatch[] = str_replace('{letters}', $currentCombination, self::BASE_URL);

            // Increment indices for the next combination
            $pos = $length - 1;
            while ($pos >= 0) {
                $indices[$pos]++;
                if ($indices[$pos] < $numChars) {
                    break;
                }
                $indices[$pos] = 0;
                $pos--;
            }

            if ($pos < 0) {
                $keepGenerating = false;
            }

            // Process batch if full or if it's the last iteration and batch has items
            if (count($urlBatch) > 0 && (count($urlBatch) >= $batchSize || !$keepGenerating)) {
                $this->processUrlBatch($urlBatch, $successfulUrls, $timeout, $cacheLifetime);
                $urlBatch = []; // Reset for next batch
                if ($batchDelay > 0 && $keepGenerating) {
                    usleep($batchDelay);
                }
            }
        }

        $this->io->progressFinish();

        if (!empty($successfulUrls)) {
            $this->io->success('Successfully retrieved content from the following URLs:');
            $this->io->listing($successfulUrls);
        } else {
            $this->io->note('No URLs returned content successfully with the generated combinations.');
        }

        return Command::SUCCESS;
    }

    private function processUrlBatch(array $urlsInBatch, array &$successfulUrls, float $timeout, int $cacheLifetime): void
    {
        if (empty($urlsInBatch) || $this->io === null) {
            return;
        }

        foreach ($urlsInBatch as $url) {
            $cacheKey = 'genius_url_' . md5($url);
            $result = $this->cache->get($cacheKey, function (ItemInterface $item) use ($url, $timeout, $cacheLifetime) {
                $item->expiresAfter($cacheLifetime);
                try {
                    $response = $this->httpClient->request('GET', $url, [
                        'timeout' => $timeout,
                        'max_redirects' => 3,
                    ]);
                    $response->getHeaders(false);
                    $statusCode = $response->getStatusCode();
                    if ($statusCode >= 200 && $statusCode < 300) {
                        $content = $response->getContent(false);
                        if (strlen(trim($content)) > 0) {
                            preg_match('/validateSetup\\(2,(.*)\\);/', $content, $matches);
                            if (isset($matches[1]) && is_string($matches[1]) && strlen($matches[1]) > 0) {
                                $matchesContent = $matches[1];
                                preg_match("/,'([a-z]+\.web\.geniussports\.com)'/", $matchesContent, $validUrl);
                                if (isset($validUrl[1])) {
                                    return 'https://' . $validUrl[1];
                                }
                            }
                            return $url;
                        }
                    }
                } catch (TransportExceptionInterface|\Exception) {
                    // Ignore and do not cache failures
                }
                $item->expiresAfter(1);
                return null;
            });
            if ($result) {
                $successfulUrls[] = $result;
                if ($this->io->isVerbose()) {
                    $this->io->writeln(" <info>CACHED SUCCESS:</info> {$result}");
                }
            } elseif ($this->io->isVeryVerbose()) {
                $this->io->writeln(" <comment>CACHED MISS OR FAILURE:</comment> {$url}");
            }
        }
    }
}