1# Fiber Extension 2 3Fiber implementation for PHP using native C fibers. 4 5> **Warning** 6> Please upgrade to PHP 8.1 instead of using this extension. There are subtle differences, which can't be fixed in the extension. 7 8### Requirements 9 10- PHP 8.0 *only* (PHP 8.1+ includes Fibers, so this extension is unnecessary) 11 12## Installation 13 14Installation of the extension is similar to other PHP extensions. 15 16``` bash 17git clone https://github.com/amphp/ext-fiber 18cd ext-fiber 19phpize 20./configure 21make 22make test 23make install 24``` 25 26## API 27 28Fibers are made by creating an instance of the `Fiber` class. 29 30``` php 31final class Fiber 32{ 33 /** 34 * @param callable $callback Function to invoke when starting the fiber. 35 */ 36 public function __construct(callable $callback) {} 37 38 /** 39 * Starts execution of the fiber. Returns when the fiber suspends or terminates. 40 * 41 * @param mixed ...$args Arguments passed to fiber function. 42 * 43 * @return mixed Value from the first suspension point or NULL if the fiber returns. 44 * 45 * @throw FiberError If the fiber has already been started. 46 * @throw Throwable If the fiber callable throws an uncaught exception. 47 */ 48 public function start(mixed ...$args): mixed {} 49 50 /** 51 * Resumes the fiber, returning the given value from {@see Fiber::suspend()}. 52 * Returns when the fiber suspends or terminates. 53 * 54 * @param mixed $value 55 * 56 * @return mixed Value from the next suspension point or NULL if the fiber returns. 57 * 58 * @throw FiberError If the fiber has not started, is running, or has terminated. 59 * @throw Throwable If the fiber callable throws an uncaught exception. 60 */ 61 public function resume(mixed $value = null): mixed {} 62 63 /** 64 * Throws the given exception into the fiber from {@see Fiber::suspend()}. 65 * Returns when the fiber suspends or terminates. 66 * 67 * @param Throwable $exception 68 * 69 * @return mixed Value from the next suspension point or NULL if the fiber returns. 70 * 71 * @throw FiberError If the fiber has not started, is running, or has terminated. 72 * @throw Throwable If the fiber callable throws an uncaught exception. 73 */ 74 public function throw(Throwable $exception): mixed {} 75 76 /** 77 * @return bool True if the fiber has been started. 78 */ 79 public function isStarted(): bool {} 80 81 /** 82 * @return bool True if the fiber is suspended. 83 */ 84 public function isSuspended(): bool {} 85 86 /** 87 * @return bool True if the fiber is currently running. 88 */ 89 public function isRunning(): bool {} 90 91 /** 92 * @return bool True if the fiber has completed execution (returned or threw). 93 */ 94 public function isTerminated(): bool {} 95 96 /** 97 * @return mixed Return value of the fiber callback. NULL is returned if the fiber does not have a return statement. 98 * 99 * @throws FiberError If the fiber has not terminated or the fiber threw an exception. 100 */ 101 public function getReturn(): mixed {} 102 103 /** 104 * @return self|null Returns the currently executing fiber instance or NULL if in {main}. 105 */ 106 public static function getCurrent(): ?self {} 107 108 /** 109 * Suspend execution of the fiber. The fiber may be resumed with {@see Fiber::resume()} or {@see Fiber::throw()}. 110 * 111 * Cannot be called from {main}. 112 * 113 * @param mixed $value Value to return from {@see Fiber::resume()} or {@see Fiber::throw()}. 114 * 115 * @return mixed Value provided to {@see Fiber::resume()}. 116 * 117 * @throws FiberError Thrown if not within a fiber (i.e., if called from {main}). 118 * @throws Throwable Exception provided to {@see Fiber::throw()}. 119 */ 120 public static function suspend(mixed $value = null): mixed {} 121} 122``` 123 124A `Fiber` object is created using `new Fiber(callable $callback)` with any callable. The callable need not call `Fiber::suspend()` directly, it may be in a deeply nested call, far down the call stack (or perhaps never call `Fiber::suspend()` at all). The returned `Fiber` may be started using `Fiber->start(mixed ...$args)` with a variadic argument list that is provided as arguments to the callable used when creating the `Fiber`. 125 126`Fiber::suspend()` suspends execution of the current fiber and returns execution to the call to `Fiber->start()`, `Fiber->resume()`, or `Fiber->throw()`. The value passed to `Fiber::suspend()` is used as the return value of these methods. If the fiber throws an exception, the exception is thrown from the call to these methods. `Fiber::suspend()` will throw an instance of `FiberError` if called outside a fiber (i.e., if called from `{main}`). 127 128A suspended fiber may be resumed in one of two ways: 129 130* returning a value from `Fiber::suspend()` using `Fiber->resume()` 131* throwing an exception from `Fiber::suspend()` using `Fiber->throw()` 132 133`Fiber->getReturn()` returns the value returned from a terminated fiber (`NULL` is returned if the fiber did not return a value). This function will throw an instance of `FiberError` if the fiber has not completed execution or threw an exception. 134 135`Fiber::getCurrent()` returns the currently executing `Fiber` instance or `NULL` if called from `{main}`. This allows a fiber to store a reference to itself elsewhere, such as within an event loop callback or an array of awaiting fibers. 136 137--- 138 139### ReflectionFiber 140 141`ReflectionFiber` is used to inspect executing fibers. A `ReflectionFiber` object can be created from any `Fiber` object, even if it has not been started or if it has been finished. This reflection class is similar to `ReflectionGenerator`. 142 143``` php 144final class ReflectionFiber 145{ 146 /** 147 * @param Fiber $fiber Any Fiber object, including those that are not started or have 148 * terminated. 149 */ 150 public function __construct(Fiber $fiber) {} 151 152 /** 153 * @return Fiber The reflected Fiber object. 154 */ 155 public function getFiber(): Fiber {} 156 157 /** 158 * @return string Current file of fiber execution. 159 * 160 * @throws Error If the fiber has not been started or has terminated. 161 */ 162 public function getExecutingFile(): string {} 163 164 /** 165 * @return int Current line of fiber execution. 166 * 167 * @throws Error If the fiber has not been started or has terminated. 168 */ 169 public function getExecutingLine(): int {} 170 171 /** 172 * @param int $options Same flags as {@see debug_backtrace()}. 173 * 174 * @return array Fiber backtrace, similar to {@see debug_backtrace()} 175 * and {@see ReflectionGenerator::getTrace()}. 176 * 177 * @throws Error If the fiber has not been started or has terminated. 178 */ 179 public function getTrace(int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT): array {} 180 181 /** 182 * @return callable Callable used to create the fiber. 183 * 184 * @throws Error If the fiber has been terminated. 185 */ 186 public function getCallable(): callable {} 187} 188``` 189 190#### Unfinished Fibers 191 192Fibers that are not finished (do not complete execution) are destroyed similarly to unfinished generators, executing any pending `finally` blocks. `Fiber::suspend()` may not be invoked in a force-closed fiber, just as `yield` cannot be used in a force-closed generator. Fibers are destroyed when there are no references to the `Fiber` object. 193 194#### Fiber Stacks 195 196Each fiber is allocated a separate C stack and VM stack on the heap. The C stack is allocated using `mmap` if available, meaning physical memory is used only on demand (if it needs to be allocated to a stack value) on most platforms. Each fiber stack is allocated a maximum of 8M of memory by default, settable with an ini setting `fiber.stack_size`. Note that this memory is used for the C stack and is not related to the memory available to PHP code. VM stacks for each fiber are allocated in a similar way to generators and use a similar amount of memory and CPU. VM stacks are able to grow dynamically, so only a single VM page (4K) is initially allocated. 197 198## PHP 8.1+ 199 200This extension *only* works with PHP 8.0. The [Fiber RFC](https://wiki.php.net/rfc/fibers) was accepted and will be a part of PHP 8.1, so this extension is not necessary and incompatible with PHP 8.1 and above. 201