Issues (12)

src/RandomArray.php (3 issues)

1
<?php
2
3
namespace ierusalim\Random;
4
5
/**
6
 * This class RandomArray is intended for generating Random Arrays
7
 *
8
 * PHP Version 5.6
9
 *
10
 * @package    ierusalim\RandomArray
11
 * @author     Alexander Jer <[email protected]>
12
 * @copyright  2017, Ierusalim
13
 * @license    https://opensource.org/licenses/Apache-2.0 Apache-2.0
14
 *
15
 * Examples of use:
16
 *  Initialize:
17
 *    $g = new RandomArray();
18
 *
19
 *  //Generate random array with default parameters:
20
 *    $arr = $g->genRandomArray();
21
 *    print_r($arr);
22
 *
23
 *  //Generate random array with string keys from listed chars, 3-9 chars length
24
 *    $g->setKeysModel(3,9,'abcdefghijklmnopqrstuvwxyz');
25
 *    $g->setValuesModel(0,100); //random numeric values range from 0 to 100
26
 *    $arr = $g->genRandomArray(10,15,0); //generate 10-15 elements (not nested)
27
 *    print_r($arr);
28
 *
29
 */
30
class RandomArray extends RandomStr
31
{
32
    /**
33
     * Set this limit to avoid generation unexpected too large arrays
34
     *
35
     * @var integer
36
     */
37
    public $lim_elements = 10000;
38
    
39
     /**
40
     * Model number for generation random Keys for Arrays
41
     * if 0 then array keys will be simple 1,2,3... numeric
42
     * if 1 then array keys will be numeric from min_arr_key to max_arr_key
43
     * if 2 then array keys will be string len from min_arr_key to max_arr_key
44
     * This value setting by function setKeysModel()
45
     *
46
     * @var integer
47
     */
48
    protected $keys_model;
49
50
    /**
51
     * Model number for generation random Values for Arrays
52
     * if 0 then array values will be numeric from 0 to 65535
53
     * if 1 then array values will be numeric from min_arr_val to max_arr_val
54
     * if 2 then array values will be string len from min_arr_val to max_arr_val
55
     *  This value setting by function setValuesModel()
56
     *
57
     * @var integer
58
     */
59
    protected $values_model;
60
    
61
    /**
62
     * Value for generation random Keys for Arrays
63
     * This is minimal number for random numbers generation,
64
     * or minimal length of string for random string array-keys generation
65
     * This value setting by function setValuesModel()
66
     *
67
     * @var integer
68
     */
69
    protected $min_arr_key;
70
71
    /**
72
     * Value for generation random Keys for Arrays
73
     * This is maximal number for random numbers generation,
74
     * or maximal length of string for random string array-keys generation
75
     * This value setting by function setKeysModel()
76
     *
77
     * @var integer
78
     */
79
    protected $max_arr_key;
80
81
    /**
82
     * Value for generation random Values for Arrays
83
     * This is minimal number for random numbers generation,
84
     * or minimal length of string for random string array-values generation
85
     * This value setting by function setValuesModel()
86
     *
87
     * @var integer
88
     */
89
    protected $min_arr_val;
90
    
91
    /**
92
     * Value for generation random Values for Arrays
93
     * This is maximal number for random numbers generation,
94
     * or maximal length of string for random string array-values generation
95
     *
96
     * @var integer
97
     */
98
    protected $max_arr_val;
99
    
100
    /**
101
     * Value generate function
102
     * calling if values_model == 3
103
     *
104
     * @var callable
105
     */
106
    public $fn_gen_value;
107
    
108
    /**
109
     * Key generate function
110
     * calling if keys_model == 3
111
     *
112
     * @var callable
113
     */
114
    public $fn_gen_key;
115
116
    /**
117
     * Init parameter - string of chars for generation array values
118
     * Prefer to leave blank and use function setValuesModel for set it.
119
     *
120
     * @param string|null $init_charset_for_val
121
     */
122
    public function __construct($init_charset_for_val = null, $utf8mode = false)
123
    {
124
        parent::__construct($init_charset_for_val, $utf8mode);
125
        $this->setKeysModel();
126
        if (\is_null($init_charset_for_val)) {
127
            $this->setValuesModel(1, 16, $this->char_sets[0]);
128
        } else {
129
            $this->setValuesModel(1, 16, $init_charset_for_val);
130
        }
131
    }
132
133
    /**
134
     * Counting all values in array (recursive)
135
     *
136
     * @param array   $arr
137
     * @param integer $cnt
138
     *
139
     * @return integer
140
     */
141
    public function countArrayValuesRecursive(&$arr, $cnt = 0)
142
    {
143
        \array_walk_recursive($arr, function ($v, $k) use (&$cnt) {
0 ignored issues
show
The parameter $v is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

143
        \array_walk_recursive($arr, function (/** @scrutinizer ignore-unused */ $v, $k) use (&$cnt) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $k is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

143
        \array_walk_recursive($arr, function ($v, /** @scrutinizer ignore-unused */ $k) use (&$cnt) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
144
            $cnt++;
145
        });
146
        return $cnt;
147
    }
148
    
149
    /**
150
     * Counting the maximum depth of nesting of arrays in an array (recursive)
151
     *
152
     * @param array $arr
153
     * @param integer $c_depth
154
     *
155
     * @return integer
156
     */
157
    public function countArrayMaxDepth($arr, $c_depth = 0)
158
    {
159
        if (!is_array($arr)) {
160
            return false;
161
        }
162
        $m_depth = $c_depth;
163
        \array_walk($arr, function ($v, $k) use ($c_depth, &$m_depth) {
0 ignored issues
show
The parameter $k is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

163
        \array_walk($arr, function ($v, /** @scrutinizer ignore-unused */ $k) use ($c_depth, &$m_depth) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
164
            if (is_array($v)) {
165
                $new_depth = $this->countArrayMaxDepth($v, $c_depth+1);
166
                if ($new_depth > $m_depth) {
167
                    $m_depth = $new_depth;
168
                }
169
            }
170
        });
171
        return $m_depth;
172
    }
173
    
174
    /**
175
     * Set model for generation keys for random arrays
176
     *
177
     * @param integer      $min
178
     * @param integer      $max
179
     * @param string|null  $chars
180
     */
181
    public function setKeysModel(
182
        $min = 1,
183
        $max = null,
184
        $chars = null,
185
        $utf8mode = false
186
    ) {
187
        if (empty($chars)) {
188
            //Numeric keys model
189
            $this->keys_model = 1;
190
            if ($min == 1 && (\is_null($max))) {
191
                //Non-changes key model (numeric 0,1,2...)
192
                $this->keys_model = 0;
193
            }
194
            if (\is_null($max)) {
195
                $max = 65535;
196
            }
197
        } else {
198
            //Random-string keys model
199
            $this->keys_model = 2;
200
            //set $chars as charset number 1
201
            $this->char_sets[1] = $chars;
202
            if ($utf8mode) {
203
                $this->explodeUtf8();
204
            }
205
        }
206
        $this->min_arr_key = $min;
207
        $this->max_arr_key = is_null($max) ? 16 : $max;
208
    }
209
    
210
    /**
211
     * Set model for generation values for random arrays
212
     *
213
     * @param integer     $min
214
     * @param integer     $max
215
     * @param string|null $chars
216
     */
217
    public function setValuesModel(
218
        $min = 0,
219
        $max = 65535,
220
        $chars = null,
221
        $utf8mode = false
222
    ) {
223
        if (empty($chars)) {
224
            //Numeric values model
225
            $this->values_model = 1;
226
            if (!$min && $max==65535) {
227
                //Non-changes values model (random number from 0 to 65535)
228
                $this->values_model=0;
229
            }
230
        } else {
231
            //Random-string values model
232
            $this->values_model = 2;
233
            //set $chars as charset number 2
234
            $this->char_sets[2] = $chars;
235
            if ($utf8mode) {
236
                $this->explodeUtf8();
237
            }
238
        }
239
        $this->min_arr_val = $min;
240
        $this->max_arr_val = $max;
241
    }
242
    
243
    /**
244
     * Set function for generate values for random array
245
     *
246
     * @param callable $gen_fn
247
     */
248
    public function setValuesModelFn(callable $gen_fn)
249
    {
250
        $this->values_model = 3;
251
        $this->fn_gen_value = $gen_fn;
252
    }
253
254
    /**
255
     * Set function for generate keys for random array
256
     *
257
     * @param callable $gen_fn
258
     */
259
    public function setKeysModelFn(callable $gen_fn)
260
    {
261
        $this->keys_model = 3;
262
        $this->fn_gen_key = $gen_fn;
263
    }
264
265
    /**
266
     * Random Array generate
267
     *
268
     * Parameters $min_elem_cnt and $max_elem_cnt define the minimum and
269
     *   maximum number of elements of generated arrays
270
     *
271
     * Parameter $theshold define chance of generating scalar or nested array
272
     * If 0 is specified, scalar will always be generated, never nested array
273
     * if 65535 specified, nested array will be generated until reach $lim_depth
274
     * if 32768 specified the probability of generating array or scalar is 50/50
275
     * Only scalar generate if the depth of array nesting reached $lim_depth
276
     *
277
     * No more than $lim_elements of elements will be generated total
278
     *
279
     * @param integer $min_elem_cnt Min.count of elements in array (and nested)
280
     * @param integer $max_elem_cnt Max.count of elements in array (and nested)
281
     * @param integer $threshold Chance array or string generation (0-65535)
282
     * @param integer $lim_depth Depth limit of nesting arrays
283
     * @param integer $lim_elements Limit number of generated elements
284
     * @param string  $root Key of this array (may be needed for nested arrays)
285
     *
286
     * @return array
287
     */
288
    public function genRandomArray(
289
        $min_elem_cnt = 3,
290
        $max_elem_cnt = 10,
291
        $threshold = 32768,
292
        $lim_depth = 3,
293
        $lim_elements = 10000,
294
        $root = ''
295
    ) {
296
        if ($lim_elements) {
297
            $this->lim_elements = $lim_elements;
298
        }
299
        if ($lim_depth<1
300
            || $this->lim_elements < 0
301
            || $this->max_arr_key < 0
302
            || $this->max_arr_key < $this->min_arr_key
303
            || $this->max_arr_val < 0
304
            || $this->max_arr_val < $this->min_arr_val
305
        ) {
306
            return false;
307
        }
308
309
        $elem_cnt = mt_rand($min_elem_cnt, $max_elem_cnt);
310
        if ($elem_cnt > $this->lim_elements) {
311
            $elem_cnt = $this->lim_elements;
312
        }
313
        $r_arr = [];
314
        $gen_arr = \unpack('v*', \call_user_func($this->rnd_fn, $elem_cnt*2));
315
        $this->lim_elements-=$elem_cnt;
316
        
317
        foreach ($gen_arr as $k => $v) {
318
            if ($v > $threshold || $lim_depth<2 || $this->lim_elements <2) {
319
                if ($this->values_model) {
320
                    if ($this->values_model == 3) {
321
                        $v = \call_user_func($this->fn_gen_value,
322
                            \compact('k', 'v', 'threshold', 'lim_depth', 'root')
323
                        );
324
                    } else {
325
                        $v = mt_rand($this->min_arr_val, $this->max_arr_val);
326
                        if ($this->values_model == 2) {
327
                            $v = $this->genRandomStr($v, 2);
328
                        }
329
                    }
330
                } else {
331
                    if (!$this->keys_model) {
332
                        continue;
333
                    }
334
                }
335
            } else {
336
                $v = $this->genRandomArray(
337
                    $min_elem_cnt,
338
                    $max_elem_cnt,
339
                    $threshold,
340
                    $lim_depth - 1,
341
                    0
342
                );
343
            }
344
            if ($this->keys_model) {
345
                if ($this->keys_model === 3) {
346
                    $k = \call_user_func($this->fn_gen_key,
347
                            \compact('k', 'v', 'threshold', 'lim_depth', 'root')
348
                        );
349
                } else {
350
                    $k = \mt_rand($this->min_arr_key, $this->max_arr_key);
351
                    if ($this->keys_model === 2) {
352
                        $k = $this->genRandomStr($k, 1);
353
                    }
354
                }
355
                $r_arr[$k] = $v;
356
            } else {
357
                $gen_arr[$k] = $v;
358
            }
359
        }
360
        
361
        return $this->keys_model ? $r_arr : $gen_arr;
362
    }
363
}
364