Last active
August 29, 2015 14:22
-
-
Save sasezaki/72e77f04a47bed7db951 to your computer and use it in GitHub Desktop.
memory usage echo vs stream_copy_to_stream when 10M send
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ curl "http://localhost/tmp/diactoros/test.php?bigsize" > /dev/null | |
% Total % Received % Xferd Average Speed Time Time Time Current | |
Dload Upload Total Spent Left Speed | |
100 10.0M 100 10.0M 0 0 35.9M 0 --:--:-- --:--:-- --:--:-- 35.9M | |
$ cat memory_get_usage.txt | |
10900304 | |
$ curl "http://localhost/tmp/diactoros/test.php?emitter=streamcopy&bigsize" > /dev/null | |
% Total % Received % Xferd Average Speed Time Time Time Current | |
Dload Upload Total Spent Left Speed | |
100 10.0M 100 10.0M 0 0 31.6M 0 --:--:-- --:--:-- --:--:-- 31.6M | |
$ cat memory_get_usage.txt | |
423736 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Zend\Diactoros\Response; | |
use Zend\Diactoros\Stream; | |
use Zend\Diactoros\Response\SapiEmitter; | |
use Zend\Diactoros\ServerRequestFactory; | |
require __DIR__ . '/vendor/autoload.php'; | |
require __DIR__ . '/StreamCopyEmitter.php'; | |
$request = ServerRequestFactory::fromGlobals(); | |
$response = new Response(); | |
if (isset($_GET['emitter']) && $_GET['emitter'] == 'streamcopy') { | |
$emitter = new StreamCopyEmitter(); | |
} else { | |
$emitter = new SapiEmitter(); | |
} | |
if (isset($_GET['bigsize'])) { | |
// $ dd if=/dev/zero of=tempfile bs=1M count=10 | |
$image = __DIR__.'/tempfile'; | |
$response = $response->withHeader('Content-Type', 'image/jpeg') | |
->withHeader('Content-Length', (string) filesize($image)) | |
->withBody(new Stream($image)); | |
} else { | |
$response->getBody()->write("hello"); | |
} | |
$emitter->emit($response); | |
file_put_contents("memory_get_usage.txt", var_export(memory_get_usage(), true)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Psr\Http\Message\ResponseInterface; | |
use Zend\Diactoros\Response\EmitterInterface; | |
//use RuntimeException; | |
class StreamCopyEmitter implements EmitterInterface | |
{ | |
/** | |
* Emits a response for a PHP SAPI environment. | |
* | |
* Emits the status line and headers via the header() function, and the | |
* body content via the output buffer. | |
* | |
* @param ResponseInterface $response | |
* @param null|int $maxBufferLevel Maximum output buffering level to unwrap. | |
*/ | |
public function emit(ResponseInterface $response, $maxBufferLevel = null) | |
{ | |
if (headers_sent()) { | |
throw new RuntimeException('Unable to emit response; headers already sent'); | |
} | |
$this->emitStatusLine($response); | |
$this->emitHeaders($response); | |
$this->emitBody($response, $maxBufferLevel); | |
} | |
/** | |
* Emit the status line. | |
* | |
* Emits the status line using the protocol version and status code from | |
* the response; if a reason phrase is availble, it, too, is emitted. | |
* | |
* @param ResponseInterface $response | |
*/ | |
private function emitStatusLine(ResponseInterface $response) | |
{ | |
$reasonPhrase = $response->getReasonPhrase(); | |
header(sprintf( | |
'HTTP/%s %d%s', | |
$response->getProtocolVersion(), | |
$response->getStatusCode(), | |
($reasonPhrase ? ' ' . $reasonPhrase : '') | |
)); | |
} | |
/** | |
* Emit response headers. | |
* | |
* Loops through each header, emitting each; if the header value | |
* is an array with multiple values, ensures that each is sent | |
* in such a way as to create aggregate headers (instead of replace | |
* the previous). | |
* | |
* @param ResponseInterface $response | |
*/ | |
private function emitHeaders(ResponseInterface $response) | |
{ | |
foreach ($response->getHeaders() as $header => $values) { | |
$name = $this->filterHeader($header); | |
$first = true; | |
foreach ($values as $value) { | |
header(sprintf( | |
'%s: %s', | |
$name, | |
$value | |
), $first); | |
$first = false; | |
} | |
} | |
} | |
/** | |
* Emit the message body. | |
* | |
* Loops through the output buffer, flushing each, before emitting | |
* the response body using `echo()`. | |
* | |
* @param ResponseInterface $response | |
* @param int $maxBufferLevel Flush up to this buffer level. | |
*/ | |
private function emitBody(ResponseInterface $response, $maxBufferLevel) | |
{ | |
if (null === $maxBufferLevel) { | |
$maxBufferLevel = ob_get_level(); | |
} | |
while (ob_get_level() > $maxBufferLevel) { | |
ob_end_flush(); | |
} | |
//echo $response->getBody(); | |
$fp = $response->getBody()->detach(); | |
rewind($fp); | |
stream_copy_to_stream($fp, fopen('php://output', 'w')); | |
} | |
/** | |
* Filter a header name to wordcase | |
* | |
* @param string $header | |
* @return string | |
*/ | |
private function filterHeader($header) | |
{ | |
$filtered = str_replace('-', ' ', $header); | |
$filtered = ucwords($filtered); | |
return str_replace(' ', '-', $filtered); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment