title: Create a stream from a resource
body: <p>I know that I can create a <a href="https://secure.php.net/manual/en/intro.stream.php" rel="nofollow noreferrer">PHP stream</a> from a filename (a real one, or an URL), by using the <a href="https://secure.php.net/manual/en/function.fopen.php" rel="nofollow noreferrer">fopen</a> function:</p>
  <pre><code>$stream = fopen('php://temp', 'r');
  </code></pre>
  <p>The resulting stream (<code>$stream</code>) is then a <em>resource</em> of type <em>&quot;stream&quot;</em>, created from the URL <code>php://temp</code>.</p>
  <p><strong>But how I can create a stream like the above from a resource?</strong></p>
  <hr/>
  <p><strong>Why am I asking this?</strong></p>
  <p>I am working on a <a href="https://www.php-fig.org/psr/psr-7/" rel="nofollow noreferrer">PSR-7</a> library and I implemented the PSR-7 <a href="https://www.php-fig.org/psr/psr-7/#34-psrhttpmessagestreaminterface" rel="nofollow noreferrer">StreamInterface</a> with a <code>Stream</code> class. In order to create <code>Stream</code> instances, I decided to implement a <code>StreamFactory</code> too. Its interface, <code>StreamFactoryInterface</code>, is defined in <a href="https://www.php-fig.org/psr/psr-17/#24-streamfactoryinterface" rel="nofollow noreferrer">PSR-17: HTTP Factories</a>.</p>
  <p>The <code>StreamFactoryInterface</code> defines a method named <code>createStreamFromResource</code>, which - conform to its official comments - should:</p>
  <blockquote>
  <p>Create a new stream from an existing resource.</p>
  <p>The stream MUST be readable and may be writable.</p>
  </blockquote>
  <p>So the factory method receives a resource as argument. And, in its concrete implementation, a new <code>Stream</code> object is created - which receives a resource as argument, too.</p>
  <p><strong>Here is the problem:</strong></p>
  <p>For the sake of simplicity, let's say that the <code>Stream</code> class works only with a stream, e.g. with a resource of type <em>&quot;stream&quot;</em>. If it receives a resource which is not of type <em>&quot;stream&quot;</em>, it rejects it.</p>
  <p>So, what if the resource argument of <code>createStreamFromResource</code> is not already a resource of type <em>&quot;stream&quot;</em>? How can I transform it into a stream, e.g. into a resource of type <em>&quot;stream&quot;</em>, so that I can pass it further, to the call for creating a new <code>Stream</code> object with it? Is there a way (a PHP method, a function, or maybe a casting function) of achieving this task?</p>
  <p><strong>Notes:</strong></p>
  <ul>
  <li>For clarity, I prepared a complete example (<code>testStream.php</code>) of how I create a stream, e.g. a <code>Stream</code> instance, in three ways: once directly, and twice using the stream factory.</li>
  <li>I also post the concrete implementation of the factory interface: the class <code>StreamFactory</code> with the method <code>createStreamFromResource</code>. A call to this method should be my fourth way of creating a stream in <code>testStream.php</code>.</li>
  <li>Furthermore I present the classes <code>Stream</code> and <code>Response</code>, so that you can directly test all, if you wish. The two classes are a very simplified version of my real code.</li>
  <li>In my codes I tagged the two questioning places with <em><strong>&quot;@asking&quot;</strong></em>.</li>
  </ul>
  <p>Thank you very much for your time and patience!</p>
  <hr/>
  <p><strong>testStream.php (the testing page):</strong></p>
  <pre><code>&lt;?php
  
  use Tests\Stream;
  use Tests\Response;
  use Tests\StreamFactory;
  
  /*
   * ================================================
   * Option 1: Create a stream by a stream name
   * (like &quot;php://temp&quot;) with read and write rights.
   * ================================================
   */
  $stream = new Stream('php://temp', 'w+b');
  
  $response = new Response($stream);
  $response-&gt;getBody()-&gt;write(
          'Stream 1: Created directly.&lt;br/&gt;&lt;br/&gt;'
  );
  echo $response-&gt;getBody();
  
  /*
   * ================================================
   * Option 2: Create a stream by a stream name
   * (like &quot;php://temp&quot;), using a stream factory.
   * ================================================
   */
  $streamFactory = new StreamFactory();
  $stream = $streamFactory-&gt;createStreamFromFile('php://temp', 'w+b');
  
  $response = new Response($stream);
  $response-&gt;getBody()-&gt;write(
          'Stream 2: Created by a stream name, with a stream factory.&lt;br/&gt;&lt;br/&gt;'
  );
  echo $response-&gt;getBody();
  
  /*
   * ================================================
   * Option 3: Create a stream from a string, using a
   * stream factory.
   * ================================================
   */
  $streamFactory = new StreamFactory();
  $stream = $streamFactory-&gt;createStream(
          'Stream 3: Created from a string, with a stream factory.&lt;br/&gt;&lt;br/&gt;'
  );
  
  $response = new Response($stream);
  echo $response-&gt;getBody();
  
  /*
   * ================================================
   * Option 4: Create a stream from an existing
   * resource, using a stream factory.
   * ================================================
   * 
   * @asking How can I create a stream by calling the
   * the factory method ServerFactory::createStreamFromResource
   * with a resource which is not of type &quot;stream&quot;?
   */
  //...
  </code></pre>
  <p><strong>The StreamFactory class (as I have it, so not simplified):</strong></p>
  <pre><code>&lt;?php
  
  namespace Tests;
  
  use Tests\Stream;
  use Psr\Http\Message\StreamInterface;
  use Psr\Http\Message\StreamFactoryInterface;
  
  class StreamFactory implements StreamFactoryInterface {
  
      /**
       * Create a new stream from an existing resource.
       *
       * The stream MUST be readable and may be writable.
       *
       * @param resource $resource
       *
       * @return StreamInterface
       * @throws \InvalidArgumentException
       */
      public function createStreamFromResource($resource) {
          /*
           * @asking What if $resource is not already a resource of type *&quot;stream&quot;*? 
           * How can I transform it into a stream, e.g. into a resource of type *&quot;stream&quot;*, 
           * so that I can pass it further, to the call for creating a new `Stream` object 
           * with it? Is there a way (a PHP method, a function, or maybe a casting function) 
           * of achieving this task?
           */
           //...
  
          return new Stream($resource, 'w+b');
      }
  
      /**
       * Create a new stream from a string.
       *
       * The stream SHOULD be created with a temporary resource.
       *
       * @param string $content
       *
       * @return StreamInterface
       * @throws \InvalidArgumentException
       */
      public function createStream($content = '') {
          if (!isset($content) || !is_string($content)) {
              throw new \InvalidArgumentException('For creating a stream, a content string must be provided!');
          }
  
          $stream = $this-&gt;createStreamFromFile('php://temp', 'w+b');
  
          $stream-&gt;write($content);
  
          return $stream;
      }
  
      /**
       * Create a stream from an existing file.
       *
       * The file MUST be opened using the given mode, which may be any mode
       * supported by the `fopen` function.
       *
       * The `$filename` MAY be any string supported by `fopen()`.
       *
       * @param string $filename
       * @param string $mode
       *
       * @return StreamInterface
       */
      public function createStreamFromFile($filename, $mode = 'r') {
          return new Stream($filename, $mode);
      }
  
  }
  </code></pre>
  <p><strong>The Stream class (very simplified):</strong></p>
  <pre><code>&lt;?php
  
  namespace Tests;
  
  use Psr\Http\Message\StreamInterface;
  
  class Stream implements StreamInterface {
  
      /**
       * Stream (resource).
       *
       * @var resource
       */
      private $stream;
  
      /**
       *
       * @param string|resource $stream Stream name, or resource.
       * @param string $accessMode (optional) Access mode.
       * @throws \InvalidArgumentException
       */
      public function __construct($stream, string $accessMode = 'r') {
          if (
                  !isset($stream) ||
                  (!is_string($stream) &amp;&amp; !is_resource($stream))
          ) {
              throw new \InvalidArgumentException(
                  'The provided stream must be a filename, or an opened resource of type &quot;stream&quot;!'
              );
          }
  
          if (is_string($stream)) {
              $this-&gt;stream = fopen($stream, $accessMode);
          } elseif (is_resource($stream)) {
              if ('stream' !== get_resource_type($stream)) {
                  throw new \InvalidArgumentException('The provided resource must be of type &quot;stream&quot;!');
              }
              
              $this-&gt;stream = $stream;
          }
      }
  
      /**
       * Write data to the stream.
       *
       * @param string $string The string that is to be written.
       * @return int Returns the number of bytes written to the stream.
       * @throws \RuntimeException on failure.
       */
      public function write($string) {
          return fwrite($this-&gt;stream, $string);
      }
  
      /**
       * Reads all data from the stream into a string, from the beginning to end.
       *
       * @return string
       */
      public function __toString() {
          try {
              // Rewind the stream.
              fseek($this-&gt;stream, 0);
  
              // Get the stream contents as string.
              $contents = stream_get_contents($this-&gt;stream);
  
              return $contents;
          } catch (\RuntimeException $exc) {
              return '';
          }
      }
  
      public function close() {}
      public function detach() {}
      public function eof() {}
      public function getContents() {}
      public function getMetadata($key = null) {}
      public function getSize() {}
      public function isReadable() {}
      public function isSeekable() {}
      public function isWritable() {}
      public function read($length) {}
      public function rewind() {}
      public function seek($offset, $whence = SEEK_SET) {}
      public function tell() {}
  
  }
  </code></pre>
  <p><strong>The Response class (very simplified):</strong></p>
  <pre><code>&lt;?php
  
  namespace Tests;
  
  use Psr\Http\Message\StreamInterface;
  use Psr\Http\Message\ResponseInterface;
  
  class Response implements ResponseInterface {
  
      /**
       *
       * @param StreamInterface $body Message body.
       */
      public function __construct(StreamInterface $body) {
          $this-&gt;body = $body;
      }
  
      /**
       * Gets the body of the message.
       *
       * @return StreamInterface Returns the body as a stream.
       */
      public function getBody() {
          return $this-&gt;body;
      }
  
      public function getHeader($name) {}
      public function getHeaderLine($name) {}
      public function getHeaders() {}
      public function getProtocolVersion() {}
      public function hasHeader($name) {}
      public function withAddedHeader($name, $value) {}
      public function withBody(StreamInterface $body) {}
      public function withHeader($name, $value) {}
      public function withProtocolVersion($version) {}
      public function withoutHeader($name) {}
      public function getReasonPhrase() {}
      public function getStatusCode() {}
      public function withStatus($code, $reasonPhrase = '') {}
  
  }
  </code></pre>