write = $read; } else { $this->write = $write; } $this->read = $read; $this->errorHandler = function ($errno, $errstr) { throw new ChannelException(sprintf('Received corrupted data. Errno: %d; %s', $errno, $errstr)); }; } /** * {@inheritdoc} */ public function send($data): \Generator { // Serialize the data to send into the channel. try { $serialized = serialize($data); } catch (\Throwable $exception) { throw new SerializationException( 'The given data cannot be sent because it is not serializable.', $exception ); } $length = strlen($serialized); try { yield from $this->write->write(pack('CL', 0, $length) . $serialized); } catch (\Throwable $exception) { throw new ChannelException('Sending on the channel failed. Did the context die?', $exception); } return $length; } /** * {@inheritdoc} */ public function receive(): \Generator { // Read the message length first to determine how much needs to be read from the stream. $length = self::HEADER_LENGTH; $buffer = ''; $remaining = $length; try { do { $buffer .= yield from $this->read->read($remaining); } while ($remaining = $length - strlen($buffer)); $data = unpack('Cprefix/Llength', $buffer); if (0 !== $data['prefix']) { throw new ChannelException('Invalid header received.'); } $buffer = ''; $remaining = $length = $data['length']; do { $buffer .= yield from $this->read->read($remaining); } while ($remaining = $length - strlen($buffer)); } catch (\Throwable $exception) { throw new ChannelException('Reading from the channel failed. Did the context die?', $exception); } set_error_handler($this->errorHandler); // Attempt to unserialize the received data. try { $data = unserialize($buffer); } catch (\Throwable $exception) { throw new SerializationException('Exception thrown when unserializing data.', $exception); } finally { restore_error_handler(); } return $data; } }