+ private $atLineStart = true;
+ private $lastChannel = null;
+
+ /**
+ * Message outputter with channeled message support. Messages on the
+ * same channel are concatenated, but any intervening messages in another
+ * channel start a new line.
+ * @param $msg String The message without trailing newline
+ * @param $channel Channel identifier or null for no channel. Channel comparison uses ===.
+ */
+ public function outputChanneled( $msg, $channel = null ) {
+ $handle = fopen( 'php://stdout', 'w' );
+
+ if ( $msg === false ) {
+ // For cleanup
+ if ( !$this->atLineStart ) fwrite( $handle, "\n" );
+ fclose( $handle );
+ return;
+ }
+
+ // End the current line if necessary
+ if ( !$this->atLineStart && $channel !== $this->lastChannel ) {
+ fwrite( $handle, "\n" );
+ }
+
+ fwrite( $handle, $msg );
+
+ $this->atLineStart = false;
+ if ( $channel === null ) {
+ // For unchanneled messages, output trailing newline immediately
+ fwrite( $handle, "\n" );
+ $this->atLineStart = true;
+ }
+ $this->lastChannel = $channel;
+
+ // Cleanup handle
+ fclose( $handle );
+ }
+