Skip to content

Commit

Permalink
refactor: refactored equals method to have behavior of Java version…
Browse files Browse the repository at this point in the history
… and opened `Optional`
  • Loading branch information
petrknap committed May 12, 2024
1 parent 1c37072 commit 8dab530
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 28 deletions.
47 changes: 28 additions & 19 deletions src/Optional.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
* @see https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
*/
final class Optional
class Optional
{
private bool|null $wasPresent = null;

Expand All @@ -21,45 +21,41 @@ final class Optional
*
* @param T|null $value
*/
public function __construct(
private readonly mixed $value,
final public function __construct(
protected readonly mixed $value,
) {
if ($this->value !== null && !static::isSupported($this->value)) {
throw new InvalidArgumentException('Value is not supported.');
}
}

/**
* @return self<T>
*/
public static function empty(): self
public static function empty(): static
{
return self::ofNullable(null);
return new static(null);
}

/**
* @param T $value
*
* @return self<T>
*/
public static function of(mixed $value): self
public static function of(mixed $value): static
{
return $value !== null ? self::ofNullable($value) : throw new InvalidArgumentException('Value must not be null.');
return $value !== null ? new static($value) : throw new InvalidArgumentException('Value must not be null.');
}

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

public function equals(mixed $obj): bool
{
if ($obj instanceof Optional) {
if ($obj instanceof static) {
$obj = $obj->isPresent() ? $obj->get() : null;
}
return $this->value === $obj;
return ($obj === null || static::isSupported($obj)) && $this->value == $obj;
}

/**
Expand Down Expand Up @@ -113,7 +109,8 @@ public function orElseGet(callable $otherSupplier): mixed
if ($this->value !== null) {
return $this->value;
}
return $otherSupplier() ?? throw new InvalidArgumentException('Other supplier must return value.');
$other = $otherSupplier();
return static::isSupported($other) ? $other : throw new InvalidArgumentException('Other supplier must return supported other.');
}

/**
Expand All @@ -136,4 +133,16 @@ public function orElseThrow(callable $exceptionSupplier): mixed
throw new InvalidArgumentException('Exception supplier must return ' . Throwable::class . '.');
});
}

/**
* @param T|mixed $value not null
*/
protected static function isSupported(mixed $value): bool
{
trigger_error(
static::class . ' does not check the type of value.',
error_level: E_USER_NOTICE,
);
return $value !== null;
}
}
26 changes: 17 additions & 9 deletions tests/OptionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,24 @@ public function testMethodEqualsWorks(Optional $optional, mixed $obj, bool $expe

public static function dataMethodEqualsWorks(): array
{
$optionalValue = Optional::of(self::VALUE);
$optionalEmpty = Optional::empty();
$object1 = new \stdClass();
$object1->property = self::VALUE;
$object2 = new \stdClass();
$object2->property = self::VALUE;
$object3 = new \stdClass();
$object3->property = self::OTHER;
return [
'equal (value)' => [$optionalValue, self::VALUE, true],
'equal (optional)' => [$optionalValue, Optional::of(self::VALUE), true],
'equal (empty)' => [$optionalEmpty, Optional::empty(), true],
'not equal (value)' => [$optionalValue, self::OTHER, false],
'not equal (optional)' => [$optionalValue, Optional::of(self::OTHER), false],
'not equal (empty-present)' => [$optionalEmpty, $optionalValue, false],
'not equal (present-empty)' => [$optionalValue, $optionalEmpty, false],
'equal (value)' => [Optional::of(self::VALUE), self::VALUE, true],
'equal (optional)' => [Optional::of(self::VALUE), Optional::of(self::VALUE), true],
'equal (object)' => [Optional::of($object1), $object2, true],
'equal (optional<object>)' => [Optional::of($object1), Optional::of($object2), true],
'equal (empty)' => [Optional::empty(), Optional::empty(), true],
'not equal (value)' => [Optional::of(self::VALUE), self::OTHER, false],
'not equal (optional)' => [Optional::of(self::VALUE), Optional::of(self::OTHER), false],
'not equal (object)' => [Optional::of($object1), $object3, false],
'not equal (optional<object>)' => [Optional::of($object1), Optional::of($object3), false],
'not equal (empty-present)' => [Optional::empty(), Optional::of(self::VALUE), false],
'not equal (present-empty)' => [Optional::of(self::VALUE), Optional::empty(), false],
];
}

Expand Down

0 comments on commit 8dab530

Please sign in to comment.