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.

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.
// 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.