Passed
Branch master (df288f)
by Tony Karavasilev (Тони
02:30
created

PseudoRandom   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 187
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 18
eloc 40
c 1
b 0
f 0
dl 0
loc 187
ccs 47
cts 47
cp 1
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A validateSeedValue() 0 20 2
A getInt() 0 8 3
A setSeed() 0 24 4
A getMinNumber() 0 3 1
A getEightBits() 0 9 2
A getInteger() 0 3 1
A getMaxNumber() 0 3 1
A __construct() 0 6 2
A getBytes() 0 5 1
A __debugInfo() 0 5 1
1
<?php
2
3
/**
4
 * The pseudo-random generator class.
5
 */
6
7
namespace CryptoManana\Randomness;
8
9
use \CryptoManana\Core\Abstractions\Randomness\AbstractGenerator as RandomnessSource;
10
use \CryptoManana\Core\Interfaces\Randomness\SeedableGeneratorInterface as SeedAction;
11
use \CryptoManana\Core\StringBuilder as StringBuilder;
12
13
/**
14
 * Class PseudoRandom - The pseudo-random generator object.
15
 *
16
 * @package CryptoManana\Randomness
17
 */
18
class PseudoRandom extends RandomnessSource implements SeedAction
19
{
20
    /**
21
     * The initialization seed value property storage for all instances.
22
     *
23
     * @var bool|int The generator's seed value.
24
     */
25
    protected static $seed = false;
26
27
    /**
28
     * Validates the the given seed value and converts it to an integer.
29
     *
30
     * @param int|mixed $seed The initialization value.
31
     *
32
     * @return int The valid initialization value.
33
     * @throws \Exception Validation errors.
34
     */
35 22
    protected static function validateSeedValue($seed)
36
    {
37 22
        $seed = filter_var(
38 22
            $seed,
39 22
            FILTER_VALIDATE_INT,
40
            [
41
                "options" => [
42 22
                    "min_range" => -mt_getrandmax() - 1,
43 22
                    "max_range" => mt_getrandmax(),
44
                ],
45
            ]
46
        );
47
48 22
        if ($seed === false) {
49 2
            throw new \DomainException(
50 2
                "The provided seed value is of invalid type or is out of the supported range."
51
            );
52
        }
53
54 22
        return $seed;
55
    }
56
57
    /**
58
     * Internal static method for single point consumption of the randomness source that outputs integers.
59
     *
60
     * @param int $minimum The lowest value to be returned.
61
     * @param int $maximum The highest value to be returned.
62
     *
63
     * @return int Randomly generated integer number.
64
     */
65 38
    protected static function getInteger($minimum, $maximum)
66
    {
67 38
        return mt_rand($minimum, $maximum);
68
    }
69
70
    /**
71
     * Internal static method for single point consumption of the randomness source that outputs bytes.
72
     *
73
     * @param int $count The output string length based on the requested number of bytes.
74
     *
75
     * @return string Randomly generated string containing the requested number of bytes.
76
     */
77 20
    protected static function getEightBits($count)
78
    {
79 20
        $tmpBytes = '';
80
81 20
        for ($i = 1; $i <= $count; $i++) {
82 20
            $tmpBytes .= StringBuilder::getChr(self::getInteger(0, 255));
83
        }
84
85 20
        return $tmpBytes;
86
    }
87
88
    /**
89
     * The maximum supported integer.
90
     *
91
     * @return int The upper integer generation border.
92
     */
93 50
    public function getMaxNumber()
94
    {
95 50
        return mt_getrandmax();
96
    }
97
98
    /**
99
     * The minimum supported integer.
100
     *
101
     * @return int The lower integer generation border.
102
     */
103 52
    public function getMinNumber()
104
    {
105 52
        return -mt_getrandmax() - 1;
106
    }
107
108
    /**
109
     * The pseudo-random generator constructor.
110
     *
111
     * Note: This type of generator is auto-seeded on the first object creation.
112
     */
113 82
    public function __construct()
114
    {
115 82
        parent::__construct();
116
117 82
        if (self::$seed === false) {
118 2
            self::setSeed();
119
        }
120 82
    }
121
122
    /**
123
     * Seed the generator initialization or invoke auto-seeding.
124
     *
125
     * Note: Invokes auto-seeding if the `null` value is passed.
126
     *
127
     * @param null|int $seed The initialization value.
128
     *
129
     * @throws \Exception Validation errors.
130
     */
131 24
    public static function setSeed($seed = null)
132
    {
133 24
        if (!is_null($seed)) {
134 22
            $seed = self::validateSeedValue($seed);
135
        } else {
136
            // Get time information
137 4
            list($microSeconds, $seconds) = explode(' ', microtime());
138
139
            // Get microseconds as integer first
140 4
            $seed = (int)($microSeconds * 1000000) - 1;
141
142
            // A 32bit integer overflow  workaround for the UNIX timestamp format
143 4
            $seed = (PHP_MAJOR_VERSION === 5) ? abs($seconds - $seed) : $seconds + $seed;
144
        }
145
146 24
        $seed = (int)$seed;
147
148
        // Set the used seed value for history
149 24
        self::$seed = $seed;
150
151
        /**
152
         * {@internal Backward compatibility algorithm for seed must be used. }}
153
         */
154 24
        (PHP_VERSION_ID < 70100) ? mt_srand($seed) : mt_srand($seed, MT_RAND_PHP);
155 24
    }
156
157
    /**
158
     * Generate a random integer number in a certain range.
159
     *
160
     * Note: Passing `null` will use the default parameter value.
161
     *
162
     * @param null|int $from The lowest value to be returned (default => 0).
163
     * @param null|int $to The highest value to be returned (default => $this->getMaxNumber()).
164
     *
165
     * @return int Randomly generated integer number.
166
     * @throws \Exception Validation errors.
167
     */
168 44
    public function getInt($from = 0, $to = null)
169
    {
170 44
        $from = ($from === null) ? 0 : $from;
171 44
        $to = ($to === null) ? $this->getMaxNumber() : $to;
172
173 44
        $this->validateIntegerRange($from, $to);
174
175 34
        return self::getInteger($from, $to);
176
    }
177
178
    /**
179
     * Generate a random byte string.
180
     *
181
     * Note: PHP represents bytes as characters to make byte strings.
182
     *
183
     * @param int $length The output string length (default => 1).
184
     *
185
     * @return string Randomly generated string containing the requested number of bytes.
186
     * @throws \Exception Validation errors.
187
     */
188 22
    public function getBytes($length = 1)
189
    {
190 22
        $this->validatePositiveInteger($length);
191
192 20
        return self::getEightBits($length);
193
    }
194
195
    /**
196
     * Get debug information for the class instance.
197
     *
198
     * @return array Debug information.
199
     */
200 2
    public function __debugInfo()
201
    {
202
        return [
203 2
            'systemPrecision' => self::$systemPrecision,
204 2
            'seed' => self::$seed,
205
        ];
206
    }
207
}
208