Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
75.51% covered (warning)
75.51%
37 / 49
90.00% covered (success)
90.00%
9 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
TypeUtility
75.51% covered (warning)
75.51%
37 / 49
90.00% covered (success)
90.00%
9 / 10
41.35
0.00% covered (danger)
0.00%
0 / 1
 parseInteger
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 tryParseInteger
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 parseUInteger
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 tryParseUInteger
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 parsePositiveInteger
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 tryParsePositiveInteger
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 parseBoolean
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isNullable
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
132
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\Core;
6
7use PeServer\Core\Collection\Arr;
8use PeServer\Core\Regex;
9use PeServer\Core\Text;
10use PeServer\Core\Throws\ParseException;
11
12/**
13 * 型系。
14 *
15 * PHPの型変換がおれの予想をはるかに超えてくる。つらい。
16 */
17abstract class TypeUtility
18{
19    #region define
20
21    private const INT_PATTERN = '/^\s*(\+|\-)?\d+\s*$/';
22    private const UINT_PATTERN = '/^\s*(\+)?\d+\s*$/';
23
24    public const TYPE_BOOLEAN = "bool";
25    public const TYPE_INTEGER = "int";
26    public const TYPE_DOUBLE = "float";
27    public const TYPE_STRING = "string";
28    public const TYPE_ARRAY = "array";
29    public const TYPE_OBJECT = "object";
30    public const TYPE_RESOURCE = "resource"; //BUGS: つかえん
31    public const TYPE_RESOURCE_CLOSED = "resource (closed)";
32    public const TYPE_NULL = "null";
33
34    #endregion
35
36    #region function
37
38    /**
39     * 文字列を整数に変換。
40     *
41     * @param string $input 文字列。
42     * @return int 変換後整数。
43     * @throws ParseException 変換できない文字列。
44     */
45    public static function parseInteger(string $input): int
46    {
47        $regex = new Regex();
48        if (!$regex->isMatch($input, self::INT_PATTERN)) {
49            throw new ParseException($input);
50        }
51
52        return (int)Text::trim($input);
53    }
54
55    /**
56     * 文字列を整数に変換した結果を取得。
57     *
58     * @param string $input 文字列。
59     * @param int|null $result 変換成功時の整数。
60     * @return boolean 変換成功状態。
61     * @phpstan-assert-if-true int $result
62     */
63    public static function tryParseInteger(string $input, ?int &$result): bool
64    {
65        $regex = new Regex();
66        if (!$regex->isMatch($input, self::INT_PATTERN)) {
67            return false;
68        }
69
70        $result = (int)Text::trim($input);
71        return true;
72    }
73
74    /**
75     * 文字列を整数に変換。
76     *
77     * @param string $input 文字列。
78     * @return int 変換後整数。
79     * @phpstan-return non-negative-int $result
80     * @throws ParseException 変換できない文字列。
81     */
82    public static function parseUInteger(string $input): int
83    {
84        $regex = new Regex();
85        if (!$regex->isMatch($input, self::UINT_PATTERN)) {
86            throw new ParseException($input);
87        }
88
89        /** @phpstan-var non-negative-int */
90        return (int)Text::trim($input);
91    }
92
93    /**
94     * 文字列を整数に変換した結果を取得。
95     *
96     * @param string $input 文字列。
97     * @param int|null $result 変換成功時の整数。
98     * @phpstan-param non-negative-int|null $result
99     * @return boolean 変換成功状態。
100     * @phpstan-assert-if-true non-negative-int $result
101     */
102    public static function tryParseUInteger(string $input, ?int &$result): bool
103    {
104        $regex = new Regex();
105        if (!$regex->isMatch($input, self::UINT_PATTERN)) {
106            $result = null;
107            return false;
108        }
109
110        /** @phpstan-var non-negative-int */
111        $result = (int)Text::trim($input); // @phpstan-ignore-line
112        return true;
113    }
114
115    /**
116     * 文字列を整数(0超過)に変換。
117     *
118     * @param string $input 文字列。
119     * @return int 変換後整数。
120     * @phpstan-return positive-int $result
121     * @throws ParseException 変換できない文字列。
122     */
123    public static function parsePositiveInteger(string $input): int
124    {
125        $result = self::parseUInteger($input);
126        if (0 < $result) {
127            return $result;
128        }
129
130        throw new ParseException($input);
131    }
132
133    /**
134     * 文字列を整数(0超過)に変換した結果を取得。
135     *
136     * @param string $input 文字列。
137     * @param int|null $result 変換成功時の整数。
138     * @phpstan-param positive-int|null $result
139     * @return boolean 変換成功状態。
140     * @phpstan-assert-if-true positive-int $result
141     */
142    public static function tryParsePositiveInteger(string $input, ?int &$result): bool
143    {
144        if (self::tryParseUInteger($input, $temp)) {
145            if (0 < $temp) {
146                $result = $temp;
147                return true;
148            }
149        }
150
151        return false;
152    }
153
154    /**
155     * 文字列を真偽値に変換した結果を取得。
156     *
157     * @param mixed $input
158     * @return bool
159     */
160    public static function parseBoolean(mixed $input): bool
161    {
162        if (is_bool($input)) {
163            return (bool)$input;
164        }
165        if (is_string($input)) {
166            $s = Text::toLower(Text::trim((string)$input));
167            $trues = ['true', 't', 'on', 'ok', '1'];
168            return Arr::containsValue($trues, $s);
169        }
170
171        return boolval($input);
172    }
173
174    public static function toString(mixed $input): string
175    {
176        return Text::toString($input);
177    }
178
179    /**
180     * 値から型を返す。
181     *
182     * @param mixed $input
183     * @return string 型名
184     * @phpstan-return class-string|self::TYPE_*
185     * @see https://www.php.net/manual/get_debug_type.php
186     */
187    public static function getType(mixed $input): string
188    {
189        return get_debug_type($input); //@phpstan-ignore-line 正直戻り値の制限いらんとは思っている
190    }
191
192    /**
193     * NULL を許容する型か。
194     *
195     * NULL 許容型ではないことに注意。
196     *
197     * @param string $type
198     * @return bool
199     */
200    public static function isNullable(string $type): bool
201    {
202        // if($type[0] === '?') {
203        //     return true;
204        // }
205        return match ($type) {
206            self::TYPE_BOOLEAN => false,
207            self::TYPE_INTEGER => false,
208            self::TYPE_DOUBLE => false,
209            self::TYPE_STRING => true,
210            self::TYPE_ARRAY => true,
211            self::TYPE_OBJECT => true,
212            self::TYPE_RESOURCE => true,
213            self::TYPE_RESOURCE_CLOSED => true,
214            self::TYPE_NULL => true,
215            default => true,
216        };
217    }
218
219    #endregion
220}