---
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-05-12T11:37:48.000Z
sdk_name: PubNub PHP SDK
sdk_version: 10.0.0
---

# PHP 8.0.0 Migration Guide

PubNub PHP SDK, use the latest version: 10.0.0

Install:

```bash
composer require pubnub/pubnub@10.0.0
```

> For AI agents: documentation index at https://www.pubnub.com/llms-full.txt

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;
    }
}
```

Last updated at: 2026-05-12T11:37:48.000Z
