Skip to content

Commit b59eefc

Browse files
committed
refactor: statics replaced by selfs and Optionals
1 parent 3becb23 commit b59eefc

17 files changed

+482
-40
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
],
4747
"check-implementation": [
4848
"phpcs --colors --standard=PSR12 --exclude=Generic.Files.LineLength src tests",
49-
"phpstan analyse --level max src --ansi --no-interaction",
49+
"phpstan analyse --level max src phpdoc_check.php --ansi --no-interaction",
5050
"phpstan analyse --level 5 tests --ansi --no-interaction",
5151
"phpinsights analyse src tests --ansi --no-interaction --format=github-action | sed -e \"s#::error file=$PWD/#::notice file=#g\""
5252
],

phpdoc_check.php

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<?php
2+
3+
/**
4+
* This file is checked by PhpStan as production code and confirms correctness of PhpDocs
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
use PetrKnap\Optional\Optional;
10+
use PetrKnap\Optional\OptionalInt;
11+
use PetrKnap\Optional\OptionalObject;
12+
use PetrKnap\Optional\OptionalString;
13+
14+
$functionWithGenericInputOptions = fn (Optional $string = null, Optional $int = null) => null;
15+
$functionWithNonGenericInputOptions = fn (OptionalString $string = null, OptionalInt $int = null) => null;
16+
$functionWithNonGenericInputs = fn (string $string = '', int $int = 0) => null;
17+
18+
// ---------------------------------------------------------------------------------------------------------------------
19+
20+
// Call all factories
21+
OptionalString::of('');
22+
OptionalString::of(null); // @phpstan-ignore argument.type
23+
OptionalString::of(false); // @phpstan-ignore argument.type
24+
OptionalString::ofFalsable('');
25+
OptionalString::ofFalsable(null); // @phpstan-ignore argument.type
26+
OptionalString::ofFalsable(false);
27+
OptionalString::ofNullable('');
28+
OptionalString::ofNullable(null);
29+
OptionalString::ofNullable(false); // @phpstan-ignore argument.type
30+
OptionalString::ofSingle(['']);
31+
OptionalString::ofSingle([null]); // @phpstan-ignore argument.type
32+
OptionalString::ofSingle([false]); // @phpstan-ignore argument.type
33+
OptionalString::ofSingle([]);
34+
35+
// Check sub-typed optional factory
36+
OptionalObject::of(new stdClass());
37+
OptionalObject::of(new class {
38+
});
39+
OptionalObject::of(''); // @phpstan-ignore argument.type, argument.templateType
40+
OptionalObject\OptionalStdClass::of(new stdClass());
41+
OptionalObject\OptionalStdClass::of(new class { // @phpstan-ignore argument.type
42+
});
43+
OptionalObject\OptionalStdClass::of(''); // @phpstan-ignore argument.type
44+
45+
// ---------------------------------------------------------------------------------------------------------------------
46+
47+
// Create generic option
48+
$stringOption = Optional::of('');
49+
50+
// Call all methods with generic arguments
51+
$stringOption->filter(static fn (string $value): bool => true);
52+
$stringOption->filter(static fn (int $value): bool => true); // @phpstan-ignore argument.type
53+
$stringOption->flatMap(static fn (string $value): Optional => $stringOption);
54+
$stringOption->flatMap(static fn (int $value): Optional => $stringOption); // @phpstan-ignore argument.type
55+
$stringOption->ifPresent(static fn (string $value): string => $value);
56+
$stringOption->ifPresent(static fn (int $value): int => $value); // @phpstan-ignore argument.type
57+
$stringOption->map(static fn (string $value): string => $value);
58+
$stringOption->map(static fn (int $value): int => $value); // @phpstan-ignore argument.type
59+
$stringOptionOrElse = $stringOption->orElse('');
60+
$stringOptionOrElseNull = $stringOption->orElse(null);
61+
$stringOption->orElse(0); // @phpstan-ignore argument.type
62+
$stringOptionOrElseGet = $stringOption->orElseGet(static fn (): string => '');
63+
$stringOption->orElseGet(static fn (): int => 0); // @phpstan-ignore argument.type
64+
65+
// Use generic option as input for functions
66+
$functionWithGenericInputOptions(string: $stringOption);
67+
$functionWithNonGenericInputOptions(string: $stringOption); // @phpstan-ignore argument.type
68+
$functionWithNonGenericInputs(string: $stringOption->get());
69+
$functionWithNonGenericInputs(string: $stringOption->orElseThrow());
70+
$functionWithNonGenericInputs(string: $stringOptionOrElse);
71+
$functionWithNonGenericInputs(string: $stringOptionOrElseNull); // @phpstan-ignore argument.type
72+
$functionWithNonGenericInputs(string: $stringOptionOrElseNull ?? '');
73+
$functionWithNonGenericInputs(string: $stringOptionOrElseGet);
74+
75+
// Re-map generic option & call filter on it to check new generic
76+
$intOptionMapped = $stringOption->map(static fn (string $value): int => 0);
77+
$intOptionMappedFiltered = $intOptionMapped->filter(static fn (int $value): bool => true);
78+
$intOptionMapped->filter(static fn (string $value): bool => true); // @phpstan-ignore argument.type
79+
$intOptionFlatMapped = $stringOption->flatMap(static fn (string $value): Optional => Optional::of(0));
80+
$intOptionFlatMappedFiltered = $intOptionFlatMapped->filter(static fn (int $value): bool => true);
81+
$intOptionFlatMapped->filter(static fn (string $value): bool => true); // @phpstan-ignore argument.type
82+
83+
// Use re-mapped filtered options as input for functions
84+
$functionWithGenericInputOptions(int: $intOptionMappedFiltered);
85+
$functionWithNonGenericInputOptions(int: $intOptionMappedFiltered); // @phpstan-ignore argument.type
86+
$functionWithNonGenericInputs(int: $intOptionMappedFiltered->get());
87+
$functionWithGenericInputOptions(int: $intOptionFlatMappedFiltered);
88+
$functionWithNonGenericInputOptions(int: $intOptionFlatMappedFiltered); // @phpstan-ignore argument.type
89+
$functionWithNonGenericInputs(int: $intOptionFlatMappedFiltered->get());
90+
91+
// ---------------------------------------------------------------------------------------------------------------------
92+
93+
// Create non-generic option
94+
$stringOption = OptionalString::of('');
95+
96+
// Call all methods with generic arguments
97+
$stringOption->filter(static fn (string $value): bool => true);
98+
$stringOption->filter(static fn (int $value): bool => true); // @phpstan-ignore argument.type
99+
$stringOption->flatMap(static fn (string $value): OptionalString => $stringOption);
100+
$stringOption->flatMap(static fn (int $value): OptionalString => $stringOption); // @phpstan-ignore argument.type
101+
$stringOption->ifPresent(static fn (string $value): string => $value);
102+
$stringOption->ifPresent(static fn (int $value): int => $value); // @phpstan-ignore argument.type
103+
$stringOption->map(static fn (string $value): string => $value);
104+
$stringOption->map(static fn (int $value): int => $value); // @phpstan-ignore argument.type
105+
$stringOptionOrElse = $stringOption->orElse('');
106+
$stringOptionOrElseNull = $stringOption->orElse(null);
107+
$stringOption->orElse(0); // @phpstan-ignore argument.type
108+
$stringOptionOrElseGet = $stringOption->orElseGet(static fn (): string => '');
109+
$stringOption->orElseGet(static fn (): int => 0); // @phpstan-ignore argument.type
110+
111+
// Use non-generic option as input for functions
112+
$functionWithGenericInputOptions(string: $stringOption);
113+
$functionWithNonGenericInputOptions(string: $stringOption);
114+
$functionWithNonGenericInputs(string: $stringOption->get());
115+
$functionWithNonGenericInputs(string: $stringOption->orElseThrow());
116+
$functionWithNonGenericInputs(string: $stringOptionOrElse);
117+
$functionWithNonGenericInputs(string: $stringOptionOrElseNull); // @phpstan-ignore argument.type
118+
$functionWithNonGenericInputs(string: $stringOptionOrElseNull ?? '');
119+
$functionWithNonGenericInputs(string: $stringOptionOrElseGet);
120+
121+
// Re-map typed option & call filter on it to check new generic
122+
$intOptionMapped = $stringOption->map(static fn (string $value): int => 0);
123+
$intOptionMappedFiltered = $intOptionMapped->filter(static fn (int $value): bool => true);
124+
$intOptionMapped->filter(static fn (string $value): bool => true); // @phpstan-ignore argument.type
125+
$intOptionFlatMapped = $stringOption->flatMap(static fn (string $value): OptionalInt => OptionalInt::of(0));
126+
$intOptionFlatMappedFiltered = $intOptionFlatMapped->filter(static fn (int $value): bool => true);
127+
$intOptionFlatMapped->filter(static fn (string $value): bool => true); // @phpstan-ignore argument.type
128+
129+
// Use re-mapped filtered options as input for functions
130+
$functionWithGenericInputOptions(int: $intOptionMappedFiltered);
131+
$functionWithNonGenericInputOptions(int: $intOptionMappedFiltered); // @phpstan-ignore argument.type
132+
$functionWithNonGenericInputs(int: $intOptionMappedFiltered->get());
133+
$functionWithGenericInputOptions(int: $intOptionFlatMappedFiltered);
134+
$functionWithNonGenericInputOptions(int: $intOptionFlatMappedFiltered); // @phpstan-ignore argument.type
135+
$functionWithNonGenericInputs(int: $intOptionFlatMappedFiltered->get());
136+
137+
// ---------------------------------------------------------------------------------------------------------------------

src/Exception/TypedOptionalException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace PetrKnap\Optional\Exception;
66

77
/**
8-
* @todo extend {@see Exception}, not {@see OptionalException}
8+
* @todo BC extend {@see Exception}, not {@see OptionalException}
99
*/
1010
interface TypedOptionalException extends OptionalException
1111
{

src/JavaSe8/Optional.php

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,32 @@ interface Optional
1717
{
1818
/**
1919
* Returns an empty {@see self::class} instance.
20+
*
21+
* @return self<T>
2022
*/
21-
public static function empty(): static;
23+
public static function empty(): self;
2224

2325
/**
2426
* Returns an {@see self::class} with the specified present non-null value.
2527
*
26-
* @param T $value
28+
* @template U of T
29+
*
30+
* @param U $value
31+
*
32+
* @return self<U>
2733
*/
28-
public static function of(mixed $value): static;
34+
public static function of(mixed $value): self;
2935

3036
/**
3137
* Returns an {@see self::class} describing the specified value, if non-null, otherwise returns an empty {@see self::class}.
3238
*
33-
* @param T|null $value
39+
* @template U of T
40+
*
41+
* @param U|null $value
42+
*
43+
* @return self<U>
3444
*/
35-
public static function ofNullable(mixed $value): static;
45+
public static function ofNullable(mixed $value): self;
3646

3747
/**
3848
* Indicates whether some other object is "equal to" this {@see self::class}.
@@ -43,8 +53,10 @@ public function equals(mixed $obj): bool;
4353
* If a value is present, and the value matches the given predicate, return an {@see self::class} describing the value, otherwise return an empty {@see self::class}.
4454
*
4555
* @param callable(T): bool $predicate
56+
*
57+
* @return self<T>
4658
*/
47-
public function filter(callable $predicate): static;
59+
public function filter(callable $predicate): self;
4860

4961
/**
5062
* If a value is present, apply the provided {@see self::class}-bearing mapping function to it, return that result, otherwise return an empty {@see self::class}.
@@ -69,7 +81,7 @@ public function get(): mixed;
6981
/**
7082
* If a value is present, invoke the specified consumer with the value, otherwise do nothing.
7183
*
72-
* @param callable(T): void $consumer
84+
* @param callable(T): mixed $consumer
7385
*/
7486
public function ifPresent(callable $consumer): void;
7587

src/NonGenericOptional.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PetrKnap\Optional;
6+
7+
/**
8+
* Changes return types from generic to non-generic {@see Optional}
9+
*
10+
* @phpstan-require-extends Optional
11+
*/
12+
trait NonGenericOptional
13+
{
14+
public static function empty(): self
15+
{
16+
/** @var self */
17+
return parent::empty();
18+
}
19+
20+
public static function of(mixed $value): self
21+
{
22+
/** @var self */
23+
return parent::of($value);
24+
}
25+
26+
public static function ofFalsable(mixed $value): self
27+
{
28+
/** @var self */
29+
return parent::ofFalsable($value);
30+
}
31+
32+
public static function ofNullable(mixed $value): self
33+
{
34+
/** @var self */
35+
return parent::ofNullable($value);
36+
}
37+
38+
public static function ofSingle(iterable $value): self
39+
{
40+
/** @var self */
41+
return parent::ofSingle($value);
42+
}
43+
44+
public function filter(callable $predicate): self
45+
{
46+
/** @var self */
47+
return parent::filter($predicate);
48+
}
49+
}

0 commit comments

Comments
 (0)