*/ public static function success(mixed $value): self { return new self($value, null, true); } /** * Create failed result * * @template U * @param Throwable $error * @param string|null $boundaryName * @return BoundaryResult */ public static function failure(Throwable $error, ?string $boundaryName = null): self { return new self(null, $error, false, $boundaryName); } /** * Check if operation was successful */ public function isSuccess(): bool { return $this->isSuccess; } /** * Check if operation failed */ public function isFailure(): bool { return ! $this->isSuccess; } /** * Get the result value (only if successful) * * @return T * @throws BoundaryFailedException */ public function getValue(): mixed { if (! $this->isSuccess) { throw new BoundaryFailedException( 'Cannot get value from failed result', $this->boundaryName ?? 'unknown', $this->error ); } return $this->value; } /** * Get the error (only if failed) */ public function getError(): ?Throwable { return $this->error; } /** * Get boundary name */ public function getBoundaryName(): ?string { return $this->boundaryName; } /** * Get value or return default if failed * * @param T $default * @return T */ public function getValueOrDefault(mixed $default): mixed { return $this->isSuccess ? $this->value : $default; } /** * Get value or execute fallback function if failed * * @param callable(): T $fallback * @return T */ public function getValueOrElse(callable $fallback): mixed { return $this->isSuccess ? $this->value : $fallback(); } /** * Transform the result if successful * * @template U * @param callable(T): U $mapper * @return BoundaryResult */ public function map(callable $mapper): self { if (! $this->isSuccess) { return new self(null, $this->error, false, $this->boundaryName); } try { $transformed = $mapper($this->value); return new self($transformed, null, true, $this->boundaryName); } catch (Throwable $e) { return new self(null, $e, false, $this->boundaryName); } } /** * Chain another operation if current result is successful * * @template U * @param callable(T): BoundaryResult $mapper * @return BoundaryResult */ public function flatMap(callable $mapper): self { if (! $this->isSuccess) { return new self(null, $this->error, false, $this->boundaryName); } try { return $mapper($this->value); } catch (Throwable $e) { return new self(null, $e, false, $this->boundaryName); } } /** * Execute callback if result is successful * * @param callable(T): void $callback * @return self */ public function onSuccess(callable $callback): self { if ($this->isSuccess) { $callback($this->value); } return $this; } /** * Execute callback if result failed * * @param callable(Throwable): void $callback * @return self */ public function onFailure(callable $callback): self { if (! $this->isSuccess && $this->error) { $callback($this->error); } return $this; } /** * Convert to array representation */ public function toArray(): array { return [ 'success' => $this->isSuccess, 'value' => $this->isSuccess ? $this->value : null, 'error' => $this->error?->getMessage(), 'boundary' => $this->boundaryName, ]; } }