---
source_url: https://www.pubnub.com/docs/sdks/php/migration-guides/php-v8-migration-guide
title: PHP 8.0.0 Migration Guide
updated_at: 2026-06-01T05:31:01.176Z
sdk_name: PubNub PHP SDK
sdk_version: 9.0.0
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# PHP 8.0.0 Migration Guide

PubNub PHP SDK, use the latest version: 9.0.0

Install:

```bash
composer require pubnub/pubnub@9.0.0
```

The PHP SDK improves compatibility and performance in v8.0.0. The legacy transport layer is replaced with an implementation that follows PHP Standards Recommendation (PSR). By default, the SDK uses the [Guzzle HTTP client](https://docs.guzzlephp.org/en/stable/).

## What has changed

See the major differences between versions:

| Feature | PHP SDK v7.x.x | PHP SDK v8.x.x |
| --- | --- | --- |
| Method to set transport layer | `PubNub::setTransport()` | `PubNub::setClient()` |

:::warning Transport was removed
`PubNub::setTransport()` is removed. Use `PubNub::setClient()` instead.
:::

## Required changes

If you didn't override the default transport, this update is seamless.

If you did, your client must implement [PSR-18](https://www.php-fig.org/psr/psr-18/). Optionally, expose an extended `send` method that accepts request options for a single call.

```php
use Psr\Http\Client\ClientInterface;

class CustomClient implements ClientInterface
{
    /**
     * Sends a PSR-7 request and returns a PSR-7 response.
     *
     * @param RequestInterface $request
     *
     * @return ResponseInterface
     *
     * @throws \Psr\Http\Client\ClientExceptionInterface If an error happens while processing the request.
     */
    public function sendRequest(RequestInterface $request): ResponseInterface { }

    /**
     * Send an HTTP request.
     *
     * @param array $options Request options to apply to the given
     *                       request and to the transfer. See \GuzzleHttp\RequestOptions.
     *
     * @throws \Psr\Http\Client\ClientExceptionInterface If an error happens while processing the request.
     */
    public function send(RequestInterface $request, array $options = []): ResponseInterface { }
}
```

## Use default HTTP client

If you don't need a custom transport, use the default `GuzzleHttp` client.

The default setup works out of the box. It suits most use cases and provides a reliable, efficient HTTP client.

```php
use PubNub\PubNub;
use PubNub\PNConfiguration;

$config = new PNConfiguration();
$config->setPublishKey('demo');
$config->setSubscribeKey('demo');
$config->setUserId('demo');
$pubnub = new PubNub();
$pubnub->publish()->channel('test')->message('Hello')->sync();
```

## Use custom HTTP client

To use a custom HTTP client, implement PSR‑18 `ClientInterface`. The example below uses built‑in cURL.

```php
class CustomClient implements ClientInterface
{
    public function sendRequest(RequestInterface $request): ResponseInterface
    {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, (string) $request->getUri());
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $request->getMethod());
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $headers = [];
        foreach ($request->getHeaders() as $name => $values) {
            foreach ($values as $value) {
                $headers[] = $name . ': ' . $value;
            }
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        if ($request->getBody()->getSize() > 0) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, (string) $request->getBody());
        }

        $responseBody = curl_exec($ch);
        $responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if ($responseBody === false) {
            throw new \RuntimeException('Curl error: ' . curl_error($ch));
        }

        curl_close($ch);

        return new Response($responseCode, [], $responseBody);
    }
}
```

This class uses cURL to send the request. It returns a `Response` (an implementation of `ResponseInterface`) and uses a `Stream` that implements `StreamInterface`.

To use this custom client with the SDK, instantiate it and call `PubNub::setClient`.

```php
use PubNub\PubNub;
use PubNub\PNConfiguration;
use CustomClient;

$config = new PNConfiguration();
$config->setPublishKey("demo");
$config->setSubscribeKey("demo");
$config->setUserId("test");

$client = new CustomClient();

$pubnub = new PubNub($config);
$pubnub->setClient($client);
$pubnub->publish()->channel('test')->message('Hello')->sync();
```

#### Response

Basic `Response` implementation:

```php
use Psr\Http\Message\ResponseInterface;

class Response implements ResponseInterface
{
    private int $statusCode;
    private array $headers;
    private StreamInterface $body;

    public function __construct(int $statusCode, array $headers, string $body)
    {
        $this->statusCode = $statusCode;
        $this->headers = $headers;
        $this->body = new Stream($body);
    }

    public function getStatusCode(): int
    {
        return $this->statusCode;
    }

    public function getReasonPhrase(): string
    {
        return '';
    }

    public function getProtocolVersion(): string
    {
        return '';
    }

    public function getHeaders(): array
    {
        return $this->headers;
    }

    public function getBody(): StreamInterface
    {
        return $this->body;
    }

    public function withStatus($code, $reasonPhrase = ''): self
    {
        $this->statusCode = $code;
        return $this;
    }

    public function withHeader($name, $value): self
    {
        $this->headers[$name] = $value;
        return $this;
    }

    public function withAddedHeader($name, $value): self
    {
        $this->headers[$name][] = $value;
        return $this;
    }

    public function withoutHeader($name): self
    {
        unset($this->headers[$name]);
        return $this;
    }

    public function withProtocolVersion($version): self
    {
        return $this;
    }

    public function hasHeader($name): bool
    {
        return isset($this->headers[$name]);
    }

    public function getHeader($name): array
    {
        return $this->headers[$name] ?? [];
    }

    public function getHeaderLine($name): string
    {
        return implode(', ', $this->headers[$name] ?? []);
    }

    public function withBody(StreamInterface $body): self
    {
        $this->body = $body;
        return $this;
    }
}
```

#### Stream

Basic `Stream` implementation:

```php
use Psr\Http\Message\StreamInterface;

class Stream implements StreamInterface
{
    private $stream;
    private $size;

    public function __construct(string $content = '')
    {
        $this->stream = fopen('php://temp', 'r+');
        fwrite($this->stream, $content);
        rewind($this->stream);
        $this->size = strlen($content);
    }

    public function __toString(): string
    {
        return stream_get_contents($this->stream, -1, 0);
    }

    public function close(): void
    {
        fclose($this->stream);
    }

    public function detach()
    {
        $result = $this->stream;
        $this->stream = null;
        return $result;
    }

    public function getSize(): ?int
    {
        return $this->size;
    }

    public function tell(): int
    {
        return ftell($this->stream);
    }

    public function eof(): bool
    {
        return feof($this->stream);
    }

    public function isSeekable(): bool
    {
        return true;
    }

    public function seek($offset, $whence = SEEK_SET): void
    {
        fseek($this->stream, $offset, $whence);
    }

    public function rewind(): void
    {
        rewind($this->stream);
    }

    public function isWritable(): bool
    {
        return true;
    }

    public function write($string): int
    {
        $result = fwrite($this->stream, $string);
        $this->size += strlen($string);
        return $result;
    }

    public function isReadable(): bool
    {
        return true;
    }

    public function read($length): string
    {
        return fread($this->stream, $length);
    }

    public function getContents(): string
    {
        return stream_get_contents($this->stream);
    }

    public function getMetadata($key = null)
    {
        $meta = stream_get_meta_data($this->stream);
        if ($key === null) {
            return $meta;
        }
        return $meta[$key] ?? null;
    }
}
```