diff --git a/README.md b/README.md index 766145b..0137d5e 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,8 @@ namespace PetrKnap\Optional; */ class YourOptional extends OptionalObject { use NonGenericOptional; - protected static function getInstanceOf(): string { - return Some\DataObject::class; + protected static function isSupported(mixed $value): bool { + return $value instanceof Some\DataObject; } } TypedOptional::register(YourOptional::class); // optional recommended step diff --git a/phpdoc_check.php b/phpdoc_check.php index 0150f88..8d581d3 100644 --- a/phpdoc_check.php +++ b/phpdoc_check.php @@ -54,6 +54,12 @@ public function nonGenericInputs(string $string = '', int $int = 0): void {} Optional::ofSingle([]); // Call main typed factories +OptionalArray::of([]); +OptionalArray::of(null); // @phpstan-ignore argument.type, argument.templateType +OptionalArray::of(false); // @phpstan-ignore argument.type, argument.templateType +OptionalArray::ofNullable([]); +OptionalArray::ofNullable(null); // @phpstan-ignore argument.templateType +OptionalArray::ofNullable(false); // @phpstan-ignore argument.type, argument.templateType OptionalString::of(''); OptionalString::of(null); // @phpstan-ignore argument.type OptionalString::of(false); // @phpstan-ignore argument.type diff --git a/src/AbstractOptional.php b/src/AbstractOptional.php new file mode 100644 index 0000000..da921a1 --- /dev/null +++ b/src/AbstractOptional.php @@ -0,0 +1,53 @@ + */ + use GenericOptional; + + /** + * @template U of T + * + * @param U|null $value + * + * @return self + */ + public static function ofNullable(mixed $value): self // @phpstan-ignore generics.notSubtype + { + if (static::class === self::class) { + if ($value !== null) { + try { + /** @var self */ // @phpstan-ignore generics.notSubtype + return TypedOptional::of($value, static::class); + } catch (Exception\CouldNotFindTypedOptionalForValue) { + } + } + /** @var self */ + return self::createInstance($value); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType + } + /** @var self */ + return parent::ofNullable($value); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType + } + + /** + * @template U of T + * + * @param U|null $value + * + * @return self + */ + abstract protected static function createInstance(mixed $value): self; + + abstract protected static function isInstanceOfStatic(object $obj): bool; +} diff --git a/src/GenericOptional.php b/src/GenericOptional.php new file mode 100644 index 0000000..0a806c5 --- /dev/null +++ b/src/GenericOptional.php @@ -0,0 +1,85 @@ + + */ + public static function empty(): self + { + /** @var self */ + return parent::empty(); + } + + /** + * @template U of T + * + * @param U $value + * + * @return self + */ + public static function of(mixed $value): self // @phpstan-ignore generics.notSubtype + { + /** @var self */ + return parent::of($value); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType + } + + /** + * @template U of T + * + * @param U|false $value + * + * @return self + */ + public static function ofFalsable(mixed $value): self // @phpstan-ignore generics.notSubtype + { + /** @var self */ + return parent::ofFalsable($value); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType + } + + /** + * @template U of T + * + * @param U|null $value + * + * @return self + */ + public static function ofNullable(mixed $value): self // @phpstan-ignore generics.notSubtype + { + /** @var self */ + return parent::ofNullable($value); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType + } + + /** + * @template U of T + * + * @param iterable $value + * + * @return self + */ + public static function ofSingle(iterable $value): self // @phpstan-ignore generics.notSubtype + { + /** @var self */ + return parent::ofSingle($value); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType + } + + /** + * @return self + */ + public function filter(callable $predicate): self // @phpstan-ignore generics.notSubtype + { + /** @var self */ + return parent::filter($predicate); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType + } +} diff --git a/src/NonGenericOptional.php b/src/NonGenericOptional.php index 5a38960..5ed2ece 100644 --- a/src/NonGenericOptional.php +++ b/src/NonGenericOptional.php @@ -5,7 +5,7 @@ namespace PetrKnap\Optional; /** - * Sets return types to non-generic {@see Optional} + * Provides unified type hints and non-generic behavior for concrete {@see Optional} implementations. * * @phpstan-require-extends Optional */ diff --git a/src/Optional.php b/src/Optional.php index a67a025..5b310e1 100644 --- a/src/Optional.php +++ b/src/Optional.php @@ -305,7 +305,7 @@ public function orElseThrow( } /** - * @internal overridden by abstracts + * @internal overridden by {@see AbstractOptional} */ protected static function isInstanceOfStatic(object $obj): bool { diff --git a/src/OptionalArray.php b/src/OptionalArray.php index 0279452..91a5706 100644 --- a/src/OptionalArray.php +++ b/src/OptionalArray.php @@ -11,75 +11,8 @@ */ final class OptionalArray extends Optional { - /** - * @return self - */ - public static function empty(): self - { - /** @var self */ - return parent::empty(); - } - - /** - * @template U of T - * - * @param U $value - * - * @return self - */ - public static function of(mixed $value): self - { - /** @var self */ - return parent::of($value); - } - - /** - * @template U of T - * - * @param U|false $value - * - * @return self - */ - public static function ofFalsable(mixed $value): self - { - /** @var self */ - return parent::ofFalsable($value); - } - - /** - * @template U of T - * - * @param U|null $value - * - * @return self - */ - public static function ofNullable(mixed $value): self - { - /** @var self */ - return parent::ofNullable($value); - } - - /** - * @template U of T - * - * @param iterable $value - * - * @return self - */ - public static function ofSingle(iterable $value): self - { - /** @var self */ - return parent::ofSingle($value); - } - - /** - * @return self - */ - public function filter(callable $predicate): self - { - /** @var self */ - return parent::filter($predicate); - } + /** @use GenericOptional */ + use GenericOptional; protected static function isSupported(mixed $value): bool { diff --git a/src/OptionalObject.php b/src/OptionalObject.php index 1a10b8c..75bd6ff 100644 --- a/src/OptionalObject.php +++ b/src/OptionalObject.php @@ -11,110 +11,28 @@ */ abstract class OptionalObject extends Optional { - /** @internal */ - protected const ANY_INSTANCE_OF = ''; + /** @use AbstractOptional */ + use AbstractOptional; /** - * @return self - */ - public static function empty(): self - { - /** @var self */ - return parent::empty(); - } - - /** - * @template U of T - * - * @param U $value - * - * @return self - */ - public static function of(mixed $value): self - { - /** @var self */ - return parent::of($value); - } - - /** - * @template U of T - * - * @param U|false $value - * - * @return self - */ - public static function ofFalsable(mixed $value): self - { - /** @var self */ - return parent::ofFalsable($value); - } - - /** - * @template U of T + * @param T|null $value * - * @param U|null $value - * - * @return self - */ - public static function ofNullable(mixed $value): self - { - if (static::class === OptionalObject::class) { - if ($value !== null) { - try { - /** @var self */ - return TypedOptional::of($value, OptionalObject::class); - } catch (Exception\CouldNotFindTypedOptionalForValue) { - } - } - /** @var self */ - return new class ($value) extends OptionalObject { - protected static function isInstanceOfStatic(object $obj): bool - { - return $obj instanceof OptionalObject; - } - protected static function getInstanceOf(): string - { - TypedOptional::triggerNotice(OptionalObject::class . ' does not check the instance of object.'); - /** @var class-string */ - return self::ANY_INSTANCE_OF; - } - }; - } - /** @var self */ - return parent::ofNullable($value); - } - - /** - * @template U of T - * - * @param iterable $value - * - * @return self - */ - public static function ofSingle(iterable $value): self - { - /** @var self */ - return parent::ofSingle($value); - } - - /** * @return self */ - public function filter(callable $predicate): self + protected static function createInstance(mixed $value): self { /** @var self */ - return parent::filter($predicate); - } + return new class ($value) extends OptionalObject { + protected static function isInstanceOfStatic(object $obj): bool + { + return $obj instanceof OptionalObject; + } - protected static function isSupported(mixed $value): bool - { - /** @var string $expectedInstanceOf */ - $expectedInstanceOf = static::getInstanceOf(); - return is_object($value) && ($expectedInstanceOf === self::ANY_INSTANCE_OF || $value instanceof $expectedInstanceOf); + protected static function isSupported(mixed $value): bool + { + TypedOptional::triggerNotice(OptionalObject::class . ' does not check the instance of object.'); + return is_object($value); + } + }; } - - /** - * @return class-string - */ - abstract protected static function getInstanceOf(): string; } diff --git a/src/OptionalObject/OptionalStdClass.php b/src/OptionalObject/OptionalStdClass.php index e8707e4..6a103b3 100644 --- a/src/OptionalObject/OptionalStdClass.php +++ b/src/OptionalObject/OptionalStdClass.php @@ -15,8 +15,8 @@ final class OptionalStdClass extends OptionalObject { use NonGenericOptional; - protected static function getInstanceOf(): string + protected static function isSupported(mixed $value): bool { - return stdClass::class; + return $value instanceof stdClass; } } diff --git a/tests/Some/OptionalDataObject.php b/tests/Some/OptionalDataObject.php index 47c179c..8dbd1fb 100644 --- a/tests/Some/OptionalDataObject.php +++ b/tests/Some/OptionalDataObject.php @@ -14,8 +14,8 @@ final class OptionalDataObject extends OptionalObject { use NonGenericOptional; - protected static function getInstanceOf(): string + protected static function isSupported(mixed $value): bool { - return DataObject::class; + return $value instanceof DataObject; } }