Photo by Compare Fibre on Unsplash

PHP Fibers: How PHP is Finally Warming Up to Asynchronous Programming

Byte Blog

--

Ah, PHP. For years, it was the go-to language for web development, powering everything from tiny blog sites to giant platforms like Facebook (at least in its early days). But despite all its growth, PHP always had a somewhat conservative approach to asynchronous programming – until now. With the arrival of PHP Fibers in PHP 8.1 (and a much-needed tune-up in PHP 8.4), it seems PHP is finally embracing the joys of concurrency.

So, let’s take a deep dive into PHP Fibers: what they are, how they work, and why you might find yourself grinning as you introduce them into your codebase.

What Exactly are Fibers, and Why Should You Care?

Think of fibers as lightweight threads – they let you pause and resume functions without blocking your whole application. Imagine you’re in a line at the coffee shop, ordering a latte. While you’re waiting, instead of just standing there doing nothing, you could pause your order and check your emails or chat with a friend. When your latte’s ready, you jump back into the ordering process without missing a beat.

In code, fibers allow your application to keep doing useful work while waiting for time-consuming tasks to finish. Unlike traditional synchronous PHP code, where everything runs in a single line (one command after another, no skipping ahead), fibers let you jump in and out of tasks – perfect for real-time applications that can’t afford to hang around.

Important Note on Versions: Fibers were introduced in PHP 8.1, but they’re fully functional and more stable in PHP 8.4. So if you’re still on PHP 7.x or 8.0, now might be the time for an upgrade.

Why Fibers? Didn’t PHP Already Have Asynchronous Options?

You might be thinking, “But wait! Haven’t we had options like pcntl_fork and ReactPHP for concurrency?” And you’d be right. But these methods are either complex or require additional extensions and libraries. Plus, they don’t let you write asynchronous code as naturally as fibers do.

With fibers, you don’t have to jump through hoops or install extra extensions. Just write your code, sprinkle in some fibers, and you’re good to go.

Getting Started with PHP Fibers

Now, let’s have a play with some code and get a feel for how fibers work. First, let’s check if your PHP version is ready for the fiber revolution:

php -v

If you see PHP 8.1 or higher, you’re all set! If not, well, time to talk to whoever is managing your server or, in extreme cases, brace yourself for the great migration.

The Basic Anatomy of a Fiber

The beauty of PHP Fibers is in their simplicity. Here’s how to create a fiber and get it up and running:

$fiber = new Fiber(function() {
echo "Fiber started…\n";
Fiber::suspend(); // Pause the fiber
echo "Fiber resumed…\n";
});
echo "Fiber starting…\n";
$fiber->start(); // Start the fiber
echo "Main script running…\n";
$fiber->resume(); // Resume the fiber

Here’s what’s going on:

1. We create a new Fiber with a function that does two things: prints a message, suspends itself, then prints another message.

2. We start the fiber, which begins execution until it hits Fiber::suspend().

3. The fiber “pauses” itself at Fiber::suspend(), allowing the main script to keep going.

4. Later, we call $fiber->resume(), which picks up the fiber where it left off and finishes the job.

And voilà! You’ve just created asynchronous code in PHP.

A Practical Example: Fetching Data Concurrently with Fibers

Suppose you want to fetch data from multiple APIs without waiting for each request to finish before moving on to the next. Fibers allow you to start each request, pause it, and then resume it later — letting your main script perform other tasks in the meantime.

<?php

// Function to create a fiber that simulates fetching data from an API
function fetchData(string $url, int $delay) {
return new Fiber(function() use ($url, $delay) {
echo "Starting request to $url...\n";
sleep($delay); // Simulate network delay
Fiber::suspend("Data from $url"); // Pause fiber and return simulated data
});
}

// Initialize fibers for each "API request"
$fiber1 = fetchData('https://jsonplaceholder.typicode.com/posts/1', 2);
$fiber2 = fetchData('https://jsonplaceholder.typicode.com/posts/2', 3);

// Start fibers (this initiates each "request" and pauses at Fiber::suspend)
$fiber1->start();
$fiber2->start();

echo "Performing other tasks while waiting for data...\n";

// Collect data once fibers have completed their simulated requests
$data1 = $fiber1->resume();
$data2 = $fiber2->resume();

echo "$data1\n";
echo "$data2\n";
echo "All data fetched successfully.\n";

Explanation

  1. Creating Fibers: The fetchData function creates a fiber for each "API request." Each fiber simulates a delay, suspends, and returns a message once "data" is ready.
  2. Starting Fibers: start() initiates each fiber, and the fiber suspends after starting the "request," allowing other code to run while it "waits."
  3. Non-blocking Execution: After starting both fibers, the main script proceeds with other tasks (indicated by the echo statement).
  4. Resuming Fibers: Once you’re ready for the results, you call resume() on each fiber to retrieve the data. The suspended data from Fiber::suspend() is returned when resume() is called, completing the "requests."

This might look a little odd at first, but imagine the possibilities… you could be working on other parts of your application (like rendering a page or handling user input) while data is fetched in the background.

Real-World Use Case: Asynchronous Image Processing

Let’s take it a step further. Imagine you have an application where users can upload images, and you want to apply several filters to those images. Processing each filter can take a bit of time, so let’s use fibers to handle it all in the background:

<?php

function applyFilter($image, $filter) {
return new Fiber(function() use ($image, $filter) {
echo "Applying $filter to $image...\n";
sleep(2); // Simulate filter processing delay
Fiber::suspend("$filter applied to $image."); // Suspend fiber and provide completion message
});
}

$image = 'user-uploaded-image.jpg';
$filters = ['grayscale', 'blur', 'sharpen'];

// Create a fiber for each filter
$fibers = array_map(fn($filter) => applyFilter($image, $filter), $filters);

// Start all fibers
foreach ($fibers as $fiber) {
$fiber->start();
}

echo "Processing other tasks while filters are being applied...\n";

// Resume each fiber to complete processing and collect results
foreach ($fibers as $fiber) {
if ($fiber->isSuspended()) {
$result = $fiber->resume();
echo "$result\n";
}
}

echo "All filters have been applied.\n";

This example uses fibers to apply three different filters to an image concurrently. While the filters are applied, the script can move on and “process other tasks.” When we’re ready, we resume each fiber to complete the filtering process.

PHP 8.4 and Beyond: What’s Next for Fibers?

While fibers in PHP 8.1 were an exciting start, PHP 8.4 brings several improvements that make them more stable and efficient for production use. Version 8.4 fixes some issues around fiber memory management and concurrency handling, making fibers more predictable and robust.

If you’re diving into PHP asynchronous programming, using PHP 8.4 will provide a smoother experience. It’s worth mentioning that fibers are a low-level feature – if you’re building complex applications, consider using a higher-level library (like ReactPHP) that can abstract some of the details and offer additional tools for managing concurrency.

A Word of Caution

Fibers are a powerful tool, but with great power comes great responsibility. It’s easy to go a little fiber-crazy and start pausing and resuming everything. But overuse can make your code hard to read and debug, so use fibers wisely. And remember: fiber usage is like juggling flaming swords – exciting, but best attempted with a solid grasp of the basics.

Wrapping It Up

PHP Fibers are a great addition for PHP developers who’ve long wished for a simpler way to handle asynchronous programming. They provide a clear, manageable way to work with concurrency, without the complexities of threads or external libraries. From asynchronous API calls to background processing, fibers open up a world of possibilities in PHP – making it more modern, capable, and just a little bit more fun.

So, if you’re on PHP 8.1 or higher, give fibers a spin in your next project. They might just become your new favourite feature!

--

--

Responses (2)