> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/feature-management-experimentation/new-to-fme/sdks-and-customer-deployed-components/server-side-sdks/php-sdk.md).

# PHP SDK

This guide provides detailed information about our PHP SDK. All of our SDKs are open source. Go to our [PHP SDK GitHub repository](https://github.com/splitio/php-client) to learn more.

### Before you begin <a href="#before-you-begin" id="before-you-begin"></a>

The PHP SDK supports PHP language version 7.3 and later.

### Initialization <a href="#initialization" id="initialization"></a>

#### SDK architecture <a href="#sdk-architecture" id="sdk-architecture"></a>

The PHP SDK is architected differently from our other SDKs. This is because of the **share nothing** nature of PHP, which means that you need to leverage a remote data store that your processes can share to ensure that your customers are served consistent treatments from our SDK. The SDK has three components.

**SDK factory client**

The SDK factory client is embedded within your PHP app. It decides which treatment to show to a customer for a particular feature flag.

**Split Synchronizer**

The Split Synchronizer service fetches data from the Harness servers so it can evaluate what treatment to show to a customer. This is a background service that can run on one machine on a schedule via your scheduling system. Refer to the [Split Synchronizer documentation](/feature-management-experimentation/new-to-fme/sdks-and-customer-deployed-components/customer-deployed-components/split-synchronizer.md) for more information.

**Cache**

The Synchronizer Service stores its fetched data in the cache component. The SDK comes pre-packaged with a Redis Cache Adapter. It is critical that Redis is configured **to never evict**.

Now that you have a sense of how this SDK is structured, follow the steps below to set up the SDK in your code base:

#### 1. Import the SDK into your project <a href="#id-1-import-the-sdk-into-your-project" id="id-1-import-the-sdk-into-your-project"></a>

```php
composer require splitsoftware/split-sdk-php:7.5.0
```

The public release is available at [packagist.org/packages/splitsoftware/split-sdk-php](https://packagist.org/packages/splitsoftware/split-sdk-php).

{% hint style="warning" %}
**IF USING SYNCHRONIZER WITH REDIS - SYNCHRONIZER 2.X REQUIRED AFTER SDK VERSION 3.X**

Since version 2.0.0 of the split-synchronizer, we use a more efficient scheme to store impressions in Redis. This approach is faster and easier on your Redis instances, since it yields better throughput of impressions to the backend. If you use this SDK with the Synchronizer in Redis or Proxy mode, you need the newest versions of our Split Synchronizer. It is recommended that once you're using SDK versions compatible with Split-Sync 2.0 on all your applications pointing to the redis instance maintained by the Split-Sync, you disable backwards compatibility. This is as easy as changing a parameter to `true` on the JSON config or an environment variable to `on` if you're using the docker image.
{% endhint %}

#### 2. Set up the synchronizer service <a href="#id-2-set-up-the-synchronizer-service" id="id-2-set-up-the-synchronizer-service"></a>

When the composer is done, follow the steps in our [Split Synchronizer](/feature-management-experimentation/new-to-fme/sdks-and-customer-deployed-components/customer-deployed-components/split-synchronizer.md) documents to get everything set to sync data to your Redis cache. After you do that, come back to set up the SDK in consumer mode!

#### 3. Instantiate the SDK and create a new SDK factory client <a href="#id-3-instantiate-the-sdk-and-create-a-new-sdk-factory-client" id="id-3-instantiate-the-sdk-and-create-a-new-sdk-factory-client"></a>

We recommend instantiating the SDK factory once as a singleton and reusing it throughout your application.

Use the code snippet below to instantiate the client in your code base. You need to provide your Redis details and your SDK API key.

Configure the SDK with the SDK API key for the FME environment that you would like to access. In legacy Split (app.split.io) the SDK key is found on your Admin settings page, in the API keys section. Select a server-side SDK API key. See [API keys](/feature-management-experimentation/management-and-administration/api-keys.md) to learn more.

Do all of this as a part of the startup sequence of your application.

```php
<?php
 
$parameters = ['scheme' => 'tcp', 
               'host' => REDIS_HOST, 
               'port' => REDIS_PORT, 
               'timeout' => 881
              ];
 
$options = ['prefix' => ''];
 
$sdkConfig = array(
    'cache' => array('adapter' => 'predis', 
                     'parameters' => $parameters, 
                     'options' => $options
                    )
);
 
$splitFactory = \SplitIO\Sdk::factory('YOUR_SDK_KEY', $sdkConfig);
$splitClient = $splitFactory->client();
```

### Use the SDK <a href="#use-the-sdk" id="use-the-sdk"></a>

#### Basic use <a href="#basic-use" id="basic-use"></a>

After you instantiate the SDK factory client, use the `getTreatment` method of the SDK factory client to decide what version of your feature flags your customers are served. The method requires the `FEATURE_FLAG_NAME` attribute that you want to ask for a treatment and a unique `key` attribute that corresponds to the end user that you want to serve the feature flag to.

From there, you need to use an if-else-if block as shown below and insert the code for the different treatments that you defined in Harness FME. Remember the final else branch in your code to handle the client returning [the control treatment](/feature-management-experimentation/use-fme/feature-management/setup/control-treatment.md).

```php
<?php
// The key here represents the ID of the user/account/etc you're trying to evaluate a treatment for
$treatment = $splitClient->getTreatment('key','FEATURE_FLAG_NAME');
 
if ($treatment === 'on') {
    // insert code here to show on treatment
} elseif ($treatment === 'off') {
    // insert code here to show off treatment
} else {
    // insert your control treatment code here
}
```

#### Attribute syntax <a href="#attribute-syntax" id="attribute-syntax"></a>

To [target based on custom attributes](/feature-management-experimentation/use-fme/feature-management/targeting/target-with-custom-attributes.md), the SDK's `getTreatment` method needs to pass an attribute map at runtime.

In the example below, we are rolling out a feature flag to users. The provided attributes `plan_type`, `registered_date`, `permissions`, `paying_customer`, and `deal_size` are passed to the `getTreatment` call. These attributes are compared and evaluated against the attributes used in the rollout plan as defined in Harness FME to decide whether to show the `on` or `off` treatment to this account.

The `getTreatment` method supports five types of attributes: strings, numbers, dates, booleans, and sets. The proper data type and syntax for each are:

* **Strings:** Use type String.
* **Numbers:** Use type Integer.
* **Dates:** Express the value in `seconds since epoch`. Use a timestamp represented by an Integer.
* **Booleans:** Use type Boolean.
* **Sets:** Use type Array.

```php
<?php
 
$attributes["plan_type"] = "growth";
$attributes["registered_date"] = (new DateTime("now", new DateTimeZone("UTC")))->getTimestamp();
$attributes["deal_size"] = 10000;
$attributes["paying_customer"] = True;
$attributes["permissions"] = array("gold","silver","platinum");
 
$treatment = $splitClient->getTreatment('key', 'FEATURE_FLAG_NAME', $attributes);
 
if ($treatment === 'on') {
    // insert code here to show on experience
} elseif ($treatment === 'off') {
    // insert code here to show off experience
} else {
    // insert your control treatment code here to show no reporting
}
```

#### Multiple evaluations at once <a href="#multiple-evaluations-at-once" id="multiple-evaluations-at-once"></a>

In some instances, you may want to evaluate treatments for multiple feature flags at once. Use the different variations of `getTreatments` from the SDK factory client to do this.

* `getTreatments`: Pass a list of the feature flag names you want treatments for.
* `getTreatmentsByFlagSet`: Evaluate all flags that are part of the provided set name and are cached on the SDK instance.
* `getTreatmentsByFlagSets`: Evaluate all flags that are part of the provided set names and are cached on the SDK instance.

{% tabs %}
{% tab title="getTreatments" %}

```php
$treatments = $splitClient->getTreatments('key', ['FEATURE_FLAG_NAME_1', 'FEATURE_FLAG_NAME_2']);
 
echo json_encode($treatments);
```

{% endtab %}

{% tab title="getTreatmentsByFlagSet" %}

```php
$treatments = $splitClient->getTreatmentsByFlagSet('key', 'backend');
 
echo json_encode($treatments);
```

{% endtab %}

{% tab title="getTreatmentsByFlagSets" %}

```php
$treatments = $splitClient->getTreatmentsByFlagSets('key', ['backend', 'server_side']);
 
echo json_encode($treatments);
```

{% endtab %}
{% endtabs %}

You can also use the [Split Manager](#manager) to get all of your treatments at once.

#### Get Treatments with Configurations <a href="#get-treatments-with-configurations" id="get-treatments-with-configurations"></a>

To [leverage dynamic configurations with your treatments](/feature-management-experimentation/use-fme/feature-management/setup/dynamic-configurations.md), you should use the `getTreatmentWithConfig` method. This method returns an object containing the treatment and associated configuration.

The config element is a stringified version of the configuration JSON defined in Harness FME. If there is no configuration defined for a treatment, the SDK returns `null` for the config parameter.

This method takes the exact same set of arguments as the standard `getTreatment` method. See below for examples on proper usage:

```php
$result = $splitClient->getTreatmentWithConfig("KEY", "FEATURE_FLAG_NAME", attributes);
$config = json_decode($result["config"], true);
$treatment = $result["treatment"];
```

If you need to get multiple evaluations at once, you can also use the `getTreatmentsWithConfig` methods. These methods take the exact same arguments as the [getTreatments](#multiple-evaluations-at-once) methods but return a mapping of feature flag names to SplitResult instead of strings. See example usage below:

{% tabs %}
{% tab title="getTreatmentsWithConfig" %}

```php
$TreatmentResults = $splitClient->getTreatmentsWithConfig('KEY', array('FEATURE_FLAG_NAME_1' 'FEATURE_FLAG_NAME_2'), attributes);
// TreatmentResults will have the following form: 
// {
//   FEATURE_FLAG_NAME_1: {treatment: 'on',
//                  config: "{ 'color' : 'red'}}",
//   FEATURE_FLAG_NAME_2: {treatment: 'v2',
//                  config: "{ 'copy' : 'better copy'}}",
// }
```

{% endtab %}

{% tab title="getTreatmentsWithConfigByFlagSet" %}

```php
$treatments = $splitClient->getTreatmentsWithConfigByFlagSet('KEY', 'backend')
// $treatments will have the following form: 
// {
//   FEATURE_FLAG_NAME_1: {treatment: 'on',
//                  config: "{ 'color' : 'red'}}",
//   FEATURE_FLAG_NAME_2: {treatment: 'v2',
//                  config: "{ 'copy' : 'better copy'}}",
// }
```

{% endtab %}

{% tab title="getTreatmentsWithConfigByFlagSets" %}

```php
$treatments = $splitClient->getTreatmentsWithConfigByFlagSets('KEY', ['backend', 'server_side'])
// $treatments will have the following form: 
// {
//   FEATURE_FLAG_NAME_1: {treatment: 'on',
//                  config: "{ 'color' : 'red'}}",
//   FEATURE_FLAG_NAME_2: {treatment: 'v2',
//                  config: "{ 'copy' : 'better copy'}}",
// }
```

{% endtab %}
{% endtabs %}

#### Shutdown <a href="#shutdown" id="shutdown"></a>

Due to the nature of PHP and the way HTTP requests are handled, the client is instantiated on every request and automatically destroyed when the request lifecycle comes to an end. The data is stored in Redis, which is populated by an external synchronization tool, so it does not make sense to provide a shutdown method within the PHP client. If desired, you can manually start or stop the Split Synchronizer and flush the Redis database.

### Track <a href="#track" id="track"></a>

Use the `track` method to record any actions your customers perform. Each action is known as an `event` and corresponds to an `event type`. Calling `track` through one of our SDKs or via the API is the first step to and allows you to measure the impact of your feature flags on your users’ actions and metrics.

Refer to the [Events](/feature-management-experimentation/use-fme/release-monitoring/events/index.md) documentation for more information about using track events in feature flags.

In the examples below you can see that the `.track()` method can take up to five arguments. The proper data type and syntax for each are:

* **key:** The `key` variable used in the `getTreatment` call and firing this track event. The expected data type is **String**.
* **TRAFFIC\_TYPE:** The traffic type of the key in the track call. The expected data type is **String**. You can only pass values that match the names of [traffic types](/feature-management-experimentation/management-and-administration/traffic-types.md) that you have defined in FME.
* **EVENT\_TYPE:** The event type that this event should correspond to. The expected data type is **String**. Full requirements on this argument are:
  * Contains 63 characters or fewer.
  * Starts with a letter or number.
  * Contains only letters, numbers, hyphen, underscore, or period.
  * This is the regular expression we use to validate the value:\
    `[a-zA-Z0-9][-_\.a-zA-Z0-9]{0,62}`
* **VALUE:** (Optional) The value to be used in creating the metric. This field can be sent in as null or 0 if you intend to purely use the count function when creating a metric. The expected data type is **Integer** or **Float**.
* **PROPERTIES:** (Optional) An Map of key value pairs that can be used to filter your metrics. Learn more about event property capture in the [Events](/feature-management-experimentation/use-fme/release-monitoring/events/index.md#event-properties) guide. FME currently supports three types of properties: strings, numbers, and booleans.

{% hint style="warning" %}
**REDIS SUPPORT**

If you are using our SDK with Redis, you need Split Synchronizer v2.3.0 version at least in order to support *properties* in the `track` method.
{% endhint %}

The `track` method returns a boolean value of `true` or `false` to indicate whether or not the SDK was able to successfully queue the event to be sent back to Harness servers on the next event post. The SDK will return `false` if the current queue size is equal to the config set by `eventsQueueSize` or if an incorrect input to the `track` method has been provided.

In the case that a bad input has been provided, you can read more about our SDK's expected behavior in the [Events documentation](/feature-management-experimentation/use-fme/release-monitoring/events/index.md).

```php
<?php
 
// If you would like to send an event without a value 
$trackEvent = $splitClient->track("KEY", "TRAFFIC_TYPE", "EVENT_TYPE");
// Example
$trackEvent = $splitClient->track("john@doe.com", "user", "page_load_time");

// If you would like to associate a value to an event
$trackEvent = $splitClient->track("KEY", "TRAFFIC_TYPE", "EVENT_TYPE", VALUE);
// Example  
$trackEvent = $splitClient->track("john@doe.com", "user", "page_load_time", 83.334);

// If you would like to associate just properties to an event
$trackEvent = $splitClient->track("KEY", "TRAFFIC_TYPE", "EVENT_TYPE", null, {PROPERTIES});

// If you would like to associate a value and properties to an event
$trackEvent = $splitClient->track("KEY", "TRAFFIC_TYPE", "EVENT_TYPE", VALUE, {PROPERTIES});
// Example
$properties = array(
    "package" => "premium",
    "admin" => true,
    "discount" => 50
);
$trackEvent = $splitClient->track("KEY", "TRAFFIC_TYPE", "EVENT_TYPE", 83.334, $properties);
```

### Configuration <a href="#configuration" id="configuration"></a>

With the SDK architecture, there is a set of options that you can configure to get everything connected and working as expected.

| **Option**         | **Description**                                                                                                             |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| labelsEnabled      | Enable a descriptive label for each generated impression. Refer to the [Impressions data](#impressions-data) section below. |
| ipAddress          | Manually set the IP address of your server to attach as metadata when impressions are sent.                                 |
| log                | Configure the log adapter and level. Refer to the [Logging](#logging) section.                                              |
| cache              | Configure the Redis cache adapter. Refer to the [Redis cache](#redis-cache) section.                                        |
| impressionListener | Instance of an impression listener to send impression data to a custom location.                                            |
| IPAddressesEnabled | Flag to disable IP addresses and host name from being sent to the Harness servers.                                          |

```php
<?php
 
$sdkConfig = array(
   'labelsEnabled' => false,
   'ipAddress' => '15.2.34.123',
   'log' => array(...),
   'cache' => array(...),
);
 
$splitFactory = \SplitIO\Sdk::factory('YOUR_SDK_KEY', $sdkConfig);
$splitClient = $splitFactory->client();
```

#### Impressions data <a href="#impressions-data" id="impressions-data"></a>

By default, our SDK sends small amounts of information to our backend about why your customer saw a given treatment from your app. An example would be that a user saw the `on` treatment because they were `in segment all`. This information can be useful for experiments and debugging. However, if you prefer to not send this information to our servers, you can turn it off by setting the SDK configuration option `labelsEnabled`.

#### Redis cache <a href="#redis-cache" id="redis-cache"></a>

The Synchronizer Service stores its fetched data in the cache component. The SDK requires `predis` as the Redis cache adapter. For more information about `predis`, refer to the [Predis project](https://github.com/nrk/predis).

```php
<?php
 
$parameters = ['scheme' => 'tcp', 
               'host' => REDIS_HOST, 
               'port' => REDIS_PORT, 
               'timeout' => 881
              ];
 
$options = ['prefix' => ''];
 
$sdkConfig = array(
    'cache' => array('adapter' => 'predis', 
                     'parameters' => $parameters, 
                     'options' => $options
                    )
);
 
$splitFactory = \SplitIO\Sdk::factory('YOUR_SDK_KEY', $sdkConfig);
$splitClient = $splitFactory->client();
```

**Redis Sentinel**

The SDK also supports Redis with Sentinel v2 replication. The client can be configured to operate with a single master and multiple slaves to provide high availability. The current version of Sentinel is 2. A stable release of Sentinel has been shipped since Redis 2.8. For further information about Sentinel, refer to the [Sentinel documentation](https://redis.io/topics/sentinel).

Use the following configuration for Redis in Sentinel mode.

| **Variable**        | **Type** | **Description**                                                         |
| ------------------- | -------- | ----------------------------------------------------------------------- |
| distributedStrategy | string   | The strategy to be used. For Sentinel mode, the strategy is `sentinel`. |
| sentinels           | array    | The list of sentinels for replication service.                          |
| service             | string   | The name of master service.                                             |

```php
<?php
 
$sentinels = array(
    'tcp://SENTINEL_HOST_1:SENTINEL_PORT_1?timeout=10',
    'tcp://SENTINEL_HOST_2:SENTINEL_PORT_2?timeout=10',
    'tcp://SENTINEL_HOST_3:SENTINEL_PORT_3?timeout=10'
);
 
$options = array(
    'distributedStrategy' => 'sentinel',
    'service' => 'SERVICE_MASTER_NAME',
    'prefix' => ''
);
 
$sdkConfig = array(
    'cache' => array('adapter' => 'predis',
                     'sentinels' => $sentinels,
                     'options' => $options
                    )
);
 
$splitFactory = \SplitIO\Sdk::factory('YOUR_SDK_KEY', $sdkConfig);
$splitClient = $splitFactory->client();
```

**Redis cluster support**

The SDK supports Redis with Cluster. Note that a stable release of Cluster has shipped since Redis 3.0. For further information about Redis Cluster, refer to the [Cluster documentation](https://redis.io/topics/cluster-spec).

Use the following configuration for Redis in Cluster mode.

| **Variable**        | **Type** | **Description**                                                                                                                                            |
| ------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| distributedStrategy | string   | The strategy to be used. For Cluster mode, the strategy is `cluster`.                                                                                      |
| clusterNodes        | array    | The list of cluster nodes.                                                                                                                                 |
| keyHashTag          | string   | Custom hashtag to be used. Default value is `{SPLITIO}`.                                                                                                   |
| keyHashTags         | array    | List of custom hashtags from which the SDK randomly picks one to use on the generated instance. If this is set, the tag on `keyHashTag` config is ignored. |

```php
<?php
 
$clusterNodes = array(
    'tcp://CLUSTER_NODE_1:CLUSTER_PORT_1?timeout=10',
    'tcp://CLUSTER_NODE_2:CLUSTER_PORT_2?timeout=10',
    'tcp://CLUSTER_NODE_3:CLUSTER_PORT_3?timeout=10'
);
 
$options = array(
    'distributedStrategy' => 'cluster',
    'prefix' => ''
);
 
$sdkConfig = array(
    'cache' => array('adapter' => 'predis',
                     'clusterNodes' => $clusterNodes,
                     'options' => $options
                    )
);
 
$splitFactory = \SplitIO\Sdk::factory('YOUR_SDK_KEY', $sdkConfig);
$splitClient = $splitFactory->client();
```

{% hint style="info" %}
**REDIS CLUSTER**

The PHP SDK performs multi-key operations in certain methods such as `mget` (to return values of all specified keys) or `keys` (to return all the keys that matches a particular pattern) to avoid multiple calls to Redis. Redis Cluster does not allow these operations unless you use hashtags. Hashtags ensure that multiple keys are allocated in the same hash slot. The SDK allows you to use a custom key hashtag for storing keys. If this option is missing, it uses a default hashtag of `{SPLITIO}` when `cluster` mode is specified in the configuration. Keep in mind that multi-key operations may become unavailable during a resharding of the hash slots, calls to `getTreatments`, or `manager.splitNames()`, causing `featureFlagKeys` to fail.
{% endhint %}

**TLS Support**

The client can leverage TLS/SSL encryption to connect to a secured remote Redis instance by using `tls` scheme and `ssl` options.

```php
<?php
 
$parameters = [
                'scheme' => 'tls', 
                'ssl' => array(), 
                'host' => REDIS_HOST, 
                'port' => REDIS_PORT, 
            ];
 
$options = ['prefix' => ''];
 
$sdkConfig = array(
    'cache' => array('adapter' => 'predis', 
                     'parameters' => $parameters, 
                     'options' => $options
                    )
);
 
$splitFactory = \SplitIO\Sdk::factory('YOUR_SDK_KEY', $sdkConfig);
$splitClient = $splitFactory->client();
```

### Localhost mode <a href="#localhost-mode" id="localhost-mode"></a>

For testing, a developer can put code behind feature flags on their development machine without the SDK requiring network connectivity. To achieve this, the SDK can be started in **localhost** mode (aka off-the-grid mode). In this mode, the SDK neither polls nor updates Harness servers. Instead, it uses an in-memory data structure to determine what treatments to show to the logged in customer for each of the features.

To use the SDK in localhost mode, replace the SDK Key with "localhost", as shown in the example below:

```php
<?php
 
$splitFactory = \SplitIO\Sdk::factory('localhost');
$splitClient = $splitFactory->client();
```

In this mode, the SDK loads a mapping of feature flag name to treatment from a file at `$HOME/.split`. For a given feature flag, the treatment specified in the file is returned for every customer.

`getTreatment` calls for a feature flag only return the one treatment that you defined in the file. You can then change the treatment as necessary for your testing in the file. Any feature flag that is not provided in the `featureFlags` map returns [the control treatment](/feature-management-experimentation/use-fme/feature-management/setup/control-treatment.md) if the SDK is asked to evaluate them.

The format of this file is two columns separated by a whitespace. The left column is the feature flag name, and the right column is the treatment name. Here is a sample `.split` file.

```bash
## this is a comment <a href="#this-is-a-comment" id="this-is-a-comment"></a>
 
## sdk.getTreatment(*, reporting_v2) will return 'on' <a href="#sdkgettreatment-reportingv2-will-return-on" id="sdkgettreatment-reportingv2-will-return-on"></a>
reporting_v2 on
 
## sdk.getTreatment(*, double_writes_to_cassandra) will return 'off' <a href="#sdkgettreatment-doublewritestocassandra-will-return-off" id="sdkgettreatment-doublewritestocassandra-will-return-off"></a>
double_writes_to_cassandra off
 
## sdk.getTreatment(*, new-navigation) will return 'v3' <a href="#sdkgettreatment-new-navigation-will-return-v3" id="sdkgettreatment-new-navigation-will-return-v3"></a>
new-navigation v3
```

Since version 6.1.0, our SDK supports a new type of localhost feature flag definition file, using the YAML format. This new format allows the user to map different keys to different treatments within a single feature flag, and also adds configurations to them. The new format is a list of single-key maps (one per mapping feature-flag-keys-config), defined as follows:

```yaml
## - feature_flag_name: <a href="#featureflagname" id="featureflagname"></a>
## treatment: "treatment_applied_to_this_entry" <a href="#treatment-treatmentappliedtothisentry" id="treatment-treatmentappliedtothisentry"></a>
## keys: "single_key_or_list" <a href="#keys-singlekeyorlist" id="keys-singlekeyorlist"></a>
## config: "{\"desc\" : \"this applies only to ON treatment\"}" <a href="#config-desc-this-applies-only-to-on-treatment" id="config-desc-this-applies-only-to-on-treatment"></a>
- my_feature:
    treatment: "on"
    keys: "key"
    config: "{\"desc\" : \"this applies only to ON treatment\"}"
- some_other_feature:
    treatment: "off"
- my_feature:
    treatment: "off"
```

In the example above, we have 3 entries:

* The first entry defines that for feature flag `my_feature`, the key `key` returns the treatment `on` and the `on` treatment is tied to the configuration `{"desc" : "this applies only to ON treatment"}`.
* The second entry defines that the feature flag `some_other_feature` always returns the `off` treatment and no configuration.
* The third entry defines that `my_feature` always returns `off` for all keys that don't match another entry (in this case, any key other than `key`).

### Manager <a href="#manager" id="manager"></a>

Use the Split Manager to get a list of feature flags available to the SDK factory client.

To instantiate a Manager in your code base, use the same factory that you used for your client.

```php
<?php
 
$splitFactory = \SplitIO\Sdk::factory('YOUR_SDK_KEY', $options);
$splitManager = $splitFactory->manager();
```

The Manager then has the following methods available.

```php
<?php
namespace SplitIO\Sdk\Manager;
 
interface SplitManagerInterface
{
    /**
     * Retrieves the feature flags that are currently registered with the
     * SDK.
     *
     * @return array of \SplitIO\Sdk\Manager\SplitView
     */
    public function splits();
 
    /**
     * Returns the feature flags registered with the SDK of this name.
     *
     * @param $featureFlagName
     * @return \SplitIO\Sdk\Manager\SplitView
     */
    public function split($featureFlagName);
}
```

The `SplitView` object referenced above has the following structure.

```php
<?php
namespace SplitIO\Sdk\Manager;
 
class SplitView
{
    private $name;
    private $trafficType; // the name of the traffic type
    private $killed;
    private $treatments;
    private $changeNumber;
    private $configs;
  
  // Getter and Setter methods have been omitted
}
```

### Listener <a href="#listener" id="listener"></a>

FME SDKs send impression data back to Harness servers periodically when evaluating feature flags. To send this information to a location of your choice, define and attach an *impression listener*. Use the SDK's `impressionListener` parameter, where you can add an implementation of `ImpressionListener`. This implementation **must** define the `logImpression` method. It receives data in the following schema.

| **Name**             | **Type**   | **Description**                                                                 |
| -------------------- | ---------- | ------------------------------------------------------------------------------- |
| impression           | impression | Impression object that has the feature flag name, treatment result, label, etc. |
| attributes           | array      | A list of attributes passed by the client.                                      |
| instance-id          | string     | The IP address of the machine running the SDK.                                  |
| sdk-language-version | string     | The version of the SDK. In this case the language is `php` plus the version.    |

### Implement a custom impression listener <a href="#implement-a-custom-impression-listener" id="implement-a-custom-impression-listener"></a>

Here is an example of how to implement a custom impression listener.

```php
// Implementation Sample for a Custom Impression Listener
class CustomImpressionListener implements \SplitIO\Sdk\ImpressionListener
{
    public function logImpression($data)
    {
        // Custom Behavior
    }
}
```

#### Attach a custom impression listener <a href="#attach-a-custom-impression-listener" id="attach-a-custom-impression-listener"></a>

Here is an example of how to attach a custom impression listener.

```php
$sdkConfig = array(
    'log' => ...
    'cache' => ...
    'impressionListener' => new CustomImpressionListener(),
);
 
$splitFactory = \SplitIO\Sdk::factory('YOUR_SDK_KEY', $sdkConfig);
$splitClient = $splitFactory->client();
```

### Logging <a href="#logging" id="logging"></a>

The SDK provides a custom logger that implements the [PSR-3 standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md). **By default, the SDK logs to syslog and a WARNING log level.** To configure the logger, set the adapter and the desired log level.

{% hint style="warning" %}
**PRODUCTION ENVIRONMENTS**

For production environments, we strongly recommend setting the adapter to **syslog** and avoid using the `echo` adapter. Even better, set your own custom adapter. See [Custom logging](#custom-logging) below.
{% endhint %}

```php
<?php
$sdkConfig = array(
    'log' => array('adapter' => 'syslog', 'level' => 'error')
);
 
$splitFactory = \SplitIO\Sdk::factory('YOUR_SDK_KEY', $sdkConfig);
$splitClient = $splitFactory->client();
```

The log configuration parameters are described below.

| **Configuration** | **Description**                                                                                                                                                                                                                                                                                                                                                                                          | **Default value** |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
| adapter           | <p>The logger adapter. The SDK supports:</p><ul><li><strong>stdout:</strong> Write log messages to standard output (php\://stdout)</li><li><strong>syslog:</strong> Generate a log message that is distributed by the system logger.</li><li><strong>void:</strong> Prevent log writes.</li><li><strong>echo:</strong> Echo messages to output. Note that the output could be the web browser.</li></ul> | syslog            |
| level             | <p>The log level message. According the <a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md">PSR-3 standard</a> the supported levels are:</p><ul><li>emergency</li><li>alert</li><li>critical</li><li>error</li><li>warning</li><li>notice</li><li>info</li><li>debug</li></ul>                                                                             | warning           |
| psr3-instance     | Your custom logger instance that implements the [PSR-3 standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)                                                                                                                                                                                                                                                | null              |

**Custom logging**

To integrate a third-party logger, follow this example of including the Zend logger.

```php
<?php
 
$zendLogLogger = new Zend\Log\Logger;
$psrLogger = new Zend\Log\PsrLoggerAdapter($zendLogLogger);
 
/** SDK options */
$options = [
    'log'   => ['psr3-instance' => $psrLogger],
];
 
/** Create the SDK factory client instance. */
$splitFactory = \SplitIO\Sdk::factory('YOUR_SDK_KEY', $options);
$splitClient = $splitFactory->client();
```

Another example is [Monolog](https://github.com/Seldaek/monolog). Monolog sends your logs to files, sockets, inboxes, databases, and various web services. See the complete list of handlers in the [Monolog documentation](https://github.com/Seldaek/monolog/blob/master/doc/02-handlers-formatters-processors.md).

```php
<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
 
/** create a log channel */
$psrLogger = new Logger('SplitIO');
$psrLogger->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
 
/** SDK options */
$options = [
    'log'   => ['psr3-instance' => $psrLogger],
];
 
/** Create the client instance. */
$splitClient = \SplitIO\Sdk::factory('YOUR_SDK_KEY', $options);
```

### Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

#### Why is PHP unable to write impressions to Redis throwing error "NOAUTH Authentication required"? <a href="#why-is-php-unable-to-write-impressions-to-redis-throwing-error-noauth-authentication-required" id="why-is-php-unable-to-write-impressions-to-redis-throwing-error-noauth-authentication-required"></a>

Using the PHP SDK with Redis and Split Synchronizer, calling `getTreatment` causes an exception:

```csharp
Fetching item ** SPLITIO.split.test ** from cache getTreatment method is throwing exceptions NOAUTH Authentication required.
```

The Redis instance requires authentication, but the PHP SDK configuration is missing the password parameter.

Add the Redis password to the configuration parameters passed to the PHP SDK:

```php
$options = [
  'prefix' => '',
  'parameters' => [
      'password' => 'REDISPASSWORD'
  ],
];

$sdkConfig = array(
  'cache' => array(
    'adapter' => 'predis', 
    'parameters' => $parameters, 
    'options' => $options
  )
);
```

This ensures the SDK authenticates properly with Redis.
