RandomSequence
The RandomSequence component provides object-oriented random number sequences behind a common SequenceInterface. This is useful when you need to inject a random source as a dependency, swap implementations for testing, or produce reproducible sequences from a known seed.
The Interface
Every sequence implements SequenceInterface with a single method:
use Psl\IO;
use Psl\RandomSequence\SecureSequence;
use Psl\RandomSequence\SequenceInterface;
/** @var SequenceInterface $sequence */
$sequence = new SecureSequence();
$a = $sequence->next(); // next random int
$b = $sequence->next(); // another random int
IO\write_line('First: %d', $a);
IO\write_line('Second: %d', $b);
Implementations
MersenneTwisterSequence
A seedable Mersenne Twister (MT19937) PRNG. Given the same seed, it always produces the same sequence, making it ideal for reproducible simulations, procedural generation, and deterministic tests:
use Psl\IO;
use Psl\RandomSequence\MersenneTwisterSequence;
$seq = new MersenneTwisterSequence(seed: 42);
$first = $seq->next(); // always the same for seed 42
$second = $seq->next(); // deterministic
IO\write_line('First (seed 42): %d', $first);
IO\write_line('Second (seed 42): %d', $second);
MersenneTwisterPHPVariantSequence
A variant that matches PHP's internal mt_rand twist behavior. Use this when you need compatibility with sequences generated by PHP's built-in Mersenne Twister:
use Psl\IO;
use Psl\RandomSequence\MersenneTwisterPHPVariantSequence;
$seq = new MersenneTwisterPHPVariantSequence(seed: 42);
$first = $seq->next();
$second = $seq->next();
IO\write_line('PHP variant first (seed 42): %d', $first);
IO\write_line('PHP variant second (seed 42): %d', $second);
SecureSequence
A cryptographically secure sequence backed by SecureRandom\int(). Use this in production when security matters:
use Psl\IO;
use Psl\RandomSequence\SecureSequence;
$seq = new SecureSequence();
$value = $seq->next(); // cryptographically secure random int
IO\write_line('Secure random: %d', $value);
Dependency Injection
The shared interface makes it easy to swap implementations. Use MersenneTwisterSequence in tests for reproducibility and SecureSequence in production:
use Psl\IO;
use Psl\Iter;
use Psl\RandomSequence\MersenneTwisterSequence;
use Psl\RandomSequence\SecureSequence;
use Psl\RandomSequence\SequenceInterface;
/**
* Picks a random winner from the list of participants using the provided RNG.
*
* @param non-empty-list<non-empty-string> $participants
*
* @return non-empty-string The name of the winner.
*/
function pick_winner(array $participants, SequenceInterface $rng): string
{
/** @var int<0, max> $index */
$index = $rng->next() % Iter\count($participants);
return $participants[$index];
}
// Deterministic for tests
$testRng = new MersenneTwisterSequence(seed: 42);
$winner = pick_winner(['Alice', 'Bob', 'Charlie'], $testRng);
IO\write_line('Test winner: %s', $winner);
// Secure for production
$prodRng = new SecureSequence();
$winner = pick_winner(['Alice', 'Bob', 'Charlie'], $prodRng);
IO\write_line('Production winner: %s', $winner);
See src/Psl/RandomSequence/ for the full API.