rfc:rng_extension
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:rng_extension [2021/06/25 22:23] – 2.0: Add Random Extension zeriyoshi | rfc:rng_extension [2021/07/07 13:52] – fix interface and drop C implementation stub, they're currently not fixed. zeriyoshi | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: Add Random Extension ====== | ====== PHP RFC: Add Random Extension ====== | ||
- | * Version: 2.0 | + | * Version: 2.2 |
* Date: 2021-05-18 | * Date: 2021-05-18 | ||
* Author: Go Kudo < | * Author: Go Kudo < | ||
Line 45: | Line 45: | ||
Implement and bundled Random extension into PHP. | Implement and bundled Random extension into PHP. | ||
- | The phpstub | + | The pseudo-implementation |
<code php> | <code php> | ||
+ | <?php | ||
- | /** @generate-class-entries */ | + | namespace Random |
- | /** @generate-function-entries */ | + | { |
+ | interface NumberGenerator | ||
+ | { | ||
+ | public | ||
+ | } | ||
+ | } | ||
namespace Random\NumberGenerator | namespace Random\NumberGenerator | ||
{ | { | ||
- | interface RandomNumberGenerator | + | class XorShift128Plus implements Random\NumberGenerator |
- | { | + | { |
- | /** | + | |
- | * @tentative-return-type | + | public function generate(): int {} |
- | * @internal | + | public function __serialize(): |
- | */ | + | public function __unserialize(array $data): void {} |
- | public function generate(): int; | + | } |
- | } | + | |
- | class XorShift128Plus | + | |
- | { | + | { |
- | /** @tentative-return-type */ | + | public function __construct(? |
- | public function __construct(? | + | public function generate(): int {} |
+ | public function __serialize(): | ||
+ | public function __unserialize(array $data): void {} | ||
+ | | ||
- | /** | + | |
- | * @tentative-return-type | + | { |
- | * @internal | + | public function __construct() {} |
- | */ | + | public function generate(): int {} |
- | public function generate(): int {} | + | } |
- | + | ||
- | /** @tentative-return-type */ | + | |
- | public function __serialize(): | + | |
- | + | ||
- | /** @tentative-return-type */ | + | |
- | public function __unserialize(array $data): void {} | + | |
- | } | + | |
- | + | ||
- | class MT19937 | + | |
- | { | + | |
- | /** | + | |
- | * @implementation-alias | + | |
- | * @tentative-return-type | + | |
- | */ | + | |
- | public function __construct(? | + | |
- | + | ||
- | /** | + | |
- | * @implementation-alias Random\NumberGenerator\XorShift128Plus:: | + | |
- | * @tentative-return-type | + | |
- | */ | + | |
- | | + | |
- | + | ||
- | /** | + | |
- | * @implementation-alias Random\NumberGenerator\XorShift128Plus:: | + | |
- | * @tentative-return-type | + | |
- | */ | + | |
- | public function __serialize(): | + | |
- | + | ||
- | /** | + | |
- | * @implementation-alias Random\NumberGenerator\XorShift128Plus:: | + | |
- | * @tentative-return-type | + | |
- | */ | + | |
- | public function __unserialize(array $data): void {} | + | |
- | } | + | |
- | + | ||
- | class Secure implements RandomNumberGenerator | + | |
- | { | + | |
- | /** @tentative-return-type */ | + | |
- | public function __construct() {} | + | |
- | + | ||
- | /** | + | |
- | * @implementation-alias Random\NumberGenerator\XorShift128Plus:: | + | |
- | * @tentative-return-type | + | |
- | */ | + | |
- | public function generate(): int {} | + | |
- | } | + | |
} | } | ||
namespace | namespace | ||
{ | { | ||
- | interface RandomInterface | + | final class Random |
- | { | + | { |
- | /** @tentative-return-type */ | + | |
- | public function nextInt(): int; | + | |
- | + | ||
- | /** @tentative-return-type */ | + | |
- | public function getInt(int | + | |
- | + | ||
- | /** @tentative-return-type */ | + | |
- | public function getBytes(int $length): string; | + | |
- | + | ||
- | /** @tentative-return-type */ | + | |
- | public function shuffleArray(array $array): array; | + | |
- | + | ||
- | /** @tentative-return-type */ | + | |
- | public function shuffleString(string $string): string; | + | |
- | } | + | |
- | final class Random implements RandomInterface | + | |
- | { | + | public function getNumberGenerator(): |
- | // FIXME: stub generator (gen_stub.php) does not supported. | + | |
- | // private Random\NumberGenerator\RandomNumberGenerator $rng; | + | |
- | private mixed $rng; | + | |
- | + | ||
- | | + | |
- | public function getNumberGenerator(): | + | |
- | public function nextInt(): int {} | + | |
public function getInt(int $min, int $max): int {} | public function getInt(int $min, int $max): int {} | ||
public function getBytes(int $length): string {} | public function getBytes(int $length): string {} | ||
Line 156: | Line 97: | ||
public function __serialize(): | public function __serialize(): | ||
public function __unserialize(array $data): void {} | public function __unserialize(array $data): void {} | ||
- | } | + | |
} | } | ||
</ | </ | ||
- | Each RNG is implemented as a class in the Random\NumberGenerator namespace. They all implement the Random\NumberGenerator\RandomNumberGenerator | + | Each RNG is implemented as a class in the Random\NumberGenerator namespace. They all implement the Random\NumberGenerator interface. |
The bundled RNGs are as follows: | The bundled RNGs are as follows: | ||
Line 171: | Line 112: | ||
Random class use a XorShift128+ by default. It can generate 64-bit values, is used by major browsers, and is fast and reliable. | Random class use a XorShift128+ by default. It can generate 64-bit values, is used by major browsers, and is fast and reliable. | ||
However, when used XorShift128+ in a 32-bit environment, | However, when used XorShift128+ in a 32-bit environment, | ||
+ | |||
+ | Note that (new Random\NumberGenerator\MT19937($seed))-> | ||
Secure is practically equivalent to random_int() and random_bytes(), | Secure is practically equivalent to random_int() and random_bytes(), | ||
- | This class also supports RNGs defined in userland. It can be used by passing an instance of a class that implements the RandomNumberGenerator | + | This class also supports RNGs defined in userland. It can be used by passing an instance of a class that implements the Random\NumberGenerator |
<code php> | <code php> | ||
- | class UserDefinedRNG implements Random\NumberGenerator\RandomNumberGenerator | + | class UserDefinedRNG implements Random\NumberGenerator |
{ | { | ||
protected int $current = 0; | protected int $current = 0; | ||
Line 188: | Line 131: | ||
} | } | ||
- | function foobar(Random $random): void { | + | function foobar(Random\NumberGenerator |
for ($i = 0; $i < 9; $i++) { | for ($i = 0; $i < 9; $i++) { | ||
- | echo $random->nextInt(); | + | echo $numberGenerator->generate(); |
} | } | ||
} | } | ||
- | foobar(new Random(new UserDefinedRNG())); // Results: 123456789 | + | foobar(new UserDefinedRNG()); |
</ | </ | ||
Also, as with MT, various alternative APIs using Random class will be provided. | Also, as with MT, various alternative APIs using Random class will be provided. | ||
- | <code c> | + | The Random class can be serialized using the standard PHP serialization mechanism. But, if the $rng member is not serializable, |
- | /* similar php_mt_rand() */ | + | |
- | uint64_t php_random_next(php_random *php_random, | + | |
- | + | ||
- | /* similar php_mt_rand_range() */ | + | |
- | zend_long php_random_range(php_random *php_random, | + | |
- | + | ||
- | /* similar php_array_data_shuffle() */ | + | |
- | void php_random_array_data_shuffle(php_random *php_random, | + | |
- | + | ||
- | /* similar php_string_shuffle() */ | + | |
- | void php_random_string_shuffle(php_random *php_random, | + | |
- | </ | + | |
- | + | ||
- | The Random class can be serialized using the standard PHP serialization mechanism. But, if the $rng member is not serializable, | + | |
<code php> | <code php> | ||
// serialize | // serialize | ||
$foo = new Random(new Random\Numbergenerator\XorShift128Plus()); | $foo = new Random(new Random\Numbergenerator\XorShift128Plus()); | ||
- | for ($i = 0; $i < 10; $i++) { $foo->nextInt(); } | + | for ($i = 0; $i < 10; $i++) { $foo->getInt(PHP_INT_MIN, |
- | var_dump(unserialize(serialize($foo))-> | + | var_dump(unserialize(serialize($foo))-> |
// can't serialize | // can't serialize | ||
$foo = new Random(new Random\Numbergenerator\Secure()); | $foo = new Random(new Random\Numbergenerator\Secure()); | ||
- | for ($i = 0; $i < 10; $i++) { $foo->nextInt(); } | + | for ($i = 0; $i < 10; $i++) { $foo->getInt(PHP_INT_MIN, |
- | var_dump(unserialize(serialize($foo))-> | + | var_dump(unserialize(serialize($foo))-> |
</ | </ | ||
- | It is not possible to clone the Random class. This is because the standard PHP clone method copies the members by reference when cloning. This will be an unintended behavior for most users. Instead, you can use the getNumberGenerator() method to retrieve the internal RNG instance. The RNG instance can be cloned. | + | It is not possible to clone the Random class. it always throws Error (Error: Trying to clone an uncloneable object of class Random). This is because the standard PHP clone method copies the members by reference when cloning. This will be an unintended behavior for most users. Instead, you can use the getNumberGenerator() method to retrieve the internal RNG instance. The RNG instance can be cloned. |
<code php> | <code php> | ||
Line 246: | Line 175: | ||
function foo(int $seed, callable $bar): int { | function foo(int $seed, callable $bar): int { | ||
- | $random | + | $numberGenerator |
- | $result = $random->nextInt(); | + | $result = ($numberGenerator->generate() >> 1); // requires bit-shift for compatibility. |
$bar(); | $bar(); | ||
- | $result += $random->nextInt(); | + | $result += ($numberGenerator->generate() >> 1); // requires bit-shift for compatibility. |
return $result; | return $result; | ||
} | } | ||
Line 267: | Line 196: | ||
The following class name will no longer be available: | The following class name will no longer be available: | ||
- | | + | |
- | - " | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
===== Proposed PHP Version(s) ===== | ===== Proposed PHP Version(s) ===== | ||
8.1 | 8.1 | ||
- | |||
- | ===== FAQ ===== | ||
- | ==== ==== | ||
===== RFC Impact ===== | ===== RFC Impact ===== |
rfc/rng_extension.txt · Last modified: 2022/08/01 16:52 by timwolla