Simple solution if you want to reading result from child process into the parent thread that based on socket.
Hope this can be of use to someone.
<?php
function fork_process(...$callbacks)
{
$callbackSocket = [];
$callbacks = array_filter($callbacks, function ($callback) {
return $callback instanceof \Closure;
});
/* On Windows need to use AF_INET */
$domain = (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' ? AF_INET : AF_UNIX);
$pids = [];
foreach ($callbacks as $index => $callback) {
$setUpCallbackSocket = socket_create_pair($domain, SOCK_STREAM, 0, $callbackSocket[$index]);
if (!$setUpCallbackSocket) {
throw new \Exception(
"socket_create_pair failed. Reason: " . socket_strerror(socket_last_error()),
1
);
}
$pid = pcntl_fork();
if ($pid == 0) {
try {
$returnValue = $callback();
// Declare $sendingData end of line , prevent socket_read hangs
$sendingData = serialize($returnValue) . "\0\r\n";
$bufferLength = mb_strlen($sendingData, '8bit');
// If not declare $bufferLength, it is silently truncated to the length of SO_SNDBUF
// @see https://www.php.net/manual/en/function.socket-write.php
// @see https://www.php.net/manual/en/function.socket-get-option.php
socket_write($callbackSocket[$index][0], $sendingData, $bufferLength);
socket_close($callbackSocket[$index][0]);
} finally {
// Explicity kill process, or else the resource shared with parent will be closed
posix_kill(getmypid(), SIGTERM);
exit();
}
} else {
$pids[$index] = $pid;
}
}
$results = [];
foreach ($pids as $index => $pid) {
pcntl_waitpid($pid, $status);
$msg = "";
while ($resp = socket_read($callbackSocket[$index][1], 102400)) {
$msg .= $resp;
// prevent socket_read hangs
if ($msg[-1] === "\n" && $msg[-2] === "\r" && $msg[-3] === "\0") {
break;
}
}
socket_close($callbackSocket[$index][1]);
$results[] = unserialize(trim($msg));
}
return $results;
}
$time = microtime(true);
$resp = fork_process(
function () {
sleep(1);
return 'first';
},
function () {
sleep(2);
return 'second';
},
);
echo (microtime(true) - $time);
// 2.0448851585388
echo implode(' ', $resp);
// first second
?>
Inspired by https://stackoverflow.com/questions/8707339/sharing-variables-between-child-processes-in-php