diff --git a/README.md b/README.md index 7626e6d..24c6a7c 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ It is an easy way to make sure that everyone has to check if they have (not) received a `null`. +## Examples + ```php namespace PetrKnap\Optional; @@ -28,6 +30,36 @@ if ($optionalString->equals('value')) { } ``` +### Create and use your own typed optional + +```php +namespace PetrKnap\Optional; + +class YourClass {} + +/** + * @template-extends OptionalObject + */ +class YourOptional extends OptionalObject { + protected static function getObjectClassName(): string { + return YourClass::class; + } +} +TypedOptional::register(YourOptional::class); // optional recommended step + +function your_strong_typed_function(YourOptional $input): YourOptional { + return YourOptional::empty(); +} + +/** + * @param Optional $input + * @return Optional + */ +function your_weak_typed_function(Optional $input): Optional { + return YourOptional::empty(); +} +``` + --- Run `composer require petrknap/optional` to install it. diff --git a/src/Exception/CouldNotFindTypedOptionalForValue.php b/src/Exception/CouldNotFindTypedOptionalForValue.php new file mode 100644 index 0000000..52aff13 --- /dev/null +++ b/src/Exception/CouldNotFindTypedOptionalForValue.php @@ -0,0 +1,21 @@ +value; + } +} diff --git a/src/Exception/CouldNotRegisterNonOptional.php b/src/Exception/CouldNotRegisterNonOptional.php new file mode 100644 index 0000000..c9442ae --- /dev/null +++ b/src/Exception/CouldNotRegisterNonOptional.php @@ -0,0 +1,27 @@ +className; + } +} diff --git a/src/Exception/TypedOptionalException.php b/src/Exception/TypedOptionalException.php new file mode 100644 index 0000000..fb0912b --- /dev/null +++ b/src/Exception/TypedOptionalException.php @@ -0,0 +1,9 @@ + must be iterated in reverse order */ + private static array $typedOptionals = [ + OptionalArray::class, + OptionalBool::class, + OptionalFloat::class, + OptionalInt::class, + OptionalObject::class, + OptionalObject\OptionalStdClass::class, + OptionalResource::class, + OptionalResource\OptionalStream::class, + OptionalString::class, + ]; + + /** + * @template T of mixed + * + * @param T $value + * + * @return Optional + * + * @throws Exception\CouldNotFindTypedOptionalForValue + */ + public static function of(mixed $value): Optional + { + /** @var class-string> $typedOptional */ + foreach (array_reverse(self::$typedOptionals) as $typedOptional) { + try { + return $typedOptional::of($value); + } catch (InvalidArgumentException) { + } + } + throw new Exception\CouldNotFindTypedOptionalForValue($value); + } + + /** + * @param class-string $typedOptionalClassName + * + * @throws Exception\CouldNotRegisterNonOptional + */ + public static function register(string $typedOptionalClassName): void + { + if (!is_a($typedOptionalClassName, Optional::class, allow_string: true)) { + throw new Exception\CouldNotRegisterNonOptional($typedOptionalClassName); + } + self::$typedOptionals[] = $typedOptionalClassName; + } +} diff --git a/tests/ReadmeTest.php b/tests/ReadmeTest.php index 9a13993..ce0e79d 100644 --- a/tests/ReadmeTest.php +++ b/tests/ReadmeTest.php @@ -20,7 +20,7 @@ public static function getPathToMarkdownFile(): string public static function getExpectedOutputsOfPhpExamples(): iterable { return [ - 'example' => '' + 'examples' => '' . 'value' . 'value' . 'value' @@ -28,6 +28,7 @@ public static function getExpectedOutputsOfPhpExamples(): iterable . 'value' . 'It is `value`.' , + 'create--and-use-your-own-typed-optional' => '', ]; } } diff --git a/tests/TypedOptionalsTest.php b/tests/TypedOptionalsTest.php index e7d8635..628c5ad 100644 --- a/tests/TypedOptionalsTest.php +++ b/tests/TypedOptionalsTest.php @@ -21,6 +21,7 @@ public function testCouldBeCreated(string $optionalClassName, mixed $value): voi self::assertInstanceOf($optionalClassName, $optionalClassName::of($value)); self::assertInstanceOf($optionalClassName, $optionalClassName::ofNullable($value)); self::assertInstanceOf($optionalClassName, $optionalClassName::ofNullable(null)); + self::assertInstanceOf($optionalClassName, TypedOptional::of($value)); } public static function dataCouldBeCreated(): array