PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 2.5.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v2.5.0
2.5.0 2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 All 34 releases
← All changes | vendor/wpfluent/framework/src/WPFluent/Randomizer/Randomizer.php +78 -29 1.7.1 → 2.5.0 View file →
@@ -2,9 +2,9 @@
2 2
3 3 namespace FluentBooking\Framework\Randomizer;
4 4
5 5 use Exception;
6 -use InvalidArgumentException;
6 +use FluentBooking\Framework\Support\InvalidArgumentException;
7 7
8 8 /**
9 9 * An implementation of the Randomizer class.
10 10 * @see https://www.php.net/manual/en/class.random-randomizer.php
@@ -9,8 +9,20 @@
9 9 * An implementation of the Randomizer class.
10 10 * @see https://www.php.net/manual/en/class.random-randomizer.php
11 11 */
12 12 if (class_exists('Random\Randomizer')) {
13 + /**
14 + * Wrapper around the native PHP 8.2+ Random\Randomizer.
15 + *
16 + * @method string getBytes(int $length)
17 + * @method int getInt(int $min, int $max)
18 + * @method float getFloat(float $min, float $max)
19 + * @method int nextInt()
20 + * @method float nextFloat()
21 + * @method array pickArrayKeys(array $array, int $num)
22 + * @method array shuffleArray(array $array)
23 + * @method string shuffleBytes(string $string)
24 + */
13 25 final class Randomizer
14 26 {
15 27 use GetStringTrait;
16 28
@@ -17,8 +29,9 @@
17 29 private $randomizer;
18 30
19 31 public function __construct()
20 32 {
33 + // @phpstan-ignore-next-line
21 34 $this->randomizer = new \Random\Randomizer();
22 35 }
23 36
24 37 public function getBytesFromString(string $string, int $length): string
@@ -56,9 +69,9 @@
56 69
57 70 public function getBytesFromString(string $string, int $length)
58 71 {
59 72 if ($length === 0) {
60 - throw new ValueError('Length cannot be zero.');
73 + throw new InvalidArgumentException('Length cannot be zero.');
61 74 }
62 75
63 76 $sourceLength = strlen($string);
64 77
@@ -79,23 +92,48 @@
79 92 }
80 93
81 94 public function getFloat(float $min, float $max)
82 95 {
83 - if ($min >= $max) {
84 - throw new InvalidArgumentException(
85 - 'The minimum value must be less than the maximum value.'
96 + // Match native Random\Randomizer::getFloat — allow $min == $max
97 + // (returns $min); only reject $min > $max.
98 + if ($min > $max) {
99 + $this->throwInvalidRange(
100 + 'Argument #1 ($min) must be less than or equal to argument #2 ($max).'
86 101 );
87 102 }
88 103
89 - $randomFraction = $this->nextFloat();
104 + // When $min == $max, the formula naturally returns $min
105 + // (anything * 0 == 0), so no special case needed.
106 + return $min + ($this->nextFloat() * ($max - $min));
107 + }
90 108
91 - return $min + ($randomFraction * ($max - $min));
109 + public function getInt(int $min, int $max)
110 + {
111 + // Match native Random\Randomizer::getInt — throw on $min > $max
112 + // and delegate to random_int (which already handles the range
113 + // correctly, rejection-sampled, no manual offset arithmetic).
114 + if ($min > $max) {
115 + $this->throwInvalidRange(
116 + 'Argument #1 ($min) must be less than or equal to argument #2 ($max).'
117 + );
118 + }
119 +
120 + return random_int($min, $max);
92 121 }
93 122
94 - public function getInt(int $min, int $max)
123 + /**
124 + * Throw the same exception type the native Random\Randomizer would
125 + * throw on bad range input. \ValueError landed in PHP 8.0; on older
126 + * runtimes fall back to InvalidArgumentException so we always raise
127 + * something meaningful.
128 + */
129 + private function throwInvalidRange(string $message)
95 130 {
96 - $range = $max - $min + 1;
97 - return $min + random_int(0, $range - 1);
131 + if (class_exists('ValueError', false)) {
132 + throw new \ValueError($message);
133 + }
134 +
135 + throw new InvalidArgumentException($message);
98 136 }
99 137
100 138 public function nextFloat()
101 139 {
@@ -108,25 +146,37 @@
108 146 }
109 147
110 148 public function pickArrayKeys(array $array, int $num)
111 149 {
112 - if ($num > count($array)) {
150 + $count = count($array);
151 +
152 + if ($num < 1 || $num > $count) {
113 153 throw new InvalidArgumentException(
114 - 'Cannot pick more keys than the array size.'
154 + 'Argument #2 ($num) must be between 1 and the number of elements in argument #1 ($array).'
115 155 );
116 156 }
117 157
118 - $pickedKeys = [];
119 -
158 + // Match native Random\Randomizer::pickArrayKeys — picked keys
159 + // are returned in their ORIGINAL position order in the array,
160 + // not in pick order. Strategy: build an index list, partial
161 + // Fisher-Yates to select $num indices, then sort those indices
162 + // and map back to keys. Runs in O(n) time.
120 163 $keys = array_keys($array);
164 + $indices = range(0, $count - 1);
121 165
122 - while (count($pickedKeys) < $num) {
123 - $index = random_int(0, count($keys) - 1);
124 - $pickedKeys[] = $keys[$index];
125 - array_splice($keys, $index, 1);
166 + // Partial Fisher-Yates: only shuffle the first $num positions.
167 + for ($i = 0; $i < $num; $i++) {
168 + $j = random_int($i, $count - 1);
169 + [$indices[$i], $indices[$j]] = [$indices[$j], $indices[$i]];
126 170 }
127 171
128 - return $pickedKeys;
172 + // Take the picked indices, sort to restore original order.
173 + $picked = array_slice($indices, 0, $num);
174 + sort($picked);
175 +
176 + return array_map(static function ($i) use ($keys) {
177 + return $keys[$i];
178 + }, $picked);
129 179 }
130 180
131 181 public function shuffleArray(array $array)
132 182 {
@@ -135,18 +185,17 @@
135 185 if ($count < 2) {
136 186 return $array;
137 187 }
138 188
139 - $originalArray = $array;
140 -
141 - // Shuffle and check if the result is different
142 - do {
143 - // Perform the Fisher-Yates shuffle
144 - for ($i = $count - 1; $i > 0; $i--) {
145 - $j = random_int(0, $i);
146 - [$array[$i], $array[$j]] = [$array[$j], $array[$i]];
147 - }
148 - } while ($array === $originalArray);
189 + // Match native Random\Randomizer::shuffleArray — a single
190 + // unbiased Fisher-Yates pass. Do NOT loop until the result
191 + // differs from the input; that biases the distribution and
192 + // can infinite-loop on tiny arrays. A fair shuffle MUST be
193 + // allowed to occasionally produce the original order.
194 + for ($i = $count - 1; $i > 0; $i--) {
195 + $j = random_int(0, $i);
196 + [$array[$i], $array[$j]] = [$array[$j], $array[$i]];
197 + }
149 198
150 199 return $array;
151 200 }
152 201