rfc:rng_extension

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
Next revision Both sides next revision
rfc:rng_extension [2021/06/25 22:23]
zeriyoshi 2.0: Add Random Extension
rfc:rng_extension [2021/07/07 13:52]
zeriyoshi fix interface and drop C implementation stub, they're currently not fixed.
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 <zeriyoshi@gmail.com>   * Author: Go Kudo <zeriyoshi@gmail.com>
Line 45: Line 45:
 Implement and bundled Random extension into PHP. Implement and bundled Random extension into PHP.
  
-The phpstub for the whole extension is as follows:+The pseudo-implementation for the whole extension is as follows:
  
 <code php> <code php>
 +<?php
  
-/** @generate-class-entries */ +namespace Random 
-/** @generate-function-entries */+
 +    interface NumberGenerator 
 +    { 
 +        public function generate(): int; 
 +    } 
 +}
  
 namespace Random\NumberGenerator namespace Random\NumberGenerator
 { {
- interface RandomNumberGenerator +    class XorShift128Plus implements Random\NumberGenerator 
-+    
-     /**  +        public function __construct(?int $seed = null) {} 
- * @tentative-return-type +        public function generate(): int {} 
- * @internal +        public function __serialize(): array {} 
- */ +        public function __unserialize(array $data): void {} 
-    public function generate(): int; +    }
- }+
  
- class XorShift128Plus implements RandomNumberGenerator +    class MT19937 implements Random\NumberGenerator 
-+    
- /** @tentative-return-type */ +        public function __construct(?int $seed = null) {
- public function __construct(?int $seed = null) {}+        public function generate(): int {} 
 +        public function __serialize(): array {} 
 +        public function __unserialize(array $data): void {} 
 +    }
  
- /**  +    class Secure implements Random\NumberGenerator 
- * @tentative-return-type  +    
- * @internal +        public function __construct() {} 
- */ +        public function generate(): int {} 
- public function generate(): int {} +    }
- +
- /** @tentative-return-type */ +
- public function __serialize(): array {} +
- +
- /** @tentative-return-type */ +
- public function __unserialize(array $data): void {} +
-+
- +
- class MT19937 implements RandomNumberGenerator +
-+
-    /**  +
-    * @implementation-alias Random\NumberGenerator\XorShift128Plus::__construct  +
-     * @tentative-return-type +
-    */ +
-    public function __construct(?int $seed = null) {+
- +
-    /**  +
-    * @implementation-alias Random\NumberGenerator\XorShift128Plus::generate  +
-    * @tentative-return-type +
-    */ +
-     public function generate(): int {} +
- +
-    /**  +
-    * @implementation-alias Random\NumberGenerator\XorShift128Plus::__serialize +
-    * @tentative-return-type +
-    */ +
-    public function __serialize(): array {} +
- +
-    /**  +
-    * @implementation-alias Random\NumberGenerator\XorShift128Plus::__unserialize +
-    * @tentative-return-type +
-    */ +
-    public function __unserialize(array $data): void {} +
-+
- +
- class Secure implements RandomNumberGenerator +
-+
- /** @tentative-return-type */ +
- public function __construct() {} +
- +
- /**  +
- * @implementation-alias Random\NumberGenerator\XorShift128Plus::generate  +
- * @tentative-return-type +
- */ +
- public function generate(): int {} +
- }+
 } }
  
 namespace namespace
 { {
- interface RandomInterface +    final class Random 
-+    
- /** @tentative-return-type */ +        private Random\NumberGenerator $rng;
- public function nextInt(): int; +
- +
- /** @tentative-return-type */ +
- public function getInt(int $min, int $max): 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 __construct(?Random\NumberGenerator $rng = null) {} 
-+        public function getNumberGenerator(): Random\NumberGenerator {}
-        // FIXME: stub generator (gen_stub.php) does not supported. +
-        // private Random\NumberGenerator\RandomNumberGenerator $rng; +
-        private mixed $rng; +
- +
-        public function __construct(?Random\NumberGenerator\RandomNumberGenerator $rng = null) {} +
-        public function getNumberGenerator(): Random\NumberGenerator\RandomNumberGenerator {} +
-        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(): array {}         public function __serialize(): array {}
         public function __unserialize(array $data): void {}         public function __unserialize(array $data): void {}
- }+    }
 } }
  
 </code> </code>
  
-Each RNG is implemented as a class in the Random\NumberGenerator namespace. They all implement the Random\NumberGenerator\RandomNumberGenerator interface.+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, the upper 32 bits are always truncated. This means that compatibility cannot be maintained between platforms, but this is not a problem since most platforms running PHP today are 64-bit and MT19937 can be used explicitly if compatibility is required. However, when used XorShift128+ in a 32-bit environment, the upper 32 bits are always truncated. This means that compatibility cannot be maintained between platforms, but this is not a problem since most platforms running PHP today are 64-bit and MT19937 can be used explicitly if compatibility is required.
 +
 +Note that (new Random\NumberGenerator\MT19937($seed))->generate() requires an additional bit shift to get a result equivalent to mt_rand(). mt_rand() implicitly did the bit-shifting internally, but there was no obvious reason for this.
  
 Secure is practically equivalent to random_int() and random_bytes(), This is useful when secure array or string shuffling is required. Secure is practically equivalent to random_int() and random_bytes(), This is useful when secure array or string shuffling is required.
  
-This class also supports RNGs defined in userland. It can be used by passing an instance of a class that implements the RandomNumberGenerator interface provided at the same time as the first argument.This is useful for unit testing or when you want to use a fixed number.+This class also supports RNGs defined in userland. It can be used by passing an instance of a class that implements the Random\NumberGenerator interface provided at the same time as the first argument.This is useful for unit testing or when you want to use a fixed number.
  
 <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 $numberGenerator): void {
     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()); // Results: 123456789
 </code> </code>
  
 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, it will throws Exception.
-/* similar php_mt_rand() */ +
-uint64_t php_random_next(php_random *php_random, bool shift); +
- +
-/* similar php_mt_rand_range() */ +
-zend_long php_random_range(php_random *php_random, zend_long min, zend_long max); +
- +
-/* similar php_array_data_shuffle() */ +
-void php_random_array_data_shuffle(php_random *php_random, zval *array); +
- +
-/* similar php_string_shuffle() */ +
-void php_random_string_shuffle(php_random *php_random, char *str, zend_long len); +
-</code> +
- +
-The Random class can be serialized using the standard PHP serialization mechanism. But, if the $rng member is not serializable, it will always fail.+
  
 <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, PHP_INT_MAX); } 
-var_dump(unserialize(serialize($foo))->nextInt() === $foo->nextInt()); // true+var_dump(unserialize(serialize($foo))->getInt(PHP_INT_MIN, PHP_INT_MAX) === $foo->getInt(PHP_INT_MIN, PHP_INT_MAX)); // true
  
 // 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, PHP_INT_MAX); } 
-var_dump(unserialize(serialize($foo))->nextInt() === $foo->nextInt());+var_dump(unserialize(serialize($foo))->getInt(PHP_INT_MIN, PHP_INT_MAX) === $foo->getInt(PHP_INT_MIN, PHP_INT_MAX)); // throws Exception:  Serialization of CLASS is not allowed.
 </code> </code>
  
-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 new Random(new Random\NumberGenerator\MT19937($seed)); +    $numberGenerator = new Random\NumberGenerator\MT19937($seed); 
-    $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:
  
-  - "RandomInterface" +  "Random" 
-  - "Random" +  "Random\NumberGenerator" 
-  "Random\NumberGenerator\RandomNumberGenerator+  "Random\NumberGenerator\XorShift128Plus" 
-  "Random\NumberGenerator\XorShift128Plus" +  "Random\NumberGenerator\MT19937" 
-  "Random\NumberGenerator\MT19937" +  "Random\NumberGenerator\Secure"
-  "Random\NumberGenerator\Secure"+
  
 ===== 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