# Performance Considerations for Generating a Large Number of Keys with SunLicense

> Discover performance issues generating many SunLicense keys including O(n²) complexity and memory growth. Learn hash-set optimization and batch streaming for >10000 keys.

- Repository: [Mehmet Selcuk Batal/php-license-key-generator](https://github.com/msbatal/php-license-key-generator)
- Tags: performance
- Published: 2026-03-07

---

**Generating a large number of keys with SunLicense creates O(n²) complexity due to linear duplicate checks and unbounded memory growth, requiring hash-set optimizations and streaming for batches exceeding 10,000 keys.**

The `msbatal/php-license-key-generator` repository provides a lightweight solution for creating license keys, but the `SunLicense` class exhibits specific performance constraints when scaling to high-volume generation. Understanding these architectural limitations is essential before deploying the library for bulk key provisioning. When generating a large number of keys with SunLicense, developers must account for quadratic time complexity and linear memory consumption that degrade performance beyond modest batch sizes.

## How SunLicense Generates Keys

### Template-Based Character Generation

In [`SunLicense.php`](https://github.com/msbatal/php-license-key-generator/blob/main/SunLicense.php) (lines 79-97), the `license()` method constructs each key by iterating over the template string character-by-character using a `for` loop with `strlen($this->template)`. For every alphabetic or numeric placeholder, the code invokes the legacy `rand()` function to select random characters. This approach results in **O(template-length)** computational work per key, meaning longer templates directly increase CPU time linearly.

### The Uniqueness Verification Process

The `generate()` method (lines 106-112) stores every created key in the `$this->keys` array and relies on the `check()` method to prevent duplicates. According to the source code in [`SunLicense.php`](https://github.com/msbatal/php-license-key-generator/blob/main/SunLicense.php) (lines 56-71), the `check()` method uses `in_array($key, $this->keys)` to scan the entire existing key set for each new generation attempt. This linear search creates a bottleneck that scales quadratically as the batch size grows.

## Performance Bottlenecks in Bulk Generation

### Quadratic Time Complexity

The `in_array` operation performs a linear scan of all previously generated keys. When generating *n* keys, the total number of comparisons equals the sum of integers from 1 to *n*, resulting in **O(n²)** time complexity. As implemented in `msbatal/php-license-key-generator`, this quadratic cost becomes noticeable around 10,000 keys and dominates runtime for larger batches.

### Unbounded Memory Consumption

The class maintains an indexed array `$this->keys` that retains every generated string in memory throughout the execution. For a template producing 20-character keys, generating 100,000 keys consumes approximately 2 MB of raw string data plus PHP array overhead, often exceeding default `memory_limit` settings on shared hosting environments.

### Random Number Generator Overhead

The implementation uses PHP's legacy `rand()` function (lines 86, 90, 92 in [`SunLicense.php`](https://github.com/msbatal/php-license-key-generator/blob/main/SunLicense.php)) for each character position. While sufficient for small batches, `rand()` is slower than modern alternatives like `mt_rand()` or `random_int()`, becoming a measurable bottleneck when called millions of times during large-scale generation.

## Practical Performance Thresholds

For batches of **10,000 keys or fewer**, the default `SunLicense` implementation operates efficiently on modern hardware, with template processing dominating execution time. However, beyond this threshold, the **quadratic uniqueness check** begins to dominate, causing generation time to increase disproportionately with batch size. Memory pressure compounds this issue, as PHP must maintain the entire key history in RAM.

## Optimization Strategies for High-Volume Generation

### Replace Linear Search with Hash Sets

Convert the `$this->keys` storage from an indexed array to an associative array using keys as indexes. Modify the `check()` method to use `isset($this->keys[$key])` instead of `in_array()`. This reduces duplicate detection from **O(n) to O(1)**, eliminating the quadratic bottleneck entirely.

### Stream Keys Using Generators

Instead of buffering all keys in memory, override the `generate()` method to use PHP generators (`yield`). This approach keeps memory usage constant regardless of batch size by emitting each key immediately upon creation, allowing downstream processes to write directly to databases or files without accumulating arrays.

### Upgrade the Random Generator

Replace `rand()` with `mt_rand()` for speed improvements, or `random_int()` for cryptographically secure randomness. In [`SunLicense.php`](https://github.com/msbatal/php-license-key-generator/blob/main/SunLicense.php), update the character selection logic (lines 86, 90, 92) to use the preferred function based on your security requirements.

### Implement Batch Processing

Split massive generation requests into smaller chunks (e.g., 5,000 keys per batch). Process each chunk sequentially while clearing the keys array between iterations. This strategy limits peak memory usage and keeps the quadratic check manageable if you cannot modify the source code.

## Implementation Examples

The following examples demonstrate basic usage and optimized approaches for the `msbatal/php-license-key-generator` library.

Basic generation with default settings:

```php
<?php
require_once __DIR__ . '/../SunLicense.php';

$sl = new SunLicense(null, null, 'upper', 5);
$keys = $sl->generate();
print_r($keys);

```

Streaming large batches with constant memory:

```php
<?php
require_once __DIR__ . '/../SunLicense.php';

class SunLicenseStream extends SunLicense {
    public function generate() {
        $generated = 0;
        while ($generated < $this->keyCount) {
            $key = $this->license();
            if (!isset($this->keys[$key])) {
                $this->keys[$key] = true;
                $generated++;
                yield $key;
            }
        }
    }
}

$stream = new SunLicenseStream(null, null, 'upper', 20000);
foreach ($stream->generate() as $key) {
    echo $key . PHP_EOL;
}

```

High-performance generation with faster RNG:

```php
<?php
require_once __DIR__ . '/../SunLicense.php';

class SunLicenseFast extends SunLicense {
    private function license() {
        $key = !empty($this->prefix) ? $this->prefix . '-' : '';
        $len = strlen($this->template);
        for ($i = 0; $i < $len; $i++) {
            $char = $this->template[$i];
            if (ctype_alpha($char)) {
                $key .= $this->case === 'lower'
                      ? chr(mt_rand(97, 122))
                      : chr(mt_rand(65, 90));
            } elseif (ctype_digit($char)) {
                $key .= mt_rand(0, 9);
            } else {
                $key .= '-';
            }
        }
        return $key;
    }
}

$fast = new SunLicenseFast(null, null, 'upper', 10000);
$keys = $fast->generate();
echo 'Generated ' . count($keys) . ' keys using mt_rand().' . PHP_EOL;

```

## Summary

- **Quadratic complexity**: The default `in_array` duplicate check in [`SunLicense.php`](https://github.com/msbatal/php-license-key-generator/blob/main/SunLicense.php) creates O(n²) time complexity when generating a large number of keys with SunLicense.
- **Memory growth**: The class stores every key in the `$this->keys` array, causing linear memory consumption that can exhaust PHP limits.
- **Template overhead**: Character-by-character template processing with `rand()` calls adds linear CPU cost per key based on template length.
- **Hash sets**: Replacing `in_array` with `isset()` on associative arrays reduces duplicate detection to O(1).
- **Streaming**: Using generators eliminates memory buffering, enabling unlimited batch sizes.
- **RNG selection**: `mt_rand()` offers speed improvements over `rand()` for high-volume generation.

## Frequently Asked Questions

### What is the maximum number of keys SunLicense can generate?

The theoretical limit depends on template entropy and available memory. Practically, the default implementation encounters severe performance degradation beyond 10,000 keys due to O(n²) duplicate checking. With hash-set optimizations and streaming, you can generate millions of keys limited only by your storage I/O capacity.

### Why does key generation slow down exponentially as the batch grows?

The `check()` method in [`SunLicense.php`](https://github.com/msbatal/php-license-key-generator/blob/main/SunLicense.php) uses `in_array()` to verify uniqueness, which performs a linear scan of all previously generated keys. As the array grows, each new key requires comparing against an increasingly large set, creating exponential time complexity. Switching to `isset()` with associative arrays restores linear time complexity.

### How can I reduce memory usage when generating hundreds of thousands of keys?

Override the `generate()` method to use PHP's `yield` keyword instead of returning an array. This streams each key individually, keeping memory usage constant regardless of batch size. Additionally, write keys directly to persistent storage (database or file) within the generation loop rather than accumulating them in RAM.

### Is the default rand() function secure enough for commercial license keys?

While `rand()` provides sufficient randomness for basic obfuscation, it is not cryptographically secure and exhibits statistical weaknesses. For security-critical applications, replace `rand()` with `random_int()` in the `license()` method (lines 86, 90, 92 of [`SunLicense.php`](https://github.com/msbatal/php-license-key-generator/blob/main/SunLicense.php)). Note that `random_int()` is slower than `mt_rand()`, so choose based on your security versus performance requirements.