PHP 8.2: New Random Extension

Version8.2
TypeNew Feature

PHP 8.2 introduces a new PHP extension named random, that organizes and consolidates existing PHP functionality related to random number generation, and introduces a series of PHP class structure and exception classes to provide granular choice of random-number generator and exception handling.

The random extension is bundled with PHP, and there is no compile-time or run-time configuration option to disable the random extension. The random extension will be always available in PHP 8.2 and later.

There are several changes made to existing random number generation functionality that should not cause any backwards compatibility issues across PHP versions. However, note that PHP applications and tools that inspect PHP random-number related functions (for example, using ReflectionFunction or ReflectionExtension from Reflection APIs) may get different results in PHP 8.2 and later. However, these scenarios are quite niche and are unlikely to cause any issues in regular PHP applications.


Testing Randomness of PHP Random Number Functions
Visualizing and testing various Random Number Generators available in PHP.


Existing Random Number functions moved to the new random extension

PHP has several functions in its standard library that generate random numbers. In PHP 8.2, several PHP functions are moved to the new random extension. All of the functions continue to reside in the global namespace. Because the random extension is always included when compiling PHP, there should be no practical difference in PHP applications.

The following functions and constants are now moved to the random extension.

Although the functionality of the functions above has not changed (apart from the use of new random-specific Exception and Error exceptions), this change is observable from the Reflection API. Since PHP 8.2, the ReflectionFunction::getExtension returns random extension instead of the former standard extension:

 $reflector = new ReflectionFunction('random_int');
 $reflector->getExtension()->getName();
- // "standard"
+ // "random"

New \Random namespace

Following PHP's adopted namespace policy, all new functionality introduced in the random extension are added to a new namespace called \Random.

The \Random namespace is reserved for the extension. Existing PHP applications that make use of the \Random namespace can continue to use it, as long as there are no conflicts with the new classes, interfaces, and exceptions added in PHP 8.2.

New Random\Randomizer class

One of the most important new additions with the new random extension is the Random\Randomizer class. It is meant to provide an object-oriented API to access all Random Number generation functionality with a choice of Pseudo Random Number Generator algorithm, which can be swapped out with a new implementation.

The following is an example that generates a random number using the new Random\Randomizer class.

$r = new Random\Randomizer();
echo $r->getInt(1, 100); // 42
echo $r->shuffleBytes('lorem ipsum'); // "ols mpeurim"

For a detailed example, see usage examples section section.

Random\Randomizer synopsis

namespace Random;

final class Randomizer {

    public readonly Engine $engine;

    public function __construct(?Engine $engine = null) {}

    public function nextInt(): int {}

    public function getInt(int $min, int $max): int {}

    public function getBytes(int $length): string {}

    public function shuffleArray(array $array): array {}

    public function shuffleBytes(string $bytes): string {}

    public function pickArrayKeys(array $array, int $num): array {}

    public function __serialize(): array {}

    public function __unserialize(array $data): void {}

}

Random Number Generator Engines

PHP 8.2 adds support for multiple Pseudo Random Number Generator algorithms (PRNG engines). Random\Randomizer class accepts any PRNG implementation that provides an object-oriented interface to generate random numbers and bytes, shuffle arrays, and randomly pick elements from an array with a given PRNG engine.

The random extension provides a \Random\Engine interface that all PRNG engine classes must implement. Additionally, there is a \Random\CryptoSafeEngine interface that extends \Random\Engine interface for PRNG engine classes that are safe for cryptographic operations.

namespace Random;

interface Engine {
    public function generate(): string;
}

interface CryptoSafeEngine extends Engine {
}

The random extension provides four \Random\Engine implementations built-in. All of these implementations are final classes.

Random\Engine\Mt19937

Random\Engine\Mt19937 is a built-in PHP class that implements Random\Engine interface. It uses the same Mersenne Twister Random Number Generator as mt_rand function. It is also possible to seed the algorithm with an arbitrary value when the class is instantiated. This engine is not suitable for cryptographically secure applications because the internal state of the RNG can be derived by observing consecutive output values.

Random\Engine\Mt19937 synopsis

namespace Random\Engine;

final class Mt19937 implements \Random\Engine {
    public function __construct(int|null $seed = null, int $mode = MT_RAND_MT19937) {}
    public function generate(): string {}
    public function __serialize(): array {}
    public function __unserialize(array $data): void {}
    public function __debugInfo(): array {}
}

Random\Engine\PcgOneseq128XslRr64

Random\Engine\PcgOneseq128XslRr64 class provides a Permuted congruential generator implementation. This engine is not suitable for cryptographically secure applications.

Random\Engine\PcgOneseq128XslRr64 synopsis

namespace Random\Engine;

final class PcgOneseq128XslRr64 implements \Random\Engine {
    public function __construct(string|int|null $seed = null) {}
    public function generate(): string {}
    public function jump(int $advance): void {}
    public function __serialize(): array {}
    public function __unserialize(array $data): void {}
    public function __debugInfo(): array {}
}

Random\Engine\Xoshiro256StarStar

Random\Engine\Xoshiro256StarStar class provides a Xoshiro PRNG implementation in PHP. While Xoshiro256StarStar engine is not suitable for cryptographically secure applications, it is fastest among the provided engines due to its simplicity, making it a good candidate for applications that need to randomize a pool of data (such as randomizing a slideshow).

Random\Engine\Xoshiro256StarStar synopsis

namespace Random\Engine;

final class Xoshiro256StarStar implements \Random\Engine {
    public function __construct(string|int|null $seed = null) {}
    public function generate(): string {}
    public function jump(): void {}
    public function jumpLong(): void {}
    public function __serialize(): array {}
    public function __unserialize(array $data): void {}
    public function __debugInfo(): array {}
}

Random\Engine\Secure

Random\Engine\Secure class provides the same implementation as random_bytes and random_int functions, and is recommended to be used for all random number generation, including is secure for cryptographic operations as well.

Random\Engine\Secure synopsis

namespace Random\Engine;

final class Secure implements \Random\CryptoSafeEngine {
    public function generate(): string {}
}

New Exception and Error types

As part of the changes and introduction of the new random extension, there are new Exception and Error types. PRNG engines and the Random\Randomizer classes, and existing random number generator functions throw more granular Exceptions and Errors in PHP 8.2 and later.

namespace Random;

class RandomError extends \Error {}

class BrokenRandomEngineError extends RandomError {}

class RandomException extends \Exception {}

Hierarchy of PHP Exceptions
Lists all the current PHP exceptions and errors in a hierarchical order.

Existing PHP functions that throw granular exceptions

Since PHP 8.2 and later, random_int, random_bytes, and other existing functions can throw RandomError, BrokenRandomEngineError, and RandomException exceptions where applicable. However, this is unlikely to introduce any backwards compatibility issues because the new Exception and Error types extend the base Error and Exception classes.

Usage examples

Here are some examples of using the new \Random\Randomizer class with various engines, as well as some replacement patterns.


Generating a random-number between 1 and 100

$randomizer = new Random\Randomizer();
$randomizer->getInt(1, 100); // 42

Shuffle a string

$randomizer = new Random\Randomizer();
$randomizer->shuffleBytes('abcdef'); // baecfd

Note that shuffleBytes method does exactly what it says on the name: shuffle the bytes. For multi-byte characters, this produces distorted/Mojibake text.


Shuffle an array

$randomizer = new Random\Randomizer();
$randomizer->shuffleArray(['apple', 'banana', 'orange']); // ['orange', 'apple', 'banana']

Using Mt19937 Engine

$randomizer = new Random\Randomizer(new Random\Engine\Mt19937());
$randomizer->getInt(1, 100); // 68

Using Mt19937 Engine with seed

$randomizer = new Random\Randomizer(new Random\Engine\Mt19937(42));
$randomizer->getInt(1, 100); // 43

Using Xoshiro256StarStar Engine with seed

$randomizer = new Random\Randomizer(new Random\Engine\Xoshiro256StarStar(hash("sha256", "some seed value")));
$randomizer->getInt(1, 100); // 43

Using PcgOneseq128XslRr64 Engine with seed

$randomizer = new Random\Randomizer(new Random\Engine\PcgOneseq128XslRr64(hash("md5", "some seed value")));
$randomizer->getInt(1, 100); // 43

Using a mock Engine that returns the same value, to be used in unit tests

class XKCDRandomEngine implements \Random\Engine {
    public function generate(): string {
        return \pack('V', 4); // Chosen by fair dice roll.
                              // Guaranteed to be random.
    }
}
$randomizer = new Random\Randomizer(new XKCDRandomEngine());
$randomizer->getInt(0, 100); // 4

Replacing random_bytes calls

- $randomValue = random_bytes(32); // Retrieves 32 random bytes.
+ $randomizer = new Random\Randomizer();
+ $randomizer->getBytes(32);

Backwards Compatibility Impact

random is a new extension added to PHP. Existing PHP applications should not cause any issues in PHP 8.2 and later with regards to the changes related to random extension. However, be mindful when using [the new Exception and Error classes] because older PHP versions throw more generic exceptions on the same conditions.

It is possible to port part of this new functionality to older PHP version as a polyfill, but PcgOneseq128XslRr64 and Xoshiro256StarStar will be very difficult to back-port because the underlying PRNG is computationally difficult to emulate. For example, PcgOneseq128XslRr64 is an 128 bit unsigned engine, which is difficult to emulate on 64 bit integers.


This article was updated with the support and input from Tim Düsterhus, one of the maintainers of the new random extension.


RFC Discussion Implementation