PHP 8.2: New Random
Extension
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.
- Existing Random Number functions moved to the new
random
extension - New
Random
namespace - New
Random\Randomizer
class - Random Number Generator Engines
- New Exception and Error types
- Existing PHP functions that throw granular exceptions
- Usage examples
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.
random_bytes
functionrandom_int
functionrand
functiongetrandmax
functionsrand
functionlcg_value
functionmt_rand
functionmt_getrandmax
functionmt_srand
functionMT_RAND_PHP
constantMT_RAND_MT19937
constant
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.