Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions phpdoc_check.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
53 changes: 53 additions & 0 deletions src/AbstractOptional.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

Check notice on line 1 in src/AbstractOptional.php

View workflow job for this annotation

GitHub Actions / run

* [The use of `traits` is prohibited]

declare(strict_types=1);

namespace PetrKnap\Optional;

/**
* Provides internal plumbing and instantiation logic for abstract {@see Optional} implementations.

Check notice on line 8 in src/AbstractOptional.php

View workflow job for this annotation

GitHub Actions / run

* [Line length] Line exceeds 80 characters; contains 99 characters
*
* @template-covariant T of mixed type of non-null value

Check notice on line 10 in src/AbstractOptional.php

View workflow job for this annotation

GitHub Actions / run

* [Disallow mixed type hint] Usage of "mixed" type hint is disallowed.
*
* @phpstan-require-extends Optional
*/
trait AbstractOptional
{
/** @use GenericOptional<T> */
use GenericOptional;

/**
* @template U of T
*
* @param U|null $value
*
* @return self<U>
*/
public static function ofNullable(mixed $value): self // @phpstan-ignore generics.notSubtype

Check notice on line 26 in src/AbstractOptional.php

View workflow job for this annotation

GitHub Actions / run

* [Line length] Line exceeds 80 characters; contains 96 characters
{
if (static::class === self::class) {
if ($value !== null) {
try {
/** @var self<U> */ // @phpstan-ignore generics.notSubtype

Check notice on line 31 in src/AbstractOptional.php

View workflow job for this annotation

GitHub Actions / run

* [Inline doc comment declaration] Invalid inline documentation comment format "@var self<U>", expected "@var type $variableName Optional description".
return TypedOptional::of($value, static::class);
} catch (Exception\CouldNotFindTypedOptionalForValue) {

Check notice on line 33 in src/AbstractOptional.php

View workflow job for this annotation

GitHub Actions / run

* [Empty statement] Empty CATCH statement detected
}
}
/** @var self<U> */

Check notice on line 36 in src/AbstractOptional.php

View workflow job for this annotation

GitHub Actions / run

* [Inline doc comment declaration] Invalid inline documentation comment format "@var self<U>", expected "@var type $variableName Optional description".
return self::createInstance($value); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType

Check notice on line 37 in src/AbstractOptional.php

View workflow job for this annotation

GitHub Actions / run

* [Line length] Line exceeds maximum limit of 100 characters; contains 125 characters
}
/** @var self<U> */

Check notice on line 39 in src/AbstractOptional.php

View workflow job for this annotation

GitHub Actions / run

* [Inline doc comment declaration] Invalid inline documentation comment format "@var self<U>", expected "@var type $variableName Optional description".
return parent::ofNullable($value); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType

Check notice on line 40 in src/AbstractOptional.php

View workflow job for this annotation

GitHub Actions / run

* [Line length] Line exceeds maximum limit of 100 characters; contains 119 characters
}

/**
* @template U of T
*
* @param U|null $value
*
* @return self<U>
*/
abstract protected static function createInstance(mixed $value): self;

abstract protected static function isInstanceOfStatic(object $obj): bool;
}
85 changes: 85 additions & 0 deletions src/GenericOptional.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

declare(strict_types=1);

namespace PetrKnap\Optional;

/**
* Provides strict type hints and generic behavior for concrete {@see Optional} implementations.
*
* @template-covariant T of mixed type of non-null value
*
* @phpstan-require-extends Optional
*/
trait GenericOptional
{
/**
* @return self<T>
*/
public static function empty(): self
{
/** @var self<T> */
return parent::empty();
}

/**
* @template U of T
*
* @param U $value
*
* @return self<U>
*/
public static function of(mixed $value): self // @phpstan-ignore generics.notSubtype
{
/** @var self<U> */
return parent::of($value); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType
}

/**
* @template U of T
*
* @param U|false $value
*
* @return self<U>
*/
public static function ofFalsable(mixed $value): self // @phpstan-ignore generics.notSubtype
{
/** @var self<U> */
return parent::ofFalsable($value); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType
}

/**
* @template U of T
*
* @param U|null $value
*
* @return self<U>
*/
public static function ofNullable(mixed $value): self // @phpstan-ignore generics.notSubtype
{
/** @var self<U> */
return parent::ofNullable($value); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType
}

/**
* @template U of T
*
* @param iterable<U> $value
*
* @return self<U>
*/
public static function ofSingle(iterable $value): self // @phpstan-ignore generics.notSubtype
{
/** @var self<U> */
return parent::ofSingle($value); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType
}

/**
* @return self<T>
*/
public function filter(callable $predicate): self // @phpstan-ignore generics.notSubtype
{
/** @var self<T> */
return parent::filter($predicate); // @phpstan-ignore generics.notSubtype, argument.type, argument.templateType
}
}
2 changes: 1 addition & 1 deletion src/NonGenericOptional.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
2 changes: 1 addition & 1 deletion src/Optional.php
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ public function orElseThrow(
}

/**
* @internal overridden by abstracts
* @internal overridden by {@see AbstractOptional}
*/
protected static function isInstanceOfStatic(object $obj): bool
{
Expand Down
71 changes: 2 additions & 69 deletions src/OptionalArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,75 +11,8 @@
*/
final class OptionalArray extends Optional
{
/**
* @return self<T>
*/
public static function empty(): self
{
/** @var self<T> */
return parent::empty();
}

/**
* @template U of T
*
* @param U $value
*
* @return self<U>
*/
public static function of(mixed $value): self
{
/** @var self<U> */
return parent::of($value);
}

/**
* @template U of T
*
* @param U|false $value
*
* @return self<U>
*/
public static function ofFalsable(mixed $value): self
{
/** @var self<U> */
return parent::ofFalsable($value);
}

/**
* @template U of T
*
* @param U|null $value
*
* @return self<U>
*/
public static function ofNullable(mixed $value): self
{
/** @var self<U> */
return parent::ofNullable($value);
}

/**
* @template U of T
*
* @param iterable<U> $value
*
* @return self<U>
*/
public static function ofSingle(iterable $value): self
{
/** @var self<U> */
return parent::ofSingle($value);
}

/**
* @return self<T>
*/
public function filter(callable $predicate): self
{
/** @var self<T> */
return parent::filter($predicate);
}
/** @use GenericOptional<T> */
use GenericOptional;

protected static function isSupported(mixed $value): bool
{
Expand Down
112 changes: 15 additions & 97 deletions src/OptionalObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,110 +11,28 @@
*/
abstract class OptionalObject extends Optional
{
/** @internal */
protected const ANY_INSTANCE_OF = '';
/** @use AbstractOptional<T> */
use AbstractOptional;

/**
* @return self<T>
*/
public static function empty(): self
{
/** @var self<T> */
return parent::empty();
}

/**
* @template U of T
*
* @param U $value
*
* @return self<U>
*/
public static function of(mixed $value): self
{
/** @var self<U> */
return parent::of($value);
}

/**
* @template U of T
*
* @param U|false $value
*
* @return self<U>
*/
public static function ofFalsable(mixed $value): self
{
/** @var self<U> */
return parent::ofFalsable($value);
}

/**
* @template U of T
* @param T|null $value
*
* @param U|null $value
*
* @return self<U>
*/
public static function ofNullable(mixed $value): self
{
if (static::class === OptionalObject::class) {
if ($value !== null) {
try {
/** @var self<U> */
return TypedOptional::of($value, OptionalObject::class);
} catch (Exception\CouldNotFindTypedOptionalForValue) {
}
}
/** @var self<U> */
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<U> */
return parent::ofNullable($value);
}

/**
* @template U of T
*
* @param iterable<U> $value
*
* @return self<U>
*/
public static function ofSingle(iterable $value): self
{
/** @var self<U> */
return parent::ofSingle($value);
}

/**
* @return self<T>
*/
public function filter(callable $predicate): self
protected static function createInstance(mixed $value): self
{
/** @var self<T> */
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;
}
4 changes: 2 additions & 2 deletions src/OptionalObject/OptionalStdClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Loading
Loading