为了支持我所做的评论 - “我能想到的最接近的近似值......”我拼凑了一个演示,说明了我使用 EventStream 的意思 - 可能比需要的更复杂,但输出提问的时候不能像想象的那样使用缓冲。
如果您要复制此文件并创建一个新的 php 文件,保存并运行,您应该会看到输出结果...有点。
<?php
if( !empty( $_GET['evtstream'] ) && $_GET['evtstream']==true ){
ob_clean();
set_time_limit( 0 );
ob_end_clean();
function sse( $evtname='evt', $data=null, $retry=1000 ){
if( !is_null( $data ) ){
echo "event:".$evtname."\r\n";
echo "retry:".$retry."\r\n";
echo "data:" . json_encode( $data, JSON_FORCE_OBJECT );
echo "\r\n\r\n";
}
}
header('Access-Control-Allow-Methods: GET');
header('Content-Type: text/event-stream');
$i=1;
$evt=!empty( $_GET['evt'] ) ? $_GET['evt'] : 'tick';
$count=!empty( $_GET['count'] ) ? $_GET['count'] : 10;
while( true ){
if( $i > $count ) break;
/* send some data back for the SSE listener to process */
$payload=array(
'date' => date( DATE_ATOM ),
'count' => $i,
'event' => $evt,
'calculation' => ( rand( 10,999 ) * rand( 300, 5999 ) ) / rand( 0.25, 25 ) #some random task performed by php...
);
call_user_func( 'sse', $evt, $payload );
if( @ob_get_level() > 0 ) for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
@flush();
sleep( 1 );
$i++;
}
/*
Now that the event loop has completed the 10 iterations we
need to prevent the eventsource from re-establishing itself
*/
header('Content-Type: text/html');
header('HTTP/1.1 404 Not Found', true, 404 );
echo 'goodbye';
ob_end_clean();
}
?>
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<title>Output Buffering: Server Sent Events</title>
</head>
<body>
<h1>Output buffering experiments</h1>
<div></div>
<script>
const EVENT_NAME='ticker';
const MAX_ITERATIONS=10;
let evtsource = new EventSource( location.href + '?evtstream=true&evt='+EVENT_NAME+'&ts=' + ( new Date().getTime() )+'&count='+MAX_ITERATIONS );
let oDiv=document.querySelector( 'div' );
const create=function(data){
let node=document.createElement('div');
node.innerText=data;
return node;
};
const callback=function(e){
let json=JSON.parse( e.data );
let content=Object.keys( json ).map( k => {
return [k,json[k]].join('=')
}).join('&')
oDiv.append( create( content ) );
};
const errorhandler=function(e){
evtsource.close();
oDiv.append( create( 'Terminated' ) );
};
evtsource.addEventListener( EVENT_NAME, callback, false );
evtsource.addEventListener( 'error', errorhandler,false );
</script>
</body>
</html>
否则,您可以查看 output buffering 的另一个用法的示例 - 您会看到 html 有一个由输出缓冲区回调修改的标题(香蕉...) - 这种修改不会不可能在没有输出缓冲的情况下在实时文档上使用 DOMDocument。
<?php
error_reporting( E_ALL );
function callback( $buffer ){
if( !empty( $buffer ) ){
$dom=new DOMDocument;
$dom->loadHTML( $buffer );
$h1 = $dom->getElementsByTagName('h1')->item(0);
$h1->nodeValue='A giraffe is a large mammal from Africa';
return $dom->saveHTML();
}
}
ob_start( 'callback' );
ob_implicit_flush(1);
?>
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<title>Output Buffering Example</title>
</head>
<body>
<h1>Bananas are curvy yellow fruit</h1>
</body>
</html>