1: <?php
2:
3: declare(strict_types=1);
4:
5: /**
6: * This file is part of the Nexus framework.
7: *
8: * (c) John Paul E. Balandan, CPA <paulbalandan@gmail.com>
9: *
10: * For the full copyright and license information, please view
11: * the LICENSE file that was distributed with this source code.
12: */
13:
14: namespace Nexus\Result;
15:
16: /**
17: * A PHP implementation of Rust's Result enum.
18: *
19: * `Result<T, E>` is the type used for returning and propagating errors. It is
20: * an enum with the variants, `Ok(T)`, representing success and containing a
21: * value, and `Err(E)`, representing error and containing an error value.
22: *
23: * @template T
24: * @template E
25: *
26: * @see https://doc.rust-lang.org/std/result/enum.Result.html
27: */
28: interface Result
29: {
30: /**
31: * Returns `true` if the result is `Ok`.
32: *
33: * @phpstan-assert-if-true Ok<T> $this
34: * @phpstan-assert-if-false Err<E> $this
35: */
36: public function isOk(): bool;
37:
38: /**
39: * Returns `true` if the result is `Ok` and the value inside of it matches a predicate.
40: *
41: * @param (\Closure(T): bool) $predicate
42: */
43: public function isOkAnd(\Closure $predicate): bool;
44:
45: /**
46: * Returns `true` if the result is `Err`.
47: *
48: * @phpstan-assert-if-true Err<E> $this
49: * @phpstan-assert-if-false Ok<T> $this
50: */
51: public function isErr(): bool;
52:
53: /**
54: * Returns `true` if the result is `Err` and the value inside of it matches a predicate.
55: *
56: * @param (\Closure(E): bool) $predicate
57: */
58: public function isErrAnd(\Closure $predicate): bool;
59:
60: /**
61: * Maps a `Result<T, E>` to `Result<U, E>` by applying a function to a
62: * contained `Ok` value, leaving an `Err` value untouched.
63: *
64: * @template U
65: *
66: * @param (\Closure(T): U) $predicate
67: *
68: * @return self<U, E>
69: */
70: public function map(\Closure $predicate): self;
71:
72: /**
73: * Returns the provided default (if `Err`), or applies a function to the contained value
74: * (if `Ok`).
75: *
76: * Arguments passed to `Result::mapOr()` are eagerly evaluated; if you are passing the result
77: * of a method call, it is recommended to use `Result::mapOrElse()`, which is lazily
78: * evaluated.
79: *
80: * @template U
81: *
82: * @param U $default
83: * @param (\Closure(T): U) $predicate
84: *
85: * @return U
86: */
87: public function mapOr(mixed $default, \Closure $predicate): mixed;
88:
89: /**
90: * Maps a `Result<T, E>` to `U` by applying fallback function `$default` to a contained
91: * `Err` value, or function `$predicate` to a contained `Ok` value.
92: *
93: * This method can be used to unpack a successful result while handling an error.
94: *
95: * @template U
96: *
97: * @param (\Closure(E): U) $default
98: * @param (\Closure(T): U) $predicate
99: *
100: * @return U
101: */
102: public function mapOrElse(\Closure $default, \Closure $predicate): mixed;
103:
104: /**
105: * Maps a `Result<T, E>` to `Result<T, F>` by applying a function to a contained
106: * `Err` value, leaving an `Ok` value untouched.
107: *
108: * This method can be used to pass through a successful result while handling an error.
109: *
110: * @template F
111: *
112: * @param (\Closure(E): F) $predicate
113: *
114: * @return self<T, F>
115: */
116: public function mapErr(\Closure $predicate): self;
117:
118: /**
119: * Returns the contained `Ok` value.
120: *
121: * Because this method may throw, its use is generally discouraged. Instead, prefer to
122: * use pattern matching and handle the `Err` case explicitly, or call `Result::unwrapOr()`,
123: * or `Result::unwrapOrElse()`.
124: *
125: * @return T
126: *
127: * @throws UnwrappedResultException if result is `Err`
128: */
129: public function unwrap(): mixed;
130:
131: /**
132: * Returns the contained `Ok` value or a provided `$default`.
133: *
134: * Arguments passed to `Result::unwrapOr()` are eagerly evaluated; if you are passing
135: * the result of a method call, it is recommended to use `Result::unwrapOrElse()`,
136: * which is lazily evaluated.
137: *
138: * @template U
139: *
140: * @param U $default
141: *
142: * @return T|U
143: */
144: public function unwrapOr(mixed $default): mixed;
145:
146: /**
147: * Returns the contained `Ok` value or computes it from a closure.
148: *
149: * @template U
150: *
151: * @param (\Closure(E): U) $op
152: *
153: * @return T|U
154: */
155: public function unwrapOrElse(\Closure $op): mixed;
156:
157: /**
158: * Returns the contained `Err` value.
159: *
160: * Throws if the value is an `Ok`, with a custom exception message
161: * provided by the `Ok`’s value.
162: *
163: * @return E
164: *
165: * @throws UnwrappedResultException if result is `Ok`
166: */
167: public function unwrapErr(): mixed;
168:
169: /**
170: * Returns `$res` if the result is `Ok`, otherwise returns the `Err` value of self.
171: *
172: * Arguments passed to `Result::and()` are eagerly evaluated; if you are passing the
173: * result of a method call, it is recommended to use `Result::andThen()`, which is
174: * lazily evaluated.
175: *
176: * @template U
177: *
178: * @param self<U, E> $res
179: *
180: * @return self<U, E>
181: */
182: public function and(self $res): self;
183:
184: /**
185: * Calls `$op` if the result is `Ok`, otherwise returns the `Err` value of self.
186: *
187: * This method can be used for control flow based on `Result` values. Often used to chain
188: * fallible operations that may return `Err`.
189: *
190: * @template U
191: *
192: * @param (\Closure(T): self<U, E>) $op
193: *
194: * @return self<U, E>
195: */
196: public function andThen(\Closure $op): self;
197:
198: /**
199: * Returns `$res` if the result is `Err`, otherwise returns the `Ok` value of self.
200: *
201: * Arguments passed to `Result::or()` are eagerly evaluated; if you are passing the
202: * result of a method call, it is recommended to use `Result::orElse()`, which is
203: * lazily evaluated.
204: *
205: * @template F
206: *
207: * @param self<T, F> $res
208: *
209: * @return self<T, F>
210: */
211: public function or(self $res): self;
212:
213: /**
214: * Calls `$op` if the result is `Err`, otherwise returns the `Ok` value of self.
215: *
216: * This method can be used for control flow based on result values.
217: *
218: * @template F
219: *
220: * @param (\Closure(E): self<T, F>) $op
221: *
222: * @return self<T, F>
223: */
224: public function orElse(\Closure $op): self;
225: }
226: