Skip to content

Commit 1c8f566

Browse files
committed
introduce phpstan analizing and document generics
1 parent e6113cf commit 1c8f566

25 files changed

+545
-299
lines changed

.travis.yml

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ script:
5353
php -d 'zend.assertions=1' vendor/bin/phpunit --verbose;
5454
fi
5555

56+
# run phpstan
57+
- php vendor/bin/phpstan analyse --level max src/ tests/
58+
5659
# run benchmarks to make sure they are working fine
5760
- php vendor/bin/phpbench run --no-interaction --revs=1 --retry-threshold=100
5861

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
},
2323
"require-dev": {
2424
"phpunit/phpunit": "^6.0",
25-
"phpbench/phpbench": "^0.16.1"
25+
"phpbench/phpbench": "^0.16.1",
26+
"phpstan/phpstan": "^0.12.4"
2627
},
2728
"autoload": {
2829
"psr-4": {

phpstan.neon.dist

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
parameters:
2+
ignoreErrors:
3+
# EnumSet internally handles a bitset to be either an integer or a string
4+
- message: '#Binary operation "[\|\&\^]" between int\|string and int\|string results in an error#'
5+
path: %currentWorkingDirectory%/src/EnumSet.php
6+
7+
# EnumSerializableTrait
8+
- message: '#Access to private property \$[a-z]+ of parent class MabeEnum\\Enum#'
9+
path: %currentWorkingDirectory%/src/EnumSerializableTrait.php
10+
- message: '#Access to an undefined static property MabeEnumTest\\TestAsset\\SerializableEnum::\$instances#'
11+
path: %currentWorkingDirectory%/src/EnumSerializableTrait.php
12+
- message: '#Call to function is_object\(\) with array\|null will always evaluate to false#'
13+
path: %currentWorkingDirectory%/src/EnumSerializableTrait.php
14+
15+
# Tests
16+
- message: '#Parameter \#\d \$[a-z]* of static method MabeEnum\\Enum::[^ ]* expects [^ ]*, .+ given#'
17+
path: %currentWorkingDirectory%/tests/
18+
- message: '#Parameter \#\d \$[a-z]* of method MabeEnum\\EnumSet<[^ ]*>::[^ ]* expects [^ ]*, .+ given#'
19+
path: %currentWorkingDirectory%/tests/
20+
- message: '#Parameter \#\d \$[a-z]* of class MabeEnum\\Enum(Set|Map) constructor expects class-string<T of MabeEnum\\Enum>, string given#'
21+
path: %currentWorkingDirectory%/tests/

src/Enum.php

+50-25
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ abstract class Enum
2020
/**
2121
* The selected enumerator value
2222
*
23-
* @var null|bool|int|float|string|array
23+
* @var null|bool|int|float|string|mixed[]
2424
*/
2525
private $value;
2626

@@ -34,29 +34,29 @@ abstract class Enum
3434
/**
3535
* A map of enumerator names and values by enumeration class
3636
*
37-
* @var array ["$class" => ["$name" => $value, ...], ...]
37+
* @var array<class-string<Enum>, array<string, null|bool|int|float|string|mixed[]>>
3838
*/
3939
private static $constants = [];
4040

4141
/**
4242
* A List of available enumerator names by enumeration class
4343
*
44-
* @var array ["$class" => ["$name0", ...], ...]
44+
* @var array<class-string<Enum>, string[]>
4545
*/
4646
private static $names = [];
4747

4848
/**
49-
* Already instantiated enumerators
49+
* A map of enumerator names and instances by enumeration class
5050
*
51-
* @var array ["$class" => ["$name" => $instance, ...], ...]
51+
* @var array<class-string<Enum>, array<string, Enum>>
5252
*/
5353
private static $instances = [];
5454

5555
/**
5656
* Constructor
5757
*
58-
* @param null|bool|int|float|string|array $value The value of the enumerator
59-
* @param int|null $ordinal The ordinal number of the enumerator
58+
* @param null|bool|int|float|string|mixed[] $value The value of the enumerator
59+
* @param int|null $ordinal The ordinal number of the enumerator
6060
*/
6161
final private function __construct($value, $ordinal = null)
6262
{
@@ -105,7 +105,7 @@ final public function __wakeup()
105105
/**
106106
* Get the value of the enumerator
107107
*
108-
* @return null|bool|int|float|string|array
108+
* @return null|bool|int|float|string|mixed[]
109109
*/
110110
final public function getValue()
111111
{
@@ -149,7 +149,7 @@ final public function getOrdinal()
149149
/**
150150
* Compare this enumerator against another and check if it's the same.
151151
*
152-
* @param static|null|bool|int|float|string|array $enumerator An enumerator object or value
152+
* @param static|null|bool|int|float|string|mixed[] $enumerator An enumerator object or value
153153
* @return bool
154154
*/
155155
final public function is($enumerator)
@@ -166,14 +166,22 @@ final public function is($enumerator)
166166
/**
167167
* Get an enumerator instance of the given enumerator value or instance
168168
*
169-
* @param static|null|bool|int|float|string|array $enumerator An enumerator object or value
169+
* @param static|null|bool|int|float|string|mixed[] $enumerator An enumerator object or value
170170
* @return static
171171
* @throws InvalidArgumentException On an unknown or invalid value
172172
* @throws LogicException On ambiguous constant values
173173
*/
174174
final public static function get($enumerator)
175175
{
176-
if ($enumerator instanceof static && \get_class($enumerator) === static::class) {
176+
if ($enumerator instanceof static) {
177+
if (\get_class($enumerator) !== static::class) {
178+
throw new InvalidArgumentException(sprintf(
179+
'Invalid value of type %s for enumeration %s',
180+
\get_class($enumerator),
181+
static::class
182+
));
183+
}
184+
177185
return $enumerator;
178186
}
179187

@@ -183,13 +191,15 @@ final public static function get($enumerator)
183191
/**
184192
* Get an enumerator instance by the given value
185193
*
186-
* @param null|bool|int|float|string|array $value Enumerator value
194+
* @param null|bool|int|float|string|mixed[] $value Enumerator value
187195
* @return static
188196
* @throws InvalidArgumentException On an unknown or invalid value
189197
* @throws LogicException On ambiguous constant values
190198
*/
191199
final public static function byValue($value)
192200
{
201+
/** @var mixed $value */
202+
193203
$constants = self::$constants[static::class] ?? static::getConstants();
194204

195205
$name = \array_search($value, $constants, true);
@@ -203,8 +213,11 @@ final public static function byValue($value)
203213
));
204214
}
205215

206-
return self::$instances[static::class][$name]
216+
/** @var static $instance */
217+
$instance = self::$instances[static::class][$name]
207218
?? self::$instances[static::class][$name] = new static($constants[$name]);
219+
220+
return $instance;
208221
}
209222

210223
/**
@@ -218,7 +231,9 @@ final public static function byValue($value)
218231
final public static function byName(string $name)
219232
{
220233
if (isset(self::$instances[static::class][$name])) {
221-
return self::$instances[static::class][$name];
234+
/** @var static $instance */
235+
$instance = self::$instances[static::class][$name];
236+
return $instance;
222237
}
223238

224239
$const = static::class . "::{$name}";
@@ -255,8 +270,12 @@ final public static function byOrdinal(int $ordinal)
255270
}
256271

257272
$name = self::$names[static::class][$ordinal];
258-
return self::$instances[static::class][$name]
273+
274+
/** @var static $instance */
275+
$instance = self::$instances[static::class][$name]
259276
?? self::$instances[static::class][$name] = new static($constants[$name], $ordinal);
277+
278+
return $instance;
260279
}
261280

262281
/**
@@ -269,13 +288,16 @@ final public static function getEnumerators()
269288
if (!isset(self::$names[static::class])) {
270289
static::getConstants();
271290
}
272-
return \array_map([static::class, 'byName'], self::$names[static::class]);
291+
292+
/** @var callable $byNameFn */
293+
$byNameFn = [static::class, 'byName'];
294+
return \array_map($byNameFn, self::$names[static::class]);
273295
}
274296

275297
/**
276298
* Get a list of enumerator values ordered by ordinal number
277299
*
278-
* @return mixed[]
300+
* @return (null|bool|int|float|string|mixed[])[]
279301
*/
280302
final public static function getValues()
281303
{
@@ -309,7 +331,7 @@ final public static function getOrdinals()
309331
/**
310332
* Get all available constants of the called class
311333
*
312-
* @return array
334+
* @return array<string, null|bool|int|float|string|mixed[]>
313335
* @throws LogicException On ambiguous constant values
314336
*/
315337
final public static function getConstants()
@@ -344,7 +366,7 @@ final public static function getConstants()
344366

345367
/**
346368
* Test that the given constants does not contain ambiguous values
347-
* @param array $constants
369+
* @param array<string, null|bool|int|float|string|mixed[]> $constants
348370
* @return bool
349371
*/
350372
private static function noAmbiguousValues($constants)
@@ -362,19 +384,22 @@ private static function noAmbiguousValues($constants)
362384
/**
363385
* Test if the given enumerator is part of this enumeration
364386
*
365-
* @param static|null|bool|int|float|string|array $enumerator
387+
* @param static|null|bool|int|float|string|mixed[] $enumerator
366388
* @return bool
367389
*/
368390
final public static function has($enumerator)
369391
{
370-
return ($enumerator instanceof static && \get_class($enumerator) === static::class)
371-
|| static::hasValue($enumerator);
392+
if ($enumerator instanceof static) {
393+
return \get_class($enumerator) === static::class;
394+
}
395+
396+
return static::hasValue($enumerator);
372397
}
373398

374399
/**
375400
* Test if the given enumerator value is part of this enumeration
376401
*
377-
* @param null|bool|int|float|string|array $value
402+
* @param null|bool|int|float|string|mixed[] $value
378403
* @return bool
379404
*/
380405
final public static function hasValue($value)
@@ -399,8 +424,8 @@ final public static function hasName(string $name)
399424
* This will be called automatically on calling a method
400425
* with the same name of a defined enumerator.
401426
*
402-
* @param string $method The name of the enumerator (called as method)
403-
* @param array $args There should be no arguments
427+
* @param string $method The name of the enumerator (called as method)
428+
* @param array<mixed> $args There should be no arguments
404429
* @return static
405430
* @throws InvalidArgumentException On an invalid or unknown name
406431
* @throws LogicException On ambiguous constant values

0 commit comments

Comments
 (0)