rfc:object_scope_prng

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
rfc:object_scope_prng [2021/01/26 17:46]
zeriyoshi docment 2.0
rfc:object_scope_prng [2021/04/14 14:38] (current)
zeriyoshi status update
Line 1: Line 1:
 ====== PHP RFC: Object scoped RNG Implementations. ====== ====== PHP RFC: Object scoped RNG Implementations. ======
-  * Version: 2.(Implementation: 1.3) +  * Version: 2.(Implementation: 1.3) 
-  * Date: 2021-01-27+  * Date: 2020-12-20
   * Author: Go Kudo <zeriyoshi@gmail.com>   * Author: Go Kudo <zeriyoshi@gmail.com>
-  * Status: Under Discussion+  * Status: Declined
   * Implementation: https://github.com/php/php-src/pull/6568   * Implementation: https://github.com/php/php-src/pull/6568
   * First Published at: https://wiki.php.net/rfc/object_scope_prng   * First Published at: https://wiki.php.net/rfc/object_scope_prng
Line 12: Line 12:
 <code php> <code php>
 \mt_srand(1234); // Seeding internal MT state. \mt_srand(1234); // Seeding internal MT state.
-echo \mt_rand(); // Generate random number.+\mt_rand(); // Generate random number.
 </code> </code>
  
Line 50: Line 50:
 <code shell> <code shell>
 $ git clone "https://github.com/savvot/random" $ git clone "https://github.com/savvot/random"
-$ time php -r 'require __DIR__ . "/random/src/AbstractRand.php"; require __DIR__ . "/random/src/XorShiftRand.php"; $r = new Savvot\Random\XorShiftRand(1234); for ($i = 0; $i < 1000000; $i++) { $r->random(); }'+$ time ./php -r 'require __DIR__ . "/random/src/AbstractRand.php"; require __DIR__ . "/random/src/XorShiftRand.php"; $r = new Savvot\Random\XorShiftRand(1234); for ($i = 0; $i < 1000000; $i++) { $r->random(); }'
  
 real    0m0.745s real    0m0.745s
Line 74: Line 74:
 user    0m0.010s user    0m0.010s
 sys     0m0.011s sys     0m0.011s
 +</code>
 +
 +RFC has been passed and Fiber will be introduced in PHP 8.1. Implementations with unpredictable execution order, such as Fiber, make this problem worse.
 +For example (with amphp), the following results are difficult for the user to be aware of and are not guaranteed to be consistent in the future.
 +
 +<code php>
 +use function Amp\defer;
 +use function Amp\delay;
 +
 +function task(int $i): void {
 +    global $running;
 +
 +    while ($running) {
 +        delay(250);
 +        echo "${i} : " . mt_rand() . "\n";
 +    }
 +}
 +
 +mt_srand(1234);
 +
 +$running = true;
 +
 +defer(fn() => task(1));
 +defer(fn() => task(2));
 +defer(fn() => task(3));
 +defer(fn() => task(4));
 +
 +delay(1000);
 +$running = false;
 +
 +/*
 +Result:
 +1 : 411284887
 +4 : 1068724585
 +2 : 1335968403
 +3 : 1756294682
 +1 : 940013158
 +3 : 1314500282
 +4 : 1686544716
 +2 : 1656482812
 +1 : 1674985287
 +2 : 1848274264
 +3 : 585388171
 +4 : 323490420
 +4 : 593702477
 +3 : 426315791
 +2 : 1722007381
 +1 : 1750549071
 +*/
 </code> </code>
  
Line 83: Line 132:
 Implements class-based object scoped PRNG into PHP. Implements class-based object scoped PRNG into PHP.
  
-First, implement the following interface. This is a hypothetical PHP code.+First, implement the following interface. This is a hypothetical PHP code.' 
 + 
 +Basically, this interface are supposed to be used as arguments to one of the functions. In other words, the next() and next64() methods are not intended to be called directly. next64() returns an invalid value in a 32-bit environment.
  
 <code php> <code php>
Line 105: Line 156:
 namespace RNG; namespace RNG;
  
-class XorShift128Plus implements RNGInterface {} // Fast modern PRNG. +class XorShift128Plus implements RNGInterface // Fast modern PRNG. 
-class MT19937 implements RNGInterface {} // Completely consistent \mt_srand() and \mt_rand() implementation. +
-class OS implements RNGInterface {} // Cryptographically Secure PRNG.+    public function __construct(int $seed) {} 
 +    public function next(): int {} 
 +    public function next64(): int {} 
 +    public function __serialize(): array {} 
 +    public function __unserialize(array $data): void {} 
 +
 + 
 +class MT19937 implements RNGInterface // Completely consistent \mt_srand() and \mt_rand() implementation. 
 +
 +    public function __construct(int $seed) {} 
 +    public function next(): int {} 
 +    public function next64(): int {} 
 +    public function __serialize(): array {} 
 +    public function __unserialize(array $data): void {} 
 +
 + 
 +class OS implements RNGInterface // // Cryptographically Secure PRNG. 
 +
 +    public function next(): int {} 
 +    public function next64(): int {} 
 +
 +</code> 
 + 
 +Some RNG implementations can serialize state using the standard PHP serialization methods (serialize() and unserialize() function). This is useful for the purpose of storing state. 
 + 
 +<code php> 
 +$rng = new RNG\XorShift128Plus(1234); 
 +  
 +\rng_next($rng); 
 +  
 +$serialized_string = \serialize($rng); 
 +  
 +$rng2 = \unserialize($serialized_string); 
 +  
 +\rng_next($rng) === rng_next($rng2); // true
 </code> </code>
  
Line 121: Line 206:
  
 Finally, implement a function that can generate values from RNGs, such as the mt_rand(), random_bytes() function. If the $unsigned argument is false, it will return the value generated by the RNG as is. Finally, implement a function that can generate values from RNGs, such as the mt_rand(), random_bytes() function. If the $unsigned argument is false, it will return the value generated by the RNG as is.
- 
-The rng_next64() function will throw a ValueError exception if 64-bit integer is not available on the platform. 
  
 <code php> <code php>
Line 133: Line 216:
 /** @throws ValueError */ /** @throws ValueError */
 function rng_next64(RNG\RNGInterface $rng, bool $unsigned = true): int {} // Generates 64bit random number function rng_next64(RNG\RNGInterface $rng, bool $unsigned = true): int {} // Generates 64bit random number
 +</code>
 +
 +The rng_next64() function will throw a ValueError exception if 64-bit integer is not available on the platform.
 +
 +This is for proper handling of next64() in a 32-bit environment and to improve interoperability with the mt_rand() function. The mt_rand() function performs a bit shift on the result and always returns an unsigned integer.
 +
 +<code php>
 +// If the second argument is true (default), rng_next() performs bit shifting like mt_rand() and always returns an unsigned integer.
 +\mt_srand(1234);
 +$mt_state = new \RNG\MT19937(1234);
 +\mt_rand() === \rng_next($mt_state); // true
 + 
 +// If false, it will return the value as is. This is exactly the same result as $rng->next().
 +\mt_rand() === \rng_next($mt_state, false); // false
 + 
 +// This is useful if you want to use the numbers generated by the RNG directly.
 +\rng_next(new \RNG\MT19937(1234), false) === 822569775; // true
 </code> </code>
  
Line 175: Line 275:
   * mt_rand()   * mt_rand()
  
-===== Proposed Voting Choices ===== +===== Vote ===== 
-Yes/No, requiring 2/3 majority+Voting opens 2021-04-01 and 2021-04-15 at 00:00:00 EDT. 2/3 required to accept.
  
-There are a few additional options for implementation. +<doodle title="Add object-scoped RNG" auth="zeriyoshi" voteType="single" closed="true">
- +
-<doodle title="Add object-scoped RNG" auth="user" voteType="single" closed="true">+
    * Yes    * Yes
    * No    * No
-</doodle> 
- 
-<doodle title="To which namespace should these classes and interfaces belong?" auth="user" voteType="single" closed="true"> 
-   * Top Level (\RNGInterface, \XorShift128Plus) 
-   * "RNG" namespace (\RNG\RNGInterface, \RNG\XorShift128Plus) 
-   * "PHP\RNG" namespace (\PHP\RNG\RNGInterface, \PHP\RNG\XorShift128Plus) 
 </doodle> </doodle>
  
 ===== Patches and Tests ===== ===== Patches and Tests =====
   * https://github.com/php/php-src/pull/6568   * https://github.com/php/php-src/pull/6568
rfc/object_scope_prng.1611683204.txt.gz · Last modified: 2021/01/26 17:46 by zeriyoshi