@@ -96,6 +96,73 @@ function trap(callable $callback, string $exceptionClass = \Exception::class): R
9696 }
9797}
9898
99+ /**
100+ * Wrap a callable into one that transforms its returned value or thrown exception
101+ * into a `Result` like `Result\trap()` does.
102+ *
103+ * # Examples
104+ *
105+ * Successful execution:
106+ *
107+ * ```
108+ * self::assertEq(Result\ok(3), Result\ify(fn () => 3)());
109+ * ```
110+ *
111+ * Checked exception:
112+ *
113+ * ```
114+ * $x = Result\ify(fn () => new \DateTimeImmutable("2020-30-30 UTC"))();
115+ * self::assertTrue($x->isErr());
116+ * $x->unwrap();
117+ * // @throws Exception Failed to parse time string (2020-30-30 UTC) at position 6 (0): Unexpected character
118+ * ```
119+ *
120+ * Unchecked exception:
121+ *
122+ * ```
123+ * Result\ify(fn () => 1/0)();
124+ * // @throws DivisionByZeroError Division by zero
125+ * ```
126+ *
127+ * Result-ify `strtotime()`:
128+ *
129+ * ```
130+ * $strtotime = Result\ify(
131+ * static fn (...$args)
132+ * => \strtotime(...$args)
133+ * ?: throw new \RuntimeException("Could not convert string to time"),
134+ * );
135+ *
136+ * self::assertEq($strtotime("2015-09-21 UTC midnight")->unwrap(), 1442793600);
137+ *
138+ * $r = $strtotime("nope");
139+ * self::assertTrue($r->isErr());
140+ * $r->unwrap(); // @throws RuntimeException Could not convert string to time
141+ * ```
142+ *
143+ * @template U
144+ * @template E of \Throwable
145+ * @param callable(mixed...):U $callback
146+ * @param class-string<E> $exceptionClass
147+ * @return \Closure(mixed...):Result<U,E>
148+ */
149+ #[ExamplesSetup(IgnoreUnusedResults::class)]
150+ function ify (callable $ callback , string $ exceptionClass = \Exception::class): \Closure
151+ {
152+ return static function (...$ args ) use ($ callback , $ exceptionClass ): Result
153+ {
154+ try {
155+ return Result \ok ($ callback (...$ args ));
156+ } catch (\Throwable $ th ) {
157+ if (\is_a ($ th , $ exceptionClass )) {
158+ return Result \err ($ th );
159+ }
160+
161+ throw $ th ;
162+ }
163+ };
164+ }
165+
99166/**
100167 * Converts from `Result<Result<T, E>, E>` to `Result<T, E>`.
101168 *
0 commit comments