$channel */ $channel = new ThreadSafeArray(); $thread = new class($channel) extends NativeThread{ /** * @phpstan-param ThreadSafeArray $channel */ public function __construct( private ThreadSafeArray $channel, ){} public function run() : void{ require dirname(__DIR__, 2) . '/vendor/autoload.php'; $channel = $this->channel; $reader = new ConsoleReader(); while(true){ // @phpstan-ignore-line $line = $reader->readLine(); if($line !== null){ $channel->synchronized(function() use ($channel, $line) : void{ $channel[] = $line; $channel->notify(); }); } } } }; $thread->start(NativeThread::INHERIT_NONE); while(!feof($socket)){ $line = $channel->synchronized(function() use ($channel) : ?string{ if(count($channel) === 0){ $channel->wait(1_000_000); } $line = $channel->shift(); return $line; }); if(@fwrite($socket, ($line ?? "") . "\n") === false){ //Always send even if there's no line, to check if the parent is alive //If the parent process was terminated forcibly, it won't close the connection properly, so feof() will return //false even though the connection is actually broken. However, fwrite() will fail. break; } } //For simplicity's sake, we don't bother with a graceful shutdown here. //The parent process would normally forcibly terminate the child process anyway, so we only reach this point if the //parent process was terminated forcibly and didn't clean up after itself. Process::kill(Process::pid());