Parallel Processing with PHP (Part 2): Inter-Process Communication

How to send data between parent and child processes in PHP using sockets In Part 1 - "Parallel Processing with PHP: why, how, and when", we learned how to use pcntl_fork() in PHP to create parallel processes. In PHP, once a child process finishes its task (or even during the task), it often needs to send information back to the parent process. This second part will explain how to build a communication channel between parent and child processes. Why is communication important? Without a dedicated communication channel, a parent process can only rely on the child’s exit status code, which is limited to a simple numeric value (0–255). This tells the parent if the child finished successfully or if a signal terminated it, but not what the child did or why something failed. That means the parent is left guessing: Did the child complete its task as expected? What data did it generate? Was the result partial or corrupted? Was there a recoverable error? By setting up a proper communication channel, the parent process can receive detailed, structured messages, unlocking smarter behavior like: Aggregating and combining child results (e.g., JSON, serialized arrays). Automatically retrying or replacing failed tasks based on error messages. Logging what each child did, in real time or after completion. Tracking progress or updating a UI with live task status. In short, exit codes are good for controlling flow, but for meaningful collaboration, your processes need to talk, and sockets make that possible. How to communicate: the pipe between the parent and the child process In UNIX-like systems (and PHP), one of the easiest ways to make processes talk is by using a socket pair. Think of it as installing a private phone line between the parent and child processes. Each process holds one end of the line: The parent listens (reads). The child speaks (writes). The flowchart Example: child process talking to parent In the following example, the script forks a new process (child), and then manages the communication between the child and parent processes.

May 1, 2025 - 21:31
 0
Parallel Processing with PHP (Part 2): Inter-Process Communication

How to send data between parent and child processes in PHP using sockets

In Part 1 - "Parallel Processing with PHP: why, how, and when", we learned how to use pcntl_fork() in PHP to create parallel processes.

In PHP, once a child process finishes its task (or even during the task), it often needs to send information back to the parent process.

This second part will explain how to build a communication channel between parent and child processes.

Why is communication important?

Without a dedicated communication channel, a parent process can only rely on the child’s exit status code, which is limited to a simple numeric value (0–255). This tells the parent if the child finished successfully or if a signal terminated it, but not what the child did or why something failed.

That means the parent is left guessing:

  • Did the child complete its task as expected?
  • What data did it generate?
  • Was the result partial or corrupted?
  • Was there a recoverable error?

By setting up a proper communication channel, the parent process can receive detailed, structured messages, unlocking smarter behavior like:

  • Aggregating and combining child results (e.g., JSON, serialized arrays).
  • Automatically retrying or replacing failed tasks based on error messages.
  • Logging what each child did, in real time or after completion.
  • Tracking progress or updating a UI with live task status.

In short, exit codes are good for controlling flow, but for meaningful collaboration, your processes need to talk, and sockets make that possible.

How to communicate: the pipe between the parent and the child process

In UNIX-like systems (and PHP), one of the easiest ways to make processes talk is by using a socket pair.

Think of it as installing a private phone line between the parent and child processes.

Each process holds one end of the line:

  • The parent listens (reads).
  • The child speaks (writes).

The flowchart

The flowchart of child process talking to parent

Example: child process talking to parent

In the following example, the script forks a new process (child), and then manages the communication between the child and parent processes.



// Create a socket pair for communication
$sockets = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
if ($sockets === false) {
    exit("Could not create communication socket.\n");
}
list($readChannel, $writeChannel) = $sockets;

// Fork the process
$pid = pcntl_fork();

if ($pid == -1) {
    // Fork failed
    exit("Could not fork process.\n");
} elseif ($pid > 0) {
    // Parent process
    fclose($writeChannel); // Close child's socket
    echo ' Parent process. PID: ' . getmypid() . "\n";
    echo " Created child with PID: $pid\n";
    $message = fread($readChannel, 1024);
    echo " Received message from child: \"$message\"\n";

    fclose($readChannel); // Close parent's socket

} else {
    // Child process
    fclose($readChannel); // Close parent's socket
    echo '  Child process. PID: ' . getmypid() . "\n";
    echo "  Doing some work\n";
    sleep(1); // Simulate work

    $response = "Hello Parent, this is child PID " . getmypid();
    fwrite($writeChannel, $response);

    echo "  Message sent.\n";
    echo "  Doing some work\n";
    sleep(1); // Simulate additional work
    echo "  Child process done.\n";
    exit(0);
}

// Wait for child to exit
pcntl_waitpid($pid, $status);
echo " Child {$pid} has finished with status {$status}.\n";
if (pcntl_wifexited($status)) {
    echo " The child status code represents a normal exit.\n";
    echo ' The child returned the code: ' . pcntl_wexitstatus($status) . "\n";
}
if (pcntl_wifsignaled($status)) {
    echo " The child status exit because a siginal.\n";
    echo ' The child was termined by signal code: ' . pcntl_wtermsig($status) . "\n";
}


What’s happening behind the scenes?

Actor Action
Parent creates a socket pair and forks a child
Parent closes its write end of the socket, listens
Child closes its read end of the socket, writes a message
Child exits after sending a message
Parent reads the message and then waits for the child

Understanding stream_socket_pair: your private communication line

When working with parent and child processes in PHP, stream_socket_pair() is one of the easiest and safest ways to let them talk to each other.

But if you've never worked with sockets before, don’t worry, let's break it down step-by-step.

What is stream_socket_pair()?

The stream_socket_pair() function creates two connected channels (like two ends of a telephone line) inside your program.

  • Whatever you write on one side, you can read on the other side.
  • It’s a full-duplex connection, meaning both sides can technically read and write.
  • In PHP, it works locally (inside your system), without needing a network.

Here’s the basic usage:

list($parentSocket, $childSocket) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);

  • $parentSocket: the "phone" the parent will use. In the previous example, the first socket ($readChannel) was used by the parent to read messages.
  • $childSocket: the "phone" the child will use. In the previous example, the second socket ($writeChannel) was used by the child to write messages.

Now they can send messages to each other!

The two channels: read and write

Even though both sockets are capable of reading and writing, in practice in the previous example we assigned a direction to keep things clean:

Process Action Socket
Parent Read $parentSocket
Child Write $childSocket

This keeps communication simple and predictable.

Best practice: close what you don't need

After forking, both parent and child inherit both sockets.
If you’re not careful, you might accidentally leave both open in each process, causing confusing bugs like:

  • Processes hanging forever.
  • Messages are not being delivered properly.

Solution: Immediately close the end you don’t need in each process:

Process Action
Parent Close child’s socket (fclose($childSocket))
Child Close parent’s socket (fclose($parentSocket))

This ensures:

  • The parent only holds the socket it reads from.
  • The child only holds the socket it writes to.
  • No accidental data leaks.

In short

  • stream_socket_pair() creates two connected communication channels.
  • Assign one side to read and one side to write.
  • Always close the socket you don’t use in each process.
  • Now parent and child can send clean, direct messages without confusion!

Why sockets and not just exit codes?

  • Exit codes are limited (0–255).
  • Messages can be detailed (strings, JSON, serialized data).
  • Sockets allow flexible, rich communication, even multiple messages if needed.

What's next?

Now that you know how to fork processes and make them talk, you’re ready to tackle more advanced scenarios:

  • Managing multiple children at once.
  • Aggregating child results.
  • Handling timeouts and retries.