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
32 changes: 12 additions & 20 deletions phpdoc_check.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,20 @@ public function rawInputs(int $int = 0, string $string = ''): void {}
$concrete->filter(static fn (int $value): bool => true);
$concrete->filter(static fn (string $value): bool => true); // @phpstan-ignore argument.type
// - flatMap
$abstract->flatMap(static fn (int $value): Optional => $abstract);
$abstract->flatMap(static fn (string $value): Optional => $abstract); // @phpstan-ignore argument.type
$concrete->flatMap(static fn (int $value): Some\Optional => $concrete);
$concrete->flatMap(static fn (string $value): Some\Optional => $concrete); // @phpstan-ignore argument.type
$abstractFlatMapped = $abstract->flatMap(static fn (int $value): Some\Optional => Some\Optional::of(''));
$abstract->flatMap(static fn (string $value): Some\Optional => Some\Optional::of(1)); // @phpstan-ignore argument.type
$concreteFlatMapped = $concrete->flatMap(static fn (int $value): Optional => Optional::of(''));
$concrete->flatMap(static fn (string $value): Optional => Optional::of(1)); // @phpstan-ignore argument.type
// - ifPresent
$abstract->ifPresent(static fn (int $value): int => $value);
$abstract->ifPresent(static fn (string $value): string => $value); // @phpstan-ignore argument.type
$concrete->ifPresent(static fn (int $value): int => $value);
$concrete->ifPresent(static fn (string $value): string => $value); // @phpstan-ignore argument.type
// - map
$abstract->map(static fn (int $value): int => $value);
$abstract->map(static fn (string $value): string => $value); // @phpstan-ignore argument.type
$concrete->map(static fn (int $value): int => $value);
$concrete->map(static fn (string $value): string => $value); // @phpstan-ignore argument.type
$abstractMapped = $abstract->map(static fn (int $value): string => '');
$abstract->map(static fn (string $value): int => 1); // @phpstan-ignore argument.type
$concreteMapped = $concrete->map(static fn (int $value): string => '');
$concrete->map(static fn (string $value): int => 1); // @phpstan-ignore argument.type
// - orElse
$abstractOrElse = $abstract->orElse(0);
$abstractOrElseNull = $abstract->orElse(null);
Expand All @@ -131,33 +131,25 @@ public function rawInputs(int $int = 0, string $string = ''): void {}
$concreteOrElseGet = $concrete->orElseGet(static fn (): int => 0);
$concrete->orElseGet(static fn (): string => ''); // @phpstan-ignore argument.type

// Re-map & filter it
$abstractMapped = $abstract->map(static fn (int $value): string => '');
$abstractMappedFiltered = $abstractMapped->filter(static fn (string $value): bool => true);
$abstractMapped->filter(static fn (int $value): bool => true); // @phpstan-ignore argument.type
$concreteMapped = $concrete->map(static fn (int $value): string => '');
$concreteMappedFiltered = $concreteMapped->filter(static fn (string $value): bool => true);
$concreteMapped->filter(static fn (int $value): bool => true); // @phpstan-ignore argument.type

// Check it
// - abstract
$check->genericInputOptions(abstract: $abstract); // @phpstan-ignore argument.type
$check->genericInputOptions(abstract: $abstractMappedFiltered);
$check->rawInputs(int: $abstract->get());
$check->rawInputs(int: $abstractOrElse);
$check->rawInputs(int: $abstractOrElseGet);
$check->rawInputs(int: $abstractOrElseNull); // @phpstan-ignore argument.type
$check->rawInputs(int: $abstractOrElseNull ?? 0);
$check->rawInputs(string: $abstractMappedFiltered->orElseThrow());
$check->rawInputs(string: $abstractMapped->orElseThrow());
$check->rawInputs(string: $abstractFlatMapped->orElseThrow());
// - concrete
$check->genericInputOptions(concrete: $concrete); // @phpstan-ignore argument.type
$check->genericInputOptions(concrete: $concreteMappedFiltered);
$check->rawInputs(int: $concrete->get());
$check->rawInputs(int: $concreteOrElse);
$check->rawInputs(int: $concreteOrElseGet);
$check->rawInputs(int: $concreteOrElseNull); // @phpstan-ignore argument.type
$check->rawInputs(int: $concreteOrElseNull ?? 0);
$check->rawInputs(string: $concreteMappedFiltered->orElseThrow());
$check->rawInputs(string: $concreteMapped->orElseThrow());
$check->rawInputs(string: $concreteFlatMapped->orElseThrow());

// ---------------------------------------------------------------------------------------------------------------------

Expand Down
23 changes: 12 additions & 11 deletions src/JavaSe8/Optional.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
interface Optional
{
/**
* Returns an empty {@see self::class} instance.
* Returns an empty {@see Optional} instance.
*
* @return self<T>
*/
public static function empty(): self;

/**
* Returns an {@see self::class} with the specified present non-null value.
* Returns an {@see Optional} with the specified present non-null value.
*
* @template U of T
*
Expand All @@ -34,7 +34,7 @@ public static function empty(): self;
public static function of(mixed $value): self;

/**
* Returns an {@see self::class} describing the specified value, if non-null, otherwise returns an empty {@see self::class}.
* Returns an {@see Optional} describing the specified value, if non-null, otherwise returns an empty {@see Optional}.
*
* @template U of T
*
Expand All @@ -45,12 +45,12 @@ public static function of(mixed $value): self;
public static function ofNullable(mixed $value): self;

/**
* Indicates whether some other object is "equal to" this {@see self::class}.
* Indicates whether some other object is "equal to" this {@see Optional}.
*/
public function equals(mixed $obj): bool;

/**
* 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}.
* If a value is present, and the value matches the given predicate, return an {@see Optional} describing the value, otherwise return an empty {@see Optional}.
*
* @param callable(T): bool $predicate
*
Expand All @@ -59,18 +59,19 @@ public function equals(mixed $obj): bool;
public function filter(callable $predicate): self;

/**
* 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}.
* If a value is present, apply the provided {@see Optional}-bearing mapping function to it, return that result, otherwise return an empty {@see Optional}.
*
* @template U of mixed type of non-null value
* @template V of Optional<U>
*
* @param callable(T): self<U> $mapper
* @param callable(T): V $mapper
*
* @return self<U>
* @return V|Optional<U>
*/
public function flatMap(callable $mapper): self;
public function flatMap(callable $mapper): Optional;

/**
* If a value is present in this {@see self::class}, returns the value, otherwise throws {@see NoSuchElementException}.
* If a value is present in this {@see Optional}, returns the value, otherwise throws {@see NoSuchElementException}.
*
* @return T
*
Expand All @@ -91,7 +92,7 @@ public function ifPresent(callable $consumer): void;
public function isPresent(): bool;

/**
* If a value is present, apply the provided mapping function to it, and if the result is non-null, return an {@see self::class} describing the result.
* If a value is present, apply the provided mapping function to it, and if the result is non-null, return an {@see Optional} describing the result.
*
* @template U of mixed type of non-null value
*
Expand Down
24 changes: 6 additions & 18 deletions src/Optional.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,31 +155,19 @@ public function filter(callable $predicate): self

/**
* @template U of mixed type of non-null value
* @template V of Optional<U>
* @template V of JavaSe8\Optional<U>
*
* @param ($empty is null ? callable(T): JavaSe8\Optional<U> : callable(T): V) $mapper
* @param V|null $empty
* @param callable(T): V $mapper
*
* @return ($empty is null ? Optional<U> : V)
*
* @note do not use {@see self}/{@see static}, it maps itself to another {@see Optional}
*
* @todo return JavaSe8\Optional
* @return V|self<U>
*/
public function flatMap(callable $mapper, Optional|null $empty = null): Optional
public function flatMap(callable $mapper): JavaSe8\Optional
{
if ($this->value === null) {
/** @var V */
return $empty ?? Optional::empty();
return $this;
}

/** @var JavaSe8\Optional<T>|"" $mapped */
$mapped = $mapper($this->value);
return match (true) {
$mapped instanceof Optional => $mapped,
$mapped instanceof JavaSe8\Optional => $mapped->isPresent() ? Optional::of($mapped->get()) : Optional::empty(),
default => throw new InvalidArgumentException('Mapper must return instance of ' . JavaSe8\Optional::class . '.'),
};
return $mapper($this->value);
}

public function get(): mixed
Expand Down
13 changes: 13 additions & 0 deletions src/OptionalOverrides.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
/**
* @return self<T>
*/
public static function empty(): self

Check notice on line 21 in src/OptionalOverrides.php

View workflow job for this annotation

GitHub Actions / run

* [Useless overriding method] Possible useless method overriding detected
{
/** @var self<T> */
return parent::empty();
Expand All @@ -33,7 +33,7 @@
*
* @throws InvalidArgumentException
*/
public static function of(mixed $value): self

Check notice on line 36 in src/OptionalOverrides.php

View workflow job for this annotation

GitHub Actions / run

* [Useless overriding method] Possible useless method overriding detected
{
/** @var self<U> */
return parent::of($value);
Expand All @@ -50,7 +50,7 @@
*
* @throws InvalidArgumentException
*/
public static function ofFalsable(mixed $value): self

Check notice on line 53 in src/OptionalOverrides.php

View workflow job for this annotation

GitHub Actions / run

* [Useless overriding method] Possible useless method overriding detected
{
/** @var self<U> */
return parent::ofFalsable($value);
Expand All @@ -63,7 +63,7 @@
*
* @return self<U>
*/
public static function ofNullable(mixed $value): self

Check notice on line 66 in src/OptionalOverrides.php

View workflow job for this annotation

GitHub Actions / run

* [Useless overriding method] Possible useless method overriding detected
{
/** @var self<U> */
return parent::ofNullable($value);
Expand All @@ -80,7 +80,7 @@
*
* @throws InvalidArgumentException
*/
public static function ofSingle(iterable $value): self

Check notice on line 83 in src/OptionalOverrides.php

View workflow job for this annotation

GitHub Actions / run

* [Useless overriding method] Possible useless method overriding detected
{
/** @var self<U> */
return parent::ofSingle($value);
Expand All @@ -89,12 +89,25 @@
/**
* @return self<T>
*/
public function filter(callable $predicate): self

Check notice on line 92 in src/OptionalOverrides.php

View workflow job for this annotation

GitHub Actions / run

* [Useless overriding method] Possible useless method overriding detected
{
/** @var self<T> */
return parent::filter($predicate);
}

/**
* @template U of mixed type of non-null value
* @template V of JavaSe8\Optional<U>
*
* @param callable(T): V $mapper
*
* @return V|self<U>
*/
public function flatMap(callable $mapper): JavaSe8\Optional
{
return parent::flatMap($mapper);
}

/**
* @template U of mixed type of non-null value
*
Expand Down
4 changes: 2 additions & 2 deletions tests/JavaSe8/AnotherOption.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ public function ifPresent(callable $consumer): never
NotImplemented::throw(__METHOD__);
}

public function isPresent(): bool
public function isPresent(): never
{
return false;
NotImplemented::throw(__METHOD__);
}

public function map(callable $mapper): never
Expand Down
10 changes: 3 additions & 7 deletions tests/JavaSe8/OptionalTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,9 @@ private static void testFilter() {
}

private static void testFlatMap() {
/**
* @todo
* Optional $o1;
* $o1 = Optional.<Another>empty(); assert (Optional.of(1).flatMap($v -> $o1) == $o1);
*/
Optional $o2;
$o2 = Optional.<Another>empty(); assert (Optional.empty().flatMap($v -> $o2) != $o2);
Optional $anotherOption, $thisOption;
$anotherOption = Optional.<Another>empty(); assert (Optional.of(1).flatMap($v -> $anotherOption) == $anotherOption);
$thisOption = Optional.empty(); assert ($thisOption.flatMap($v -> Optional.of(new Another())) == $thisOption);
}

private static void testGetters() {
Expand Down
Loading