RandomToFile::genBigRange()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace ierusalim\Random;
4
5
/**
6
 * This class contains RandomToFile
7
 *
8
 * PHP Version 5.6
9
 *
10
 * @package    ierusalim\RandomToFile
11
 * @author     Alexander Jer <[email protected]>
12
 * @copyright  2017, Ierusalim
13
 * @license    https://opensource.org/licenses/Apache-2.0 Apache-2.0
14
 */
15
class RandomToFile extends RandomArray
16
{
17
    /**
18
     * Function for processing data and output to a file
19
     *
20
     * @var callable
21
     */
22
    public $fn_file_output;
23
    
24
    /**
25
     * File name for data output
26
     *
27
     * @var string
28
     */
29
    public $full_file_name;
30
    
31
    /**
32
     * Handler of file opened for write
33
     *
34
     * @var resource|null
35
     */
36
    public $file_handler;
37
    
38
    /**
39
     * Default extention for make file names
40
     *
41
     * @var string
42
     */
43
    public $default_ext = '.json';
44
45
    /**
46
     * Main parameter of this class - function for processing and write data
47
     * By default, this hook is set as a function 'writeFileOutputExample',
48
     * which does the following function: output PHP code for assigning array.
49
     * By analogy, write the necessary output functions for the desired format
50
     *
51
     * @param callable|null $fn_write
52
     */
53
    public function __construct(callable $fn_write = null)
54
    {
55
        parent::__construct();
56
        if (is_null($fn_write)) {
57
            $this->fn_file_output = [$this, 'writeFileOutputExample'];
58
            $this->default_ext = '.php';
59
        } else {
60
            $this->fn_file_output = $fn_write;
61
        }
62
    }
63
64
    public function writeFileOutputExample($parr)
65
    {
66
        static $keys = [];
67
68
        //extracting following work variables:
69
        \extract($parr); //$signal, $k, $v, $lim_depth, $root
70
71
        //begin formin output string
72
        $out_str = '$x';
73
74
        switch ($signal) {
75
            //siglan 'next' - when output next scalar element of array [$k]=>$v
76
            case 'next':
77
                if (!\is_numeric($k)) {
78
                    $k = "'" . \addcslashes($k, "'\\") . "'";
79
                }
80
                if (!\is_numeric($v)) {
81
                    $v = "'" . \addcslashes($v, "'\\") . "'";
82
                }
83
                $out_str .= (count($keys) ?
84
                    '[' . implode('][', $keys) . ']'
85
                    :
86
                    ''
87
                    ) . '[' . $k . ']=' . $v . ";\r\n";
88
89
                break;
90
            
91
            //signal 'open' - when root or nested array beginning
92
            case 'open':
93
                if (count($keys) || !empty($root)) {
94
                    //nested array beginned
95
                    if (!is_numeric($root)) {
96
                        $root = "'" . \addcslashes($root, "'\\") . "'";
97
                    }
98
                    array_push($keys, $root);
99
                    $out_str .= '[' . implode('][', $keys) . ']';
100
                    $out_str .= "=[]; /* Create sub-array in key $out_str */\r\n";
101
                } else {
102
                    //root array beginned
103
                    $out_str .= "=[]; /* CREATE ROOT OF ARRAY */\r\n";
104
                    $out_str = '<' . "?php\n" . $out_str;
105
                }
106
                break;
107
                
108
            //signal 'close' - when root or nested array ended
109
            case 'close':
110
                if (count($keys)) {
111
                    //nested array ended
112
                    $out_str = "/* end $out_str"
113
                                .'[' . \implode('][', $keys) . ']'
114
                                . "*/\r\n";
115
                    \array_pop($keys);
116
                } else {
117
                    //root array ended
118
                    $out_str = " /*  END OF ARRAY */\r\n";
119
                }
120
                break;
121
122
            //signal 'init' - when file open for write
123
            case 'init':
124
                $keys = [];
125
                $out_str = '';
126
        }
127
        //write formed string to output file
128
        \fwrite($fh, $out_str);
129
    }
130
    
131
    public function genRandomToFile(
132
        $min_elem_cnt = 3,
133
        $max_elem_cnt = 10,
134
        $threshold = 32768,
135
        $lim_depth = 3,
136
        $lim_elements = 10000,
137
        $root = ''
138
    ) {
139
        if ($lim_elements) {
140
            $this->lim_elements = $lim_elements;
141
        }
142
        if ($lim_depth < 1
143
            || $this->lim_elements < 0
144
            || $this->max_arr_key < 0
145
            || $this->max_arr_key < $this->min_arr_key
146
            || $this->max_arr_val < 0
147
            || $this->max_arr_val < $this->min_arr_val
148
        ) {
149
            return false;
150
        }
151
        
152
        if (!$oh = $fh = $this->file_handler) {
153
            $this->openOutputFile();
154
            $fh = $this->file_handler;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->file_handler can also be of type false. However, the property $file_handler is declared as type null|resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
155
            $signal = 'init';
156
            \call_user_func($this->fn_file_output,
157
                \compact('signal', 'fh', 'threshold', 'lim_depth', 'root')
158
            );
159
        }
160
161
        $elem_cnt = mt_rand($min_elem_cnt, $max_elem_cnt);
162
        if ($elem_cnt > $this->lim_elements) {
163
            $elem_cnt = $this->lim_elements;
164
        }
165
166
        $this->lim_elements -= $elem_cnt;
167
        
168
        $signal = 'open';
169
        \call_user_func($this->fn_file_output,
170
            \compact('signal', 'fh', 'elem_cnt', 'lim_depth', 'root')
171
        );
172
         
173
        $signal = 'next';
174
175
        foreach ($this->genBigRange($elem_cnt) as $k => $v) {
176
            if ($this->keys_model) {
177
                if ($this->keys_model === 3) {
178
                    $k = \call_user_func($this->fn_gen_key,
179
                        \compact('k', 'v', 'threshold', 'lim_depth', 'root')
180
                        );
181
                } else {
182
                    $k = \mt_rand($this->min_arr_key, $this->max_arr_key);
183
                    if ($this->keys_model === 2) {
184
                        $k = $this->genRandomStr($k, 1);
185
                    }
186
                }
187
            }
188
            
189
            if ($v > $threshold || $lim_depth < 2 || $this->lim_elements < 2) {
190
                if ($this->values_model) {
191
                    if ($this->values_model == 3) {
192
                        $v = \call_user_func($this->fn_gen_value,
193
                            \compact('k', 'v', 'threshold', 'lim_depth', 'root')
194
                        );
195
                    } else {
196
                        $v = mt_rand($this->min_arr_val, $this->max_arr_val);
197
                        if ($this->values_model == 2) {
198
                            $v = $this->genRandomStr($v, 2);
199
                        }
200
                    }
201
                }
202
            } else {
203
                $this->genRandomToFile(
204
                    $min_elem_cnt,
205
                    $max_elem_cnt,
206
                    $threshold,
207
                    $lim_depth - 1,
208
                    0,
209
                    $k
210
                );
211
                continue;
212
            }
213
214
            \call_user_func($this->fn_file_output,
215
                \compact('signal', 'k', 'v', 'fh', 'lim_depth', 'root')
216
            );
217
        }
218
219
        $signal = 'close';
220
            \call_user_func($this->fn_file_output,
221
            \compact('signal', 'fh', 'elem_cnt', 'lim_depth', 'root')
222
            );
223
224
        if (!$oh) {
0 ignored issues
show
introduced by
$oh is of type null|resource, thus it always evaluated to false.
Loading history...
225
            $this->closeOutputFile();
226
        }
227
        return true;
228
    }
229
230
    public function genBigRange($total_elements)
231
    {
232
        for ($k = 1; $k <= $total_elements; $k++) {
233
            $v = \mt_rand(0, 65535);
234
            yield $k => $v;
235
        }
236
    }
237
238
    public function genTempFileName($ext = null, $test_exception = false)
239
    {
240
        $file_name = \sys_get_temp_dir() . \DIRECTORY_SEPARATOR . 'genRandom';
241
        if ($test_exception || (!is_dir($file_name) && !\mkdir($file_name))) {
242
            throw new \Exception("Can't mkdir $file_name for random file");
243
        }
244
        if (is_null($ext)) {
245
            $ext = $this->default_ext;
246
        }
247
        $file_name .= DIRECTORY_SEPARATOR . md5(microtime()) . $ext;
248
        return $file_name;
249
    }
250
251
    public function setOutputFile($file_name = null, $ext = null)
252
    {
253
        if (empty($file_name) || !is_string($file_name)) {
254
            if (is_null($ext)) {
255
                $ext = $this->default_ext;
256
            }
257
            $file_name = $this->genTempFileName($ext);
258
        }
259
        return $this->full_file_name = $file_name;
260
    }
261
262
    public function openOutputFile()
263
    {
264
        if (!$this->file_handler = @\fopen($this->full_file_name, 'w')) {
0 ignored issues
show
Documentation Bug introduced by
It seems like @fopen($this->full_file_name, 'w') can also be of type false. However, the property $file_handler is declared as type null|resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
265
            throw new \Exception("Error write file " . $this->full_file_name);
266
        }
267
        return $this->file_handler;
268
    }
269
270
    public function closeOutputFile()
271
    {
272
        if ($this->file_handler) {
273
            \fclose($this->file_handler);
274
            $this->file_handler = false;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type null|resource of property $file_handler.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
275
        }
276
    }
277
}
278