
Official documentation for Amplitude Experiment's server-side PHP SDK implementation.

### Install

{% callout type="info" heading="PHP version compatibility" %}
The PHP Server SDK works with PHP 7.4+.
{% /callout %}

Install the PHP Server SDK with composer.

```bash
composer require amplitude/experiment-php-server
```

## Remote evaluation

The SDK supports and uses [remote evaluation](/docs/feature-experiment/remote-evaluation) to fetch variants for users.

{% callout type="tip" heading="Quick start" %}

1. [Initialize the experiment client](#initialize-remote-evaluation)
2. [Fetch variants for the user](#fetch)
3. [Access a flag's variant](#fetch)

```php
<?php
// (1) Initialize the experiment client
$experiment = new \AmplitudeExperiment\Experiment();
$client = $experiment->initializeRemote('<DEPLOYMENT_KEY>');

// (2) Fetch variants for a user
$user = \AmplitudeExperiment\User::builder()
    ->deviceId('abcdefg')
    ->userId('user@company.com')
    ->userProperties(['premium' => true]) 
    ->build();
$variants = $client->fetch($user);

// (3) Access a flag's variant
$variant = $variants['FLAG_KEY'] ?? null;
if ($variant) {
    if ($variant->value == 'on') {
        // Flag is on
    } else {
        // Flag is off
    }
}
```

{% /callout %}

### Initialize remote evaluation

Configure the SDK to initialize on server startup. The [deployment key](/docs/feature-experiment/data-model#deployments) argument you pass into the `apiKey` parameter must live within the same project that you send analytics events to.

```php
<?php
initializeRemote(string $apiKey, ?RemoteEvaluationConfig $config = null): RemoteEvaluationClient
```

| Parameter | Requirement | Description                                                                                                                                                |
| --------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apiKey`  | required    | The [deployment key](/docs/feature-experiment/data-model#deployments) which authorizes fetch requests and determines which flags to evaluate for the user. |
| `config`  | optional    | The client [configuration](#configuration) used to customize SDK client behavior.                                                                          |

#### Configuration

You can configure the SDK client on initialization.

| Name                 | Description                                                                                                                                 | Default Value                   |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
| `serverUrl`          | The host to fetch variants from.                                                                                                            | `https://api.lab.amplitude.com` |
| `logger`             | Set to use custom logger. If not set, the SDK uses a [default logger](#custom-logger).                                                      | `null`                          |
| `logLevel`           | The [log level](#log-level) to use for the logger.                                                                                          | `LogLevel::ERROR`               |
| `httpClient`         | The underlying [HTTP client](#custom-http-client) to use for requests. If not set, the SDK uses a [default](#guzzlehttpclient) HTTP client. | `null`                          |
| `guzzleClientConfig` | The configuration for the underlying default `GuzzleHTTPClient` (if used).                                                                  | [defaults](#guzzlehttpclient)   |

{% callout type="info" heading="EU data center" %}
If you use Amplitude's EU data center, set the `serverUrl` option on initialization to `https://api.lab.eu.amplitude.com`
{% /callout %}

### Fetch

Fetches variants for a [user](/docs/feature-experiment/data-model#users) and returns the results. The function [remote evaluates](/docs/feature-experiment/remote-evaluation) the user for flags associated with the deployment used to initialize the SDK client.

```php
<?php
fetch(User $user, ?FetchOptions $fetchOptions = null): array<Variant>
// An array of variants is returned on success, an empty array is returned on failure
```

| Parameter      | Requirement | Description                                                                       |
| -------------- | ----------- | --------------------------------------------------------------------------------- |
| `user`         | required    | The [user](/docs/feature-experiment/data-model#users) for whom to fetch variants. |
| `fetchOptions` | optional    | The [options](#fetch-options) for the fetch request.                              |

**FetchOptions**

| Name               | Description                                                                                                                                | Default Value |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------- |
| `flagKeys`         | Specific flags or experiments to evaluate. If empty, Amplitude evaluates all flags and experiments.                                        | `[]`          |
| `tracksExposure`   | Tracks or doesn't track an exposure event for this fetch request. If `null`, uses the server's default behavior (doesn't track exposure).  | `null`        |
| `tracksAssignment` | Tracks or doesn't track an assignment event for this fetch request. If `null`, uses the server's default behavior (does track assignment). | `null`        |

```php
<?php
$user = \AmplitudeExperiment\User::builder()
    ->deviceId('abcdefg')
    ->userId('user@company.com')
    ->userProperties(['premium' => true])
    ->build();
$variants = $client->fetch($user);
```

After fetching variants for a user, you may want to access the variant for a specific flag.

```php
<?php
$variant = $variants['FLAG-KEY'] ?? null;
if ($variant) {
    if ($variant->value == 'on') {
        // Flag is on
    } else {
        // Flag is off
    }
}
```

{% accordion title="Account-level bucketing and analysis (v1.0.0+)" %}

Groups must either be included in the user sent with the fetch request (recommended), or identified with the user through a group identify call from the [Group Identify API](/docs/apis/analytics/group-identify) or through [`setGroup()` from an analytics SDK](/docs/sdks/analytics/browser/browser-sdk-2#user-groups).

```php
<?php
$user = \AmplitudeExperiment\User::builder()
    ->deviceId('abcdefg')
    ->userId('user@company.com')
    ->userProperties(['premium' => true])
    ->group(['org name' => ['Amplitude']])
    ->build();
$variants = $client->fetch($user);
```

To pass freeform group properties, refer to this example:

```php
<?php
$user = \AmplitudeExperiment\User::builder()
    ->deviceId('abcdefg')
    ->userId('user@company.com')
    ->userProperties(['premium' => true])
    ->groupProperties(['org name' => ['Amplitude']])
    ->build();
$variants = $client->fetch($user);
```

{% /accordion %}

## Local evaluation

Implements evaluation of variants for a user through [local evaluation](/docs/feature-experiment/local-evaluation). If you plan to use local evaluation, you should [understand the tradeoffs](/docs/feature-experiment/local-evaluation#targeting-capabilities).

{% callout type="tip" heading="Quick start" %}

1.  [Initialize the local evaluation client.](#initialize-local-evaluation)
2.  [Fetch flag configs for the local evaluation client.](#refreshflagconfigs)
3.  [Evaluate a user.](#evaluate)

 ```php
 <?php
 // (1) Initialize the experiment client
 $experiment = new \AmplitudeExperiment\Experiment();
 $client = $experiment->initializeLocal('<DEPLOYMENT_KEY>');

 // (2) Fetch flags for the local evaluation client.
 $client->refreshFlagConfigs();

 // (3) Evaluate a user.
 $user = \AmplitudeExperiment\User::builder()
     ->deviceId('abcdefg')
     ->userId('user@company.com')
     ->userProperties(['premium' => true]) 
     ->build();

 $variants = $client->evaluate($user);
 ```

{% /callout %}

### Initialize local evaluation

Refer to [Local Evaluation](/docs/feature-experiment/local-evaluation).

{% callout type="warning" heading="Server deployment key" %}
[Initialize](#initialize-local-evaluation) the local evaluation client with a server [deployment](/docs/feature-experiment/data-model#deployments) key to access local evaluation flag configurations.
{% /callout %}

```php
initializeLocal(string $apiKey, ?LocalEvaluationConfig $config = null): LocalEvaluationClient
```

| Parameter | Requirement | Description                                                                                                                                                       |
| --------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apiKey`  | required    | The server [deployment key](/docs/feature-experiment/data-model#deployments) which authorizes fetch requests and determines which flags to evaluate for the user. |
| `config`  | optional    | The client [configuration](#configuration) used to customize SDK client behavior.                                                                                 |

#### Configuration

You can configure the SDK client on initialization.

| Name                 | Description                                                                                                                                 | Default Value                   |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
| `serverUrl`          | The host to fetch flag configurations from.                                                                                                 | `https://api.lab.amplitude.com` |
| `logger`             | Set to use custom logger. If not set, the SDK uses a [default logger](#custom-logger).                                                      | `null`                          |
| `logLevel`           | The [log level](#log-level) to use for the logger.                                                                                          | `LogLevel::ERROR`               |
| `httpClient`         | The underlying [HTTP client](#custom-http-client) to use for requests. If not set, the SDK uses a [default](#guzzlehttpclient) HTTP client. | `null`                          |
| `guzzleClientConfig` | The configuration for the underlying default `GuzzleHTTPClient` (if used).                                                                  | [defaults](#guzzlehttpclient)   |
| `bootstrap`          | Bootstrap the client with an array of flag key to flag configuration                                                                        | `[]`                            |
| `assignmentConfig`   | **Deprecated.** Configuration for automatically tracking assignment events after an evaluation.                                             | `null`                          |
| `exposureConfig`     | Configuration for tracking exposure events after an evaluation.                                                                             | `null`                          |

{% callout type="info" heading="EU data center" %}
If you use Amplitude's EU data center, configure the `serverUrl` option on initialization to `https://api.lab.eu.amplitude.com`
{% /callout %}

### refreshFlagConfigs

Fetch up-to-date local evaluation mode flag configs for [evaluation](#evaluate).

```php
refreshFlagConfigs(): void
```

Call `refreshFlagConfigs()` to ensure that flag configs are up-to-date before you use [`evaluate()`](#evaluate)

```php
<?php
$client->refreshFlagConfigs();
```

### getFlagConfigs

Return flag configs used in the client.

```php
getFlagConfigs(): array
```

Use returned flag configs to reduce start up time by [bootstrapping](#configuration) the local evaluation client.

```php
<?php
$client->getFlagConfigs();
```

### Evaluate

Executes the [evaluation logic](/docs/feature-experiment/implementation) using the flags fetched on [`refreshFlagConfigs()`](#refreshflagconfigs). Give `evaluate()` a user object argument. Optionally pass an array of flag keys if you require only a specific subset of required flag variants.

{% callout type="tip" heading="Exposure tracking" %}
Set [`exposureConfig`](#configuration) to enable exposure tracking. Then, set `tracksExposure` to `true` in `EvaluateOptions` when calling `evaluate()`.
{% /callout %}

```php
evaluate(User $user, array $flagKeys = [], ?EvaluateOptions $options = null): array
```

| Parameter  | Requirement | Description                                                                                         |
| ---------- | ----------- | --------------------------------------------------------------------------------------------------- |
| `user`     | required    | The [user](/docs/feature-experiment/data-model#users) to evaluate.                                  |
| `flagKeys` | optional    | Specific flags or experiments to evaluate. If empty, Amplitude evaluates all flags and experiments. |
| `options`  | optional    | The [options](#evaluate-options) for the evaluation request.                                        |

```php
<?php
// The user to evaluate
$user = \AmplitudeExperiment\User::builder()
        ->deviceId('abcdefg')
        ->build();

// Evaluate all flag variants
$allVariants = $client->evaluate($user);

// Evaluate a specific subset of flag variants
$specificVariants = $client->evaluate($user, [
  'my-local-flag-1',
  'my-local-flag-2',
]);

// Access a flag's variant
$variant = $allVariants['FLAG_KEY'] ?? null;
if ($variant) {
    if ($variant->value == 'on') {
        // Flag is on
    } else {
        // Flag is off
    }
}
```

**EvaluateOptions**

| Name             | Description                                                             | Default Value |
| ---------------- | ----------------------------------------------------------------------- | ------------- |
| `tracksExposure` | If `true`, the SDK tracks an exposure event for the evaluated variants. | `false`       |

### Assignment tracking

**Deprecated.** Use [Exposure tracking](#exposure-tracking) instead.

You can configure the local evaluation client to send [assignment events](/docs/feature-experiment/under-the-hood/event-tracking#assignment-events) to Amplitude.

| Name                         | Description                                                                   | Default Value |
| ---------------------------- | ----------------------------------------------------------------------------- | ------------- |
| `assignmentTrackingProvider` | The AssignmentTrackingProvider used to send assignment events.                | _required_    |
| `cacheCapacity`              | The maximum number of assignments stored in the assignment cache.             | `65536`       |
| `apiKey`                     | The analytics API key. Not to be confused with the experiment deployment key. | _required_    |
| `minIdLength`                | The minimum length of `userId` and `deviceId`.                                | `5`           |

#### AssignmentTrackingProvider

The local evaluation client uses an assignment tracking provider to send assignment events to Amplitude. Amplitude provides a default assignment tracking provider, but this is best used for testing due to its synchronous nature. Amplitude recommends that you use a custom provider for increased flexibility and performance.

```php title="AssignmentTrackingProvider"
<?php
interface AssignmentTrackingProvider {
  public function track(Assignment $assignment): void;
}
```

The local evaluation client calls `track()` when it determines there are untracked assignment events. It compares the resulting assignment from `evaluate()` with the assignment cache and tracks it if it's not in the cache.

| Parameter    | Requirement | Description                                            |
| ------------ | ----------- | ------------------------------------------------------ |
| `assignment` | required    | The object representing an Experiment assignment event |

#### DefaultAssignmentTrackingProvider

The default assignment tracking provider is a basic implementation of the interface which uses the internal `Amplitude` package to send assignment events through synchronous HTTP requests.

```php title="DefaultAssignmentTrackingProvider"
<?php
class DefaultAssignmentTrackingProvider implements AssignmentTrackingProvider {
  public function __construct(Amplitude $amplitude);
}
```

**Amplitude**

| Name     | Description                                                                   | Default Value |
| -------- | ----------------------------------------------------------------------------- | ------------- |
| `apiKey` | The analytics API key. Not to be confused with the experiment deployment key. | _required_    |
| `config` | Configuration options                                                         | `null`        |

**AmplitudeConfig**

| Name                 | Description                                                                                                                                                                                                                                  | Default Value                          |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| `flushQueueSize`     | Events wait in the buffer, and Experiment sends them in a batch. Experiment flushes the buffer when the number of events reaches the `flushQueueSize`.                                                                                       | `200`                                  |
| `minIdLength`        | The minimum length of `userId` and `deviceId`.                                                                                                                                                                                               | `5`                                    |
| `serverZone`         | The server zone of the projects. Supports `EU` and `US`. For EU data residency, Change to `EU`.                                                                                                                                              | `US`                                   |
| `serverUrl`          | The API endpoint URL where Experiment sends events. Automatically selected by `serverZone` and `useBatch`. If you set this field to a string value instead of `null`, the SDK ignores `serverZone` and `useBatch` and uses the string value. | `https://api2.amplitude.com/2/httpapi` |
| `useBatch`           | Whether to use [batch API](/docs/apis/analytics/batch-event-upload). By default, the SDK uses the default `serverUrl`.                                                                                                                       | `false`                                |
| `httpClient`         | The underlying [HTTP client](#custom-http-client) to use for requests. If not set, the SDK uses a [default](#guzzlehttpclient) HTTP client.                                                                                                  | `null`                                 |
| `guzzleClientConfig` | The configuration for the underlying default `GuzzleHTTPClient` (if used).                                                                                                                                                                   | [defaults](#guzzlehttpclient)          |
| `logger`             | Set to use custom logger. If not set, the SDK uses a [default logger](#custom-logger).                                                                                                                                                       | `null`                                 |
| `logLevel`           | The [log level](#log-level) to use for the logger.                                                                                                                                                                                           | `LogLevel::ERROR`                      |

```php
<?php
$config = \AmplitudeExperiment\Amplitude\AmplitudeConfig::builder()
          ->useBatch(true)
          ->minIdLength(10)
          ->build();
$amplitude = new \AmplitudeExperiment\Amplitude\Amplitude('<API_Key>', $config);
$defaultAssignmentTrackingProvider = new \AmplitudeExperiment\Assignment\DefaultAssignmentTrackingProvider($amplitude);
```

### Exposure tracking

You can configure the local evaluation client to send exposure events to Amplitude.

| Name                       | Description                                                                   | Default Value |
| -------------------------- | ----------------------------------------------------------------------------- | ------------- |
| `exposureTrackingProvider` | The ExposureTrackingProvider used to send exposure events.                    | _required_    |
| `cacheCapacity`            | The maximum number of exposures stored in the exposure cache.                 | `65536`       |
| `apiKey`                   | The analytics API key. Not to be confused with the experiment deployment key. | _required_    |
| `minIdLength`              | The minimum length of `userId` and `deviceId`.                                | `5`           |

#### ExposureTrackingProvider

The local evaluation client uses an exposure tracking provider to send exposure events. Amplitude provides a default exposure tracking provider that tracks events to Amplitude. You can implement a custom provider to track events to other destinations or to customize the tracking behavior.

```php title="ExposureTrackingProvider"
<?php
interface ExposureTrackingProvider {
  public function track(Exposure $exposure): void;
}
```

The local evaluation client calls `track()` when it determines there are untracked exposure events. It compares the resulting exposure from `evaluate()` with the exposure cache and tracks it if it's not in the cache.

| Parameter  | Requirement | Description                                           |
| ---------- | ----------- | ----------------------------------------------------- |
| `exposure` | required    | The object representing an Experiment exposure event. |

#### DefaultExposureTrackingProvider

The default exposure tracking provider is an implementation of the `ExposureTrackingProvider` interface that sends exposure events to Amplitude using the internal `Amplitude` package through synchronous HTTP requests.

```php title="DefaultExposureTrackingProvider"
<?php
class DefaultExposureTrackingProvider implements ExposureTrackingProvider {
  public function __construct(Amplitude $amplitude);
}
```

**Amplitude**

| Name     | Description                                                                   | Default Value |
| -------- | ----------------------------------------------------------------------------- | ------------- |
| `apiKey` | The analytics API key. Not to be confused with the experiment deployment key. | _required_    |
| `config` | Configuration options                                                         | `null`        |

**AmplitudeConfig**

| Name                 | Description                                                                                                                                                                                                                                  | Default Value                          |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| `flushQueueSize`     | Events wait in the buffer, and Experiment sends them in a batch. Experiment flushes the buffer when the number of events reaches the `flushQueueSize`.                                                                                       | `200`                                  |
| `minIdLength`        | The minimum length of `userId` and `deviceId`.                                                                                                                                                                                               | `5`                                    |
| `serverZone`         | The server zone of the projects. Supports `EU` and `US`. For EU data residency, Change to `EU`.                                                                                                                                              | `US`                                   |
| `serverUrl`          | The API endpoint URL where Experiment sends events. Automatically selected by `serverZone` and `useBatch`. If you set this field to a string value instead of `null`, the SDK ignores `serverZone` and `useBatch` and uses the string value. | `https://api2.amplitude.com/2/httpapi` |
| `useBatch`           | Whether to use [batch API](/docs/apis/analytics/batch-event-upload). By default, the SDK uses the default `serverUrl`.                                                                                                                       | `false`                                |
| `httpClient`         | The underlying [HTTP client](#custom-http-client) to use for requests. If not set, the SDK uses a [default](#guzzlehttpclient) HTTP client.                                                                                                  | `null`                                 |
| `guzzleClientConfig` | The configuration for the underlying default `GuzzleHTTPClient` (if used).                                                                                                                                                                   | [defaults](#guzzlehttpclient)          |
| `logger`             | Set to use custom logger. If not set, the SDK uses a [default logger](#custom-logger).                                                                                                                                                       | `null`                                 |
| `logLevel`           | The [log level](#log-level) to use for the logger.                                                                                                                                                                                           | `LogLevel::ERROR`                      |

```php
<?php
$config = \AmplitudeExperiment\Amplitude\AmplitudeConfig::builder()
          ->useBatch(true)
          ->minIdLength(10)
          ->build();
$amplitude = new \AmplitudeExperiment\Amplitude\Amplitude('<API_Key>', $config);
$defaultExposureTrackingProvider = new \AmplitudeExperiment\Exposure\DefaultExposureTrackingProvider($amplitude);
```

## Custom Logger

Configure local and remote evaluation clients to use a custom logger that implements the PSR logger interface. Otherwise, the SDK uses a default `error_log`-based logger.

### Log level

The SDK uses the following log levels:

| Level    | Description                               |
| -------- | ----------------------------------------- |
| `NO_LOG` | Turn off logging                          |
| `ERROR`  | Error-level messages are logged           |
| `DEBUG`  | Debug and error-level messages are logged |

## Custom HTTP Client

Configure local and remote evaluation clients to use a custom HTTP client that implements the [HTTPClientInterface](#httpclientinterface). Otherwise, the SDK uses a default [Guzzle-based HTTP client](#guzzlehttpclient).

### HTTPClientInterface

| Method          | Return Type                         | Description                                                        |
| --------------- | ----------------------------------- | ------------------------------------------------------------------ |
| `getClient`     | `Psr\HTTP\Client\ClientInterface`   | Return the underlying PSR HTTP Client.                             |
| `createRequest` | `Psr\HTTP\Message\RequestInterface` | Return a PSR Request to be sent by the underlying PSR HTTP Client. |

### GuzzleHTTPClient

Configure the default Guzzle client with the `guzzleClientConfig` option in [`RemoteEvaluationConfig`](#configuration) and [`LocalEvaluationConfig`](#configuration).

| Name                    | Description                                                                                                                                           | Default Value |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `timeoutMillis`         | The timeout for requests in milliseconds. This timeout applies to the initial request, not subsequent retries.                                        | `10000`       |
| `retries`               | The number of retries to attempt if a request fails.                                                                                                  | `8`           |
| `retryBackoffMinMillis` | The minimum (initial) backoff after a request fails. The SDK scales this delay according to the `retryBackoffScalar` setting.                         | `500`         |
| `retryBackoffMaxMillis` | The maximum backoff between retries. If the scaled backoff becomes greater than the maximum, Experiment uses the maximum for all subsequent requests. | `10000`       |
| `retryBackoffScalar`    | Scales the minimum backoff exponentially.                                                                                                             | `1.5`         |
| `retryTimeoutMillis`    | The request timeout for retrying requests.                                                                                                            | `10000`       |

```php
<?php
// Configure the default Guzzle client
$config = \AmplitudeExperiment\RemoteEvaluationConfig::builder()
          ->guzzleClientConfig(['timeoutMillis' => 5000, 'retries' => 10])
          ->build();
```

## Access Amplitude cookies

If you're using the Amplitude Analytics SDK on the client-side, the PHP server SDK provides an `AmplitudeCookie` class with convenience functions for parsing and interacting with the Amplitude identity cookie. The class ensures that the Device ID on the server matches the Device ID set on the client, especially if the client hasn't yet generated a Device ID.

```php
<?php
use AmplitudeExperiment\AmplitudeCookie;

// Get the cookie name for the Amplitude API key
// For Browser SDK 2.0 cookies, use true as second parameter:
// $amp_cookie_name = AmplitudeCookie::cookieName('amplitude-api-key', true);
$amp_cookie_name = AmplitudeCookie::cookieName('amplitude-api-key');
$device_id = null;

// Try to get device ID from existing cookie
if (isset($_COOKIE[$amp_cookie_name])) {
  $cookie_data = AmplitudeCookie::parse($_COOKIE[$amp_cookie_name]);
  // For Browser SDK 2.0: AmplitudeCookie::parse($_COOKIE[$amp_cookie_name], true);
  $device_id = $cookie_data['deviceId'];
}

// If no device ID found, generate a new one and set the cookie
if ($device_id === null) {
  $device_id = uniqid('', true);
  $amp_cookie_value = AmplitudeCookie::generate($device_id);
  // For Browser SDK 2.0: AmplitudeCookie::generate($device_id, true);
  setcookie($amp_cookie_name, $amp_cookie_value, [
    'domain' => '.your-domain.com', // this should be the same domain used by the Amplitude JS SDK
    'httponly' => false,
    'secure' => false
  ]);
}
```
