You need to enable JavaScript to run this app.
导航

PHP SDK

最近更新时间2024.04.24 17:27:39

首次发布时间2023.04.20 14:37:18

1. 安装SDK

1.1 下载SDK

将SDK下载至项目路径下,当前SDK版本:v3.0.0

git clone https://github.com/volcengine/datatester-php-sdk.git

// 项目结构如下
├── src
├── datatester-php-sdk
├── composer.json
├── composer.lock
└── vendor

1.2 composer

说明:需要采用本地依赖的方式。

  1. php版本需求:php7.1及更高版本
  2. 修改项目的composer.json文件,添加repositories结构
"repositories": [
        {
        "type": "path",
        "url": "./datatester-php-sdk/"
        }
    ]
  1. 安装本地包
composer require -W datatester/datatester-php-sdk

1.3 域名修改

源文件路径datatester-php-sdk/src/DataTester/Consts/Urls.php

部署版本

域名

配置说明

SaaS-国内

  • const BASE_URL = 'https://data.bytedance.com';
  • const EVENT_URL = 'https://mcs.ctobsnssdk.com/v2/event/list';

项目默认使用的是saas国内环境的域名,无需修改

SaaS-海外

  • const BASE_URL = 'https://datarangers.com';
  • const EVENT_URL = 'https://mcs.tobsnssdk.com/v2/event/list';

项目默认使用的是saas国内环境的域名,海外环境需要修改BASE_URL和EVENT_URL,替换为BASE_URL_I18N与EVENT_URL_I18N即可

SaaS-云原生

  • const BASE_URL = 'https://tab.volces.com';
  • const EVENT_URL = 'https://gator.volces.com';

私有化

例如:产品域名为product.cc,上报域名为product.com,则修改如下

  • const BASE_URL = 'https://product.cc';
  • const EVENT_URL = 'https://product.com/v2/event/list';

私有化部署时会有产品域名和上报域名,BASE_URL替换为产品域名,EVENT_URL替换为上报域名

2. 代码示例
use DataTesterClientAbClient;

// 初始化ABTest分流类,token获取方式详见接口描述-AbClient
$abClient = new AbClient("appKey");
// 第2个缺省值,日志接口,可根据业务需要传入自定义实现类,SDK提供默认实现
// 第3个缺省值,实验Meta信息管理接口,可根据业务需要传入自定义实现类,SDK提供默认实现
// 第4个缺省值,进组曝光事件上报接口,可根据业务需要传入自定义实现类,SDK提供默认实现
// 第5个缺省值,进组信息持久化接口,可根据业务需要传入自定义实现类,SDK提供默认实现(不持久化)
// $abClient = new AbClient("appKey", $logger,      $configManager, $eventDispatcher,$userAbInfoHandler);

// trackId 事件上报用户标识,用于事件上报,请替换为客户的真实用户标识
$trackId = "uuid";
// decisionID: 本地分流用户标识,不用于事件上报,请替换为客户的真实用户标识
$decisionId = "decisionID";
// defaultValue: 当分流未命中时返回该值,根据业务需要使用,可传null
$defaultValue = "default_value";
// attributes: 用户属性,仅用于分流,不随埋点上报,可参考https://www.volcengine.com/docs/6287/65826
$attributes = [];

// 推荐接口 variant_key为需要通过分流下发的参数名称
$value = $abClient->activate(
    "variant_key",
    $decisionId,
    $trackId,
    $attributes,
    $defaultValue);

// 各类型参数使用示例
// number
// 对照组=123 实验组=456
if ($value == 123) {

} else if ($value == 456) {

} else {

}
// 对照组=111.23 实验组=444.56
if ($value == 111.23) {

} else if ($value == 444.56) {

} else {

}

// string
// 对照组="aaa" 实验组="bbb"
if ($value === "aaa") {

} else if ($value === "bbb") {

} else {

}

// bool
// 对照组=true 实验组=false
if ($value === true) {

} else {

}

// json
// 对照组={"key":"value_a"} 实验组={"key":"value_b"}
if ($value == null || !is_array($value)) {
    return;
}
if ($value["key"] === "value_a") {

} else if ($value["key"] === "value_b") {

} else {

}

3. 接口描述

3.1 AbClient

接口:
__construct(
$token,
LoggerInterface $logger=null,
ProductConfigManagerInterface $productConfigManager = null,
EventDispatcherInterface $eventDispatcher=null,
UserAbInfoHandler $userAbInfoHandler=null
)
描述: 初始化ABTest分流类
参数:
token:表明您的Tester应用。出于安全考虑,此处使用的token=appKey,而非appId。

1、为了获取appKey,您需要在火山引擎A/B平台进行接入,并于"集团设置-应用列表-应用ID"处获取appKey。(鼠标悬浮在应用ID后的图标上可查看appKey)
2、LoggerInterface、ProductConfigManagerInterface、EventDispatcherInterface、UserAbInfoHandler详见文档末尾。
3、请尽早初始化AbClient,以免影响您的分流服务和埋点上报服务。

3.2 activate

接口: activate($variantKey, $decisionId, $trackId, $attributes, $defaultValue):object
描述: 获取特定key的分流结果,并上报曝光事件
参数:
variantKey:变体的key
decisionId:本地分流用户标识
trackId:事件上报用户标识
attributes:用户属性
defaultValue:变体默认值
返回值: 该函数返回命中版本的参数值,未命中时返回默认值
返回值示例:

参数类型为string,返回值为string "a"
参数类型为number,返回值为float  123.456
参数类型为boolean,返回值为boolean true
参数类型为json,返回值为array ["key" => "a"]

1、该接口与所有含有“WithImpression”字样的接口均会自动上报曝光事件
2、请务必填写trackId字段,否则上报失效

3.3 activateWithoutImpression

接口: activateWithoutImpression($variantKey, $decisionId, $attributes):array
描述: 获取特定key的分流结果,且不上报曝光事件
参数:
variantKey:变体的key
decisionId:本地分流用户标识
attributes:用户属性
返回值: 该函数返回命中版本的参数值,未命中时返回空数组
返回值示例:

variantKey=string:
        [
        'val' => 'b',
        'vid' => '36872'
        ]
variantKey=number:
        [
        'val' => 789.123,
        'vid' => '36872'
        ]
variantKey=json:
        [
            'val' => 
                [
                  'key' => 'b'
                ],
            'vid' => '36872'
        ]
variantKey=boolean:
        [
        'val' => false,
        'vid' => '36872'
        ]
]
variantKey=not_exist_key:
        []

3.4 getExperimentVariantName

接口: getExperimentVariantName($experimentId, $decisionId, $attributes): ?string
描述: 获取用户命中的特定实验的版本名称
参数:
experimentId:指定分流的实验Id
decisionId:本地分流用户标识
attributes:用户属性
返回值: 该函数返回用户命中的特定实验的版本名称
返回值示例:

返回值为string   "对照版本" / "实验版本1"

3.5 getExperimentConfigs

接口: getExperimentConfigs($experimentId, $decisionId, $attributes): ?array
描述: 获取用户命中的特定实验的变体详情
参数:
experimentId:指定分流的实验Id
decisionId:本地分流用户标识
attributes:用户属性
返回值: 该函数返回命中变体的array对象,表明用户命中某个实验的变体详情,通常仅能命中一个变体
返回值示例:

[
  'string' => 
        [
        'val' => 'b',
        'vid' => '36872'
        ],
  'number' => 
        [
        'val' => 789.123,
        'vid' => '36872'
        ],    
  'json' => 
        [
            'val' => 
                [
                  'key' => 'b'
                ],
            'vid' => '36872'
        ],
  'boolean' => 
        [
        'val' => false,
        'vid' => '36872'
        ]
]

3.6 getAllExperimentConfigs

接口: getAllExperimentConfigs($decisionId, $attributes): ?array
描述: 获取用户命中的所有实验的变体详情
参数:
decisionId:本地分流用户标识
attributes:用户属性
返回值: 该函数返回命中变体的array对象,表明用户命中所有实验的变体详情,通常命中多个变体
返回值示例:
与getExperimentConfigs返回结构相同,只是将多个实验的返回结果合并为一个数组

[
  'string' => 
        [
        'val' => 'b',
        'vid' => '36872'
        ],
  'number' => 
        [
        'val' => 789.123,
        'vid' => '36872'
        ],    
  'json' => 
        [
            'val' => 
                [
                  'key' => 'b'
                ],
            'vid' => '36872'
        ],
  'boolean' => 
        [
        'val' => false,
        'vid' => '36872'
        ],
 'color' =>        [        'val' => 'red',
        'vid' => '36875'
        ],    
]

3.7 getFeatureConfigs

接口: getFeatureConfigs($featureId, $decisionId, $attributes): ?array
描述: 获取用户命中的特定feature的变体详情
参数:
featureId:feature Id
decisionId:本地分流用户标识
attributes:用户属性
返回值: 该函数返回命中变体的array对象,表明用户命中某个feature的变体详情,通常仅能命中一个变体
返回值示例:

[
  'feature_key' => 
        [
        'val' => 'prod',
        'vid' => '20006421'
        ]
]

3.8 getAllFeatureConfigs

接口: getAllFeatureConfigs($decisionId, $attributes): ?array
描述: 获取用户命中的所有feature的变体详情
参数:
decisionId:本地分流用户标识
attributes:用户属性
返回值: 该函数返回命中变体的array对象,表明用户命中所有feature的变体详情,通常命中多个变体。
返回值示例:
与getFeatureConfigs返回结构相同,只是将多个feature的返回结果合并为一个数组

[
  'feature_key' => 
        [
        'val' => 'prod',
        'vid' => '20006421'
        ],
  'feature_key_color' =>        [        'val' => true,
        'vid' => '20006423'
        ]
]

3.9 getExperimentVariantNameWithImpression

同接口“getExperimentVariantName”(同时上报曝光事件,需要传入trackId)

3.10 getExperimentConfigsWithImpression

同接口“getExperimentConfigs”(同时上报曝光事件,需要传入trackId)

3.11 getFeatureConfigsWithImpression

同接口“getFeatureConfigs”(同时上报曝光事件,需要传入trackId)

4. 其他

4.1 LoggerInterface

日志打印接口,提供默认实现;如有业务需要,可自定义实现类处理,实例化AbClient时传入

4.2 ProductConfigManagerInterface

配置管理接口,请求meta服务拉取应用下的实验信息,提供默认实现,每次实例化AbClient时实时拉取;如有业务需要,可自定义实现类处理,实例化AbClient时传入

PHP本身不支持内存级别的缓存,可以通过文件(大多数第三方库的选择)或者借助Redis等进行缓存,通过定时任务去拉取meta信息,避免实时拉取。

使用Redis缓存示例(仅供参考)

// 基于redis实现的RedisConfigManager
$client = new AbClient("token", null, new RedisConfigManager("token"));
class RedisConfigManager implements ProductConfigManagerInterface
{
    /**
     * @var ProductConfig $_productConfig
     */
    private $_productConfig;

    /**
     * @var LoggerInterface Logger instance.
     */
    private $_logger;

    /**
     * @var string $_token
     */
    private $_token;

    public function __construct(
        $token
    )
    {
        $this->_logger = new DefaultLogger();
        $this->_token = $token;
    }

    public function getConfig(): ?ProductConfig
    {
        if ($this->_productConfig != null) {
            return $this->_productConfig;
        }
        $valueFromRedis = $this->getValueFromRedis("tester_meta_info");
        // pull meta when redis cache expired
        if ($valueFromRedis == null) {
            $productConfigManger = new HTTPProductConfigManager($this->_token);
            try {
                $metaInfo = $productConfigManger->getMeta();
                $this->setValue2Redis("tester_meta_info", JsonParse::transferArray2JsonStr($metaInfo), 60);
                $this->_productConfig = new ProductConfig($metaInfo, $this->_logger);
                return $this->_productConfig;
            } catch (Exception $e) {
                return null;
            }
        }
        $metaInfo = JsonParse::transferJsonStr2Array($valueFromRedis);
        $this->_productConfig = new ProductConfig($metaInfo, $this->_logger);
        return $this->_productConfig;
    }

    private function getValueFromRedis(string $key): ?string
    { 
        // need to implement it yourself
        // return redis.get($key);
        return null;
    }

    private function setValue2Redis(string $key, string $value, int $expire)
    {
        // need to implement it yourself
        // redis.set($key, $value, $expire);
    }
}

4.3 EventDispatcherInterface

事件上报接口,上报进组曝光事件,提供默认实现,调用activate与WithImpression接口时实时上报;如有业务需要,可自定义实现类处理,实例化AbClient时传入
不使用扩展PHP并不支持多线程,可以通过第三方库或者使用mq等进行异步发送,避免实时上报
基于kafka等消息队列,在实例化AbClient对象时传入EventDispatcherInterface的实现类

// 基于kafka实现的KafkaEventDispatcher
$client = new AbClient("token", null, null, new KafkaEventDispatcher());

事件直接写入kafka,通过其他服务去消费kafka并上报(上报可参考
DefaultEventDispatcher的实现),写入和消费kafka的逻辑需自行实现

<?php
namespace DemoEventInterface;

use DataTesterEventDispatcherEventDispatcherInterface;
use DataTesterUtilsJsonParse;

class KafkaEventDispatcher implements EventDispatcherInterface
{

    public function dispatchEvent($events)
    {
        kafka.send(JsonParse::transferArray2JsonStr($events));
    }
}

4.4 UserAbInfoHandler

用户信息处理接口,冻结实验、进组不出组场景下使用
冻结实验和进组不出组需要持久化用户的进组信息,SDK提供的默认实现不进行数据持久化;
如有业务需要,则实现UserAbInfoHandler接口,结合Redis或其他外部存储对用户进组信息进行持久化处理,初始化AbClient时传入。
使用方式:

  1. 初始化AbClient时不传入UserAbInfoHandler,则默认使用空实现,不启用“进组不出组”功能。
  2. 继承UserAbInfoHandler接口,自行实现持久化存储;初始化AbClient时通过构造函数传入。

使用Redis缓存示例(仅供参考)

$client = new AbClient("token", null, null, null, new RedisHandler());

class RedisHandler implements UserAbInfoHandler
{
    public function query(string $decisionId): ?string
    {
        // need to implement it yourself
        return redis.get($decisionId);
    }

    public function createOrUpdate(string $decisionId, string $experiment2variantStr): bool
    {
        // need to implement it yourself
        return redis.set($decisionId, $experiment2variantStr);
    }

    public function needPersistData(): bool
    {
        // return true if customize this interface
        return true;
    }
}

4.5 匿名上报

获取不到uuid的用户,可以通过填充device_id或者web_id进行事件上报(私有化场景下也支持bddid)

  1. 实例化AbClient后修改事件上报相关配置,setEventBuilderConfig第一个参数(true/开启,false/关闭)匿名上报,第二个参数(true/saas,false/私有化)
$client = new AbClient("token");
// enable anonymously tracking
$client->setEventBuilderConfig(true, true);
  1. 添加device_id, web_id, bddid到用户属性$attributes,trackId固定传入空字符串""
$trackId = "";
$attributes["device_id"] = 1234; int
$attributes["web_id"] = 5678; int
$attributes["bddid"] = "91011"; string
  1. 请求activate或其他'WithImpression'接口即可匿名上报