GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

I   F
last analyzed

Complexity

Total Complexity 82

Size/Duplication

Total Lines 418
Duplicated Lines 0 %

Test Coverage

Coverage 65.99%

Importance

Changes 30
Bugs 8 Features 0
Metric Value
eloc 154
c 30
b 8
f 0
dl 0
loc 418
rs 2
ccs 97
cts 147
cp 0.6599
wmc 82

15 Methods

Rating   Name   Duplication   Size   Complexity  
A def() 0 3 2
A isYii2() 0 3 1
A isEmpty() 0 3 1
A ini() 0 6 2
D get() 0 59 25
A displayErrors() 0 4 3
C setAlias() 0 39 13
A isWin() 0 3 1
B set() 0 19 7
A obj() 0 20 6
C getAlias() 0 36 12
A isExt() 0 6 3
A phpini() 0 3 3
A call() 0 5 2
A hasFlag() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like I often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use I, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Class I
4
 *
5
 * @link https://www.icy2003.com/
6
 * @author icy2003 <[email protected]>
7
 * @copyright Copyright (c) 2017, icy2003
8
 */
9
namespace icy2003\php;
10
11
use Exception;
12
use icy2003\php\ihelpers\Strings;
13
use ReflectionClass;
14
15
/**
16
 * I 类
17
 */
18
class I
19
{
20
21
    /**
22
     * 获取值
23
     *
24
     * 支持类型:数组对象和 null、数字和字符串、布尔值、回调函数,依据数据类型有不同的含义(但是都很合理)
25
     *
26
     * @param mixed $mixed 混合类型
27
     *      - 当 $mixed 为**数组或对象**时,此方法用于按照层级获取值,用法如下:
28
     *          1. 对于一个多维数组 $array 来说,a.b.cd_ef 会拿 $array['a']['b']['cd_ef'] 的值
29
     *          2. 如果 $array['a'] 是对象,则先检查 getB 方法,然后检查 b 属性
30
     *          3. 如果 $array['a']['b'] 是对象,则检查 getCdEf 方法,然后检查 cd_ef 属性
31
     *      - 当 $mixed 为**布尔值**(即表达式)时,等价于三元操作符,例如 I::get(1 > 2, '真', '假')
32
     *      - 当 $mixed 为**字符串**时,等价于 Strings::sub,截取字符串
33
     *      - 当 $mixed 为 **null** 时,含义可被描述为:在使用 I::get($array, 'a.b', 1),$array 意外的是 null,返回 1 是理所当然的
34
     *      - 当 $mixed 为**回调函数**,$mixed 的执行结果将作为 I::get 的返回值
35
     * @param mixed $keyString 取决于 $mixed 的类型:
36
     *      - 当 $mixed 为**数组或对象**时,$keyString 表示:点(.)分割代表层级的字符串,下划线用于对象中转化成驼峰方法,支持数组和对象嵌套
37
     *      - 当 $mixed 为**布尔值**(即表达式)时,$keyString 表示:$mixed 为 true 时返回的值
38
     *      - 当 $mixed 为**字符串**时,$keyString 强制转为整型,表示:截取 $mixed 时,子串的起始位置
39
     *      - 当 $mixed 为 **null** 时,此参数无效
40
     *      - 当 $mixed 为**回调函数**,如果 $mixed 的返回值代表 true(如:1),则执行此回调
41
     * @param mixed $defaultValue 取决于 $mixed 的类型:
42
     *      - 当 $mixed 为**数组或对象**时,$defaultValue 表示:拿不到值时会直接返回该默认值
43
     *      - 当 $mixed 为**布尔值**(即表达式)时,$defaultValue 表示:$mixed 为 false 时返回的值
44
     *      - 当 $mixed 为**字符串**时,$defaultValue 表示:截取 $mixed 时,子串的长度,null 时表示长度为 1
45
     *      - 当 $mixed 为 **null** 时,返回 $defaultValue
46
     *      - 当 $mixed 为**回调函数**,如果 $mixed 的返回值代表 false(如:0),则执行此回调
47
     *
48
     * @return mixed
49
     */
50 50
    public static function get($mixed, $keyString, $defaultValue = null)
51
    {
52 50
        if (is_bool($mixed)) { // 布尔类型
53 1
            return true === $mixed ? $keyString : $defaultValue;
54 50
        } elseif (is_callable($mixed)) { // 回调
55 1
            $result = self::call($mixed);
56 1
            if ($result) {
57 1
                self::call($keyString);
58
            } else {
59 1
                self::call($defaultValue);
60
            }
61 1
            return $result;
62 50
        } elseif (is_array($mixed) || is_object($mixed)) { // 数组和对象
63 50
            if (false === is_string($keyString) && is_callable($keyString)) {
64
                $mixed = self::call($keyString, [$mixed]);
65
            } else {
66 50
                // 如果是个常规数组,直接取值,只支持一维数组
67 50
                if (is_array($mixed) && array_key_exists($keyString, $mixed)) {
68 50
                    return $mixed[$keyString];
69 50
                }
70 49
                $keyArray = explode('.', $keyString);
71
                foreach ($keyArray as $key) {
72 50
                    if (is_array($mixed)) {
73
                        if (array_key_exists($key, $mixed) && null !== $mixed[$key]) {
74 2
                            $mixed = $mixed[$key];
75 2
                        } else {
76 2
                            return $defaultValue;
77 1
                        }
78 2
                    } elseif (is_object($mixed)) {
79 2
                        $method = 'get' . ucfirst(Strings::toCamel($key));
80
                        if (method_exists($mixed, $method)) {
81
                            $mixed = $mixed->$method();
82 1
                        } elseif (property_exists($mixed, $key) && null !== $mixed->$key) {
83
                            $mixed = $mixed->$key;
84
                        } else {
85
                            try {
86 1
                                $mixed = $mixed->$key;
87 2
                                if (null === $mixed) {
88
                                    return $defaultValue;
89
                                }
90
                            } catch (Exception $e) {
0 ignored issues
show
Unused Code introduced by
catch (\Exception $e) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
91
                                return $defaultValue;
92 1
                            }
93
94
                        }
95
                    } else {
96 49
                        return self::get($mixed, $key, $defaultValue);
97 1
                    }
98 1
                }
99 1
            }
100 1
            return $mixed;
101 1
        } elseif (is_string($mixed) || is_numeric($mixed)) { // 字符串或数字
102 1
            $pos = (int) $keyString;
103
            $length = null === $defaultValue ? 1 : (int) $defaultValue;
104 1
            return Strings::sub($mixed, $pos, $length);
105
        } elseif (null === $mixed) { // null
106
            return $defaultValue;
107
        } else { // 资源
108
            return $defaultValue;
109
        }
110
    }
111
112
    /**
113
     * 设置值
114
     *
115
     * @param array|object $mixed 对象或数组
116
     * @param string $key 键
117
     * @param mixed $value 值
118 1
     * @param boolean $overWrite 如果对应的值存在,是否用给定的值覆盖,默认 true,即:是
119
     *
120 1
     * @return mixed
121 1
     */
122 1
    public static function set(&$mixed, $key, $value, $overWrite = true)
123 1
    {
124 1
        $get = self::get($mixed, $key);
125 1
        if (null === $get || true === $overWrite) {
126 1
            if (is_array($mixed)) {
127 1
                $mixed[$key] = $value;
128 1
            } elseif (is_object($mixed)) {
129 1
                $method = 'set' . ucfirst(Strings::toCamel($key));
130
                if (method_exists($mixed, $method)) {
131 1
                    $mixed->$method($value);
132
                } elseif (property_exists($mixed, $key)) {
133
                    $mixed->$key = $value;
134 1
                } else {
135
                    throw new Exception('无法设置值');
136 1
                }
137
            }
138
            return $value;
139
        }
140
        return $get;
141
    }
142
143
    /**
144
     * 触发回调
145
     *
146 10
     * @param callback $callback 回调函数
147
     * @param array $params 回调参数
148 10
     * @return mixed
149 10
     */
150 10
    public static function call($callback, $params = [])
151
    {
152
        $result = false;
153
        is_callable($callback) && $result = call_user_func_array($callback, $params);
154
        return $result;
155
    }
156
157
    /**
158
     * 定义一个常量
159
     *
160
     * @param string $constant 常量名
161 1
     * @param mixed $value 值
162
     *
163 1
     * @return void
164 1
     */
165
    public static function def($constant, $value)
166
    {
167
        defined($constant) || define($constant, $value);
168
    }
169
170
    /**
171
     * 让 empty 支持函数调用
172
     *
173
     * 注意:此函数并不比 empty 好,只是为了让 empty 支持函数调用
174
     *
175
     * 例如:empty($array[0]) 就不能用此函数代替,另外,empty 是语法结构,性能明显比函数高
176
     *
177
     * @see http://php.net/manual/zh/function.empty.php
178 5
     *
179
     * @param mixed $data
180 5
     * @return boolean
181
     */
182
    public static function isEmpty($data)
183
    {
184
        return empty($data);
185
    }
186
187
    /**
188
     * 获取 php.ini 配置值
189
     *
190
     * @param string $key 配置名
191 2
     * @param mixed $default 默认值
192
     *
193 2
     * @return mixed
194
     */
195
    public static function phpini($key, $default = null)
196
    {
197
        return false !== ($ini = ini_get($key)) ? $ini : (false !== ($ini = get_cfg_var($key)) ? $ini : $default);
198
    }
199
200
    /**
201
     * 显示 PHP 错误
202
     *
203 1
     * @param boolean $show 是否显示,默认是
204
     *
205 1
     * @return void
206 1
     */
207 1
    public static function displayErrors($show = true)
208
    {
209
        ini_set("display_errors", true === $show ? 'On' : 'Off');
210
        true === $show && error_reporting(E_ALL | E_STRICT);
211
    }
212
213
    /**
214
     * 别名列表
215
     *
216
     * @var array
217
     */
218
    public static $aliases = [
219
        '@vendor' => __DIR__ . '/../../../../vendor',
220
        '@icy2003/php_tests' => __DIR__ . '/../tests',
221
        '@icy2003/php_runtime' => __DIR__ . '/../runtime',
222
        '@icy2003/php' => __DIR__,
223
    ];
224
225
    /**
226
     * 用别名获取真实路径
227
     *
228 50
     * @param string $alias 别名
229
     *
230 50
     * @return string|boolean
231 50
     */
232 18
    public static function getAlias($alias)
233
    {
234
        $alias = Strings::replace($alias, ["\\" => '/']);
235 50
        if (strncmp($alias, '@', 1)) {
236 50
            return $alias;
237 50
        }
238 50
239 50
        $pos = 0;
240 50
        while (true) {
241 50
            $pos = strpos($alias, '/', $pos);
242
            $root = $pos === false ? $alias : substr($alias, 0, $pos);
243
            if (isset(static::$aliases[$root])) {
244
                if (is_string(static::$aliases[$root])) {
245
                    return $pos === false ? static::$aliases[$root] : static::$aliases[$root] . substr($alias, $pos);
246
                } elseif (is_array(static::$aliases[$root])) {
247
                    foreach (static::$aliases[$root] as $name => $path) {
248
                        if (strpos($alias . '/', $name . '/') === 0) {
249
                            return $path . substr($alias, strlen($name));
250
                        }
251
                    }
252 50
                } else {
253
                    return false;
254
                }
255 50
            }
256
            if ($root == $alias) {
257
                break;
258
            }
259
            $pos++;
260
        }
261
        // 对 Yii2 的支持
262
        if ($result = self::call(['\Yii', 'getAlias'], [$alias])) {
263
            self::setAlias($alias, $result);
264
            return $result;
265
        }
266
267
        return false;
268
    }
269
270
    /**
271
     * 是否是 Yii2 项目
272
     *
273
     * @return boolean
274
     */
275
    public static function isYii2()
276
    {
277
        return method_exists('\Yii', 'getVersion');
278
    }
279
280
    /**
281
     * 设置别名
282
     *
283
     * @param string $alias 别名
284 1
     * @param string|null $path 路径
285
     *
286
     * @return void
287
     */
288 1
    public static function setAlias($alias, $path)
289
    {
290
        // 对 Yii2 的支持
291
        try {
292 1
            self::call(['\Yii', 'getAlias'], [$alias]);
293
        } catch (Exception $e) {
294
            self::call(['\Yii', 'setAlias'], [$alias, $path]);
295 1
        }
296 1
        if (strncmp($alias, '@', 1)) {
297 1
            $alias = '@' . $alias;
298 1
        }
299 1
        $pos = strpos($alias, '/');
300 1
        $root = $pos === false ? $alias : substr($alias, 0, $pos);
301 1
        if ($path !== null) {
302
            $path = strncmp($path, '@', 1) ? rtrim($path, '\\/') : static::getAlias($path);
303 1
            if (!isset(static::$aliases[$root])) {
304
                if ($pos === false) {
305
                    static::$aliases[$root] = $path;
306
                } else {
307
                    static::$aliases[$root] = [$alias => $path];
308
                }
309
            } elseif (is_string(static::$aliases[$root])) {
310
                if ($pos === false) {
311
                    static::$aliases[$root] = $path;
312
                } else {
313
                    static::$aliases[$root] = [
314
                        $alias => $path,
315
                        $root => static::$aliases[$root],
316 1
                    ];
317
                }
318
            } else {
319
                static::$aliases[$root][$alias] = $path;
320
                krsort(static::$aliases[$root]);
321
            }
322
        } elseif (isset(static::$aliases[$root])) {
323
            if (is_array(static::$aliases[$root])) {
324
                unset(static::$aliases[$root][$alias]);
325 1
            } elseif ($pos === false) {
326
                unset(static::$aliases[$root]);
327
            }
328
        }
329
    }
330
331
    /**
332
     * 判断给定选项值里是否设置某选项
333
     *
334
     * @param integer $flags 选项值
335 4
     * @param integer $flag 待判断的选项值
336
     *
337 4
     * @return boolean
338
     */
339
    public static function hasFlag($flags, $flag)
340
    {
341
        return $flags === ($flag | $flags);
342
    }
343
344
    /**
345
     * 创建一个对象
346
     *
347
     * @param array|string $params
348
     *      - 字符串:该字符串将被作为类名转成数组处理
349
     *      - 数组:
350
     *          1. class:表示类名
351
     *          2. 其他:该类的属性,初始化这些属性或者调用相应的 set 方法
352
     * @param array $config
353
     * - 构造函数传参
354
     *
355
     * @return object
356
     * @throws Exception
357
     */
358
    public static function obj($params, $config = [])
359
    {
360
        if (is_string($params)) {
361
            $params = ['class' => $params];
362
        }
363
        if (is_array($params) && isset($params['class'])) {
364
            try {
365
                $class = $params['class'];
366
                unset($params['class']);
367
                $reflection = new ReflectionClass($class);
368
                $object = $reflection->newInstanceArgs($config);
369
                foreach ($params as $name => $value) {
370
                    self::set($object, $name, $value);
371
                }
372
                return $object;
373
            } catch (Exception $e) {
374
                throw new Exception('初始化 ' . $class . ' 失败', $e->getCode(), $e);
375
            }
376
        }
377
        throw new Exception('必须带 class 键来指定一个类');
378
    }
379
380
    /**
381
     * 静态配置
382
     *
383
     * @var array
384
     */
385
    public static $ini = [
386
        'USE_CUSTOM' => false,
387
        'EXT_LOADED' => true,
388
    ];
389
390
    /**
391
     * 读取或设置一个全局配置
392
     *
393
     * - 该配置是利用静态类进行存储的
394
     * - 如果给定 $value,则为设置,不给则为获取
395
     * - 可选默认配置有:
396
     *      1. USE_CUSTOM:默认 false,即尝试使用 php 原生函数的实现,如果此参数为 true,则使用 icy2003/php 的实现
397
     *      2. EXT_LOADED:默认 true,即尝试检测是否有扩展,如果为 false,直接认为没有该扩展
398
     *
399
     * @param string $key
400 3
     * @param mixed $value
401
     *
402 3
     * @return void|mixed
403 3
     */
404
    public static function ini($key, $value = null)
405 2
    {
406
        if (null !== $value) {
407 3
            self::$ini[$key] = $value;
408
        } else {
409
            return self::get(self::$ini, $key);
410
        }
411
    }
412
413
    /**
414
     * 是否有加载 PHP 扩展
415
     *
416
     * @param string $extName
417
     *
418
     * @return boolean
419
     */
420
    public static function isExt($extName)
421
    {
422
        if (false === extension_loaded($extName) || false === self::ini('EXT_LOADED')) {
423
            return false;
424
        }
425
        return true;
426
    }
427
428
    /**
429
     * 判断当前操作系统是不是 windows
430
     *
431
     * @return boolean
432
     */
433
    public static function isWin()
434
    {
435
        return 'WIN' === strtoupper(substr(PHP_OS, 0, 3));
436
    }
437
}
438