datatester / datatester-php-sdk
PHP Datatester SDK
Requires
- php: >=7.1
- ext-json: *
- composer/semver: ^3.2
- guzzlehttp/guzzle: ~6.2
- lastguest/murmurhash: ^2.0
- monolog/monolog: ^1.25
Requires (Dev)
- ext-json: *
- phpunit/phpunit: ^9.5
This package is not auto-updated.
Last update: 2024-09-25 06:59:10 UTC
README
限制
此 SDK 仅支持 PHP 7.1 及更高版本。
先决条件
获取您项目的 App Key
- 前往 BytePlus 控制台 并登录您的账户。
- 在 产品 部分,点击 BytePlus 数据智能。
- 在 项目列表 页面,对于要集成 SDK 的项目,在 操作 列下,点击 详情。
- 在 社交媒体详情 弹出窗口中,复制 App Key。
添加依赖
- 将此 SDK 下载到您项目的路径:git clone https://github.com/volcengine/datatester-php-sdk.git
├── src
├── datatester-php-sdk
├── composer.json
├── composer.lock
└── vendor
- 修改 composer.json 文件,添加 "repositories" 结构。
"repositories": [
{
"type": "path",
"url": "./datatester-php-sdk/"
}
]
- 通过运行以下代码在本地安装软件包。
composer require -W datatester/datatester-php-sdk
更改域名
默认域名必须按以下方式更改。源文件是 [Urls.php]。
const BASE_URL = 'https://datarangers.com';
const EVENT_URL = 'https://mcs.tobsnssdk.com/v2/event/list';
使用 SDK
以下是一个使用 PHP SDK 的代码示例。
use DataTester\Client\AbClient;
// Initialize the traffic-allocating object
// Find your app key by clicking "details" on the project list page on the BytePlus console
$abClient = new AbClient("${app_key}");
// The second value is the log interface. You can change it if you want
// The third value is for managing meta information. You can change it if you want
// The fourth value is for event tracking. You can change it if you want
// userAbInfoHandler is to ensure that incoming users do not leave the version. If you want to constantly store the information of incoming users, you can implement UserAbInfoHandler by yourself
// $abClient = new AbClient("ede2cd73482xxxxxx05bd1b24c1", $logger, $configManager, $eventDispatcher,$userAbInfoHandler);
// The user identifier for event tracking. You need to replace it with the actual user ID
$trackId = "uuid";
// The local user identifier. Not used for event tracking. You need to replace it with the actual user ID
$decisionId = "decisionID";
// When a user/device is not in this version, then the value of this parameter is returned. You can set its value as "null"
$defaultValue = true;
// User properties. Only used for allocating the traffic
$attributes = [];
// It is recommended that you use this interface
// The first parameter is the experiment key
$value = $abClient->activate(
"${experiment_key}",
$decisionId,
$trackId,
$attributes,
$defaultValue);
if ($value) {
// The control version
} else {
// The variant version
}
API 参考
AbClient
初始化期间进行流量分配的类。
__construct(
$token,
LoggerInterface $logger = null,
ProductConfigManagerInterface $productConfigManager = null,
EventDispatcherInterface $eventDispatcher = null,
UserAbInfoHandler $userAbInfoHandler = null
)
参数描述
activate
在流量分配后获取特定实验版本的配置,并自动跟踪暴露的事件。
如果要跟踪事件,请确保填写 trackId 字段。
activate($variantKey, $decisionId, $trackId, $attributes, $defaultValue): object
参数描述
返回值
用户输入的版本参数或用户/设备不在任何版本时的默认值。可以是字符串、数字、布尔值和 json 类型。以下是一个示例
// When the parameter type is string, the returned value is string "a";
// When the parameter type is number, the returned value is float 123.456;
// When the parameter type is boolean, the returned value is boolean true;
// When the parameter type is json, the returned value array ["key" => "a"].
activateWithoutImpression
在流量分配后获取特定实验版本的配置,但不跟踪暴露的事件。
activateWithoutImpression($variantKey, $decisionId, $attributes): array
参数描述
返回值
版本参数或空数组。以下是一个示例
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:
[]
getExperimentVariantName
获取用户输入的实验版本的名称
getExperimentVariantName($experimentId, $decisionId, $attributes): ?string
参数描述
返回值
用户输入的版本名称或用户/设备不在任何版本时的 "None"。以下是一个示例
getExperimentConfigs
获取用户输入的版本的相关详细信息
getExperimentConfigs($experimentId, $decisionId, $attributes): ?array
参数描述
返回值
用户输入的版本的详细信息或用户/设备不在该版本时的 'None'。以下是一个示例
[
'string' =>
[
'val' => 'b',
'vid' => '36872'
],
'number' =>
[
'val' => 789.123,
'vid' => '36872'
],
'json' =>
[
'val' =>
[
'key' => 'b'
],
'vid' => '36872'
],
'boolean' =>
[
'val' => false,
'vid' => '36872'
]
]
getAllExperimentConfigs
获取所有实验中所有版本的相关详细信息。
getAllExperimentConfigs($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'
],
'color' =>
[
'val' => 'red',
'vid' => '36875'
]
]
getFeatureConfigs
获取用户加入的功能的相关详细信息
getFeatureConfigs($featureId, $decisionId, $attributes): ?array
参数描述
返回值
用户加入的功能变体的详细信息。如果用户/设备不在该功能中或该功能已禁用,则为 "None"。以下是一个示例
[
'feature_key' =>
[
'val' => 'prod',
'vid' => '20006421'
]
]
getAllFeatureConfigs
获取用户加入的所有功能的相关详细信息。
getAllFeatureConfigs($decisionId, $attributes): ?array
参数描述
返回值
用户加入的所有功能变体的详细信息。以下是一个示例
[
'feature_key' =>
[
'val' => 'prod',
'vid' => '20006421'
],
'feature_key_color' =>
[
'val' => true,
'vid' => '20006423'
]
]
getExperimentVariantNameWithImpression
获取用户输入的实验版本的名称。
与 WithImpression 接口接口自动跟踪事件。同时,如果想要跟踪事件,请确保在 activate 接口中填写 trackId 字段。
getExperimentVariantNameWithImpression($experimentId, $decisionId, $attributes): ?string
参数描述
返回值
用户输入的版本名称或用户/设备不在任何版本时的 "None"。以下是一个示例
getExperimentConfigsWithImpression
获取用户输入的版本的相关详细信息。
与 WithImpression 接口接口自动跟踪事件。同时,如果想要跟踪事件,请确保在 activate 接口中填写 trackId 字段。
getExperimentConfigsWithImpression($experimentId, $decisionId, $attributes): ?array
参数描述
返回值
用户输入的版本的详细信息或用户/设备不在该版本时的 'None'。以下是一个示例
[
'string' =>
[
'val' => 'b',
'vid' => '36872'
],
'number' =>
[
'val' => 789.123,
'vid' => '36872'
],
'json' =>
[
'val' =>
[
'key' => 'b'
],
'vid' => '36872'
],
'boolean' =>
[
'val' => false,
'vid' => '36872'
]
]
getFeatureConfigsWithImpression
获取用户加入的功能的相关详细信息
与 WithImpression 接口接口自动跟踪事件。同时,如果想要跟踪事件,请确保在 activate 接口中填写 trackId 字段。
getFeatureConfigsWithImpression($featureId, $decisionId, $attributes): ?array
参数描述
返回值
用户加入的功能变体的详细信息。如果用户/设备不在该功能中或该功能已禁用,则为 "None"。以下是一个示例
[
'feature_key' =>
[
'val' => 'prod',
'vid' => '20006421'
]
]
其他
为了更好地使用SDK,提供了一些建议。
LoggerInterface
日志接口提供了默认实现;如有业务需求,可以自定义实现类,在实例化AbClient时使用。
ProductConfigManagerInterface
元管理接口:请求元服务以拉取应用下的实验和特征信息。默认实现在每次实例化AbClient时实时拉取;如有业务需求,可以自定义实现类,在实例化AbClient时使用。
建议
建议使用redis缓存元信息,以避免每次初始化AbClient时都进行拉取。
以下是一个示例
$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);
}
}
EventDispatcherInterface
事件跟踪接口:跟踪曝光事件,提供默认实现,在调用'activate'和'WithImpression'接口时实时跟踪;如有业务需求,可以自定义实现类,在实例化AbClient时使用。
建议
建议使用mq(kafka/rocketmq)跟踪事件,以避免每次调用接口时通过http跟踪事件。
- 事件发生时发送消息到mq
- 使用其他服务消费kafka并跟踪事件
以下是一个示例
$client = new AbClient("token", null, null, new KafkaEventDispatcher());
class KafkaEventDispatcher implements EventDispatcherInterface
{
public function dispatchEvent($events)
{
// need to implement it yourself
kafka.send(JsonParse::transferArray2JsonStr($events));
}
}
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;
}
}
匿名跟踪
如果没有用户_unique_id作为跟踪ID,可以使用device_id、web_id、bddid(仅限本地)进行匿名跟踪。
- 设置事件构建器配置
enable anonymously tracking
$this->_abClient->setEventBuilderConfig(true, true);
- 当trackId为空字符串时,将device_id、web_id、bddid附加到$attributes中
$trackId = "";
$attributes["device_id"] = 1234; int
$attributes["web_id"] = 5678; int
$attributes["bddid"] = "91011"; string
- 调用activate或其他'WithImpression'接口
DataTester PHP SDK
版本需求
php7.1及更高版本
准备工作
获取应用的App Key(即SDK使用的token)
- 访问火山引擎并登录您的账号
- 进入集团设置页面,找到应用列表-应用ID列
- 将鼠标悬停在应用ID后的感叹号上以获取App Key
依赖导入
- 将SDK下载到项目路径下: git clone https://github.com/volcengine/datatester-php-sdk.git
├── src
├── datatester-php-sdk
├── composer.json
├── composer.lock
└── vendor
- 修改项目的composer.json文件,添加repositories结构
"repositories": [
{
"type": "path",
"url": "./datatester-php-sdk/"
}
]
- 安装本地包
composer require -W datatester/datatester-php-sdk
域名修改
SaaS-国内: 默认使用的是SaaS国内环境的域名,无需修改
const BASE_URL = 'https://data.bytedance.com';
const EVENT_URL = 'https://mcs.ctobsnssdk.com/v2/event/list';
SaaS-海外: 海外环境需要修改BASE_URL和EVENT_URL,替换为BASE_URL_I18N与EVENT_URL_I18N即可
修改如下
const BASE_URL = 'https://datarangers.com';
const EVENT_URL = 'https://mcs.tobsnssdk.com/v2/event/list';
私有化: 私有化部署时会有产品域名和上报域名,如下所示,BASE_URL替换为产品域名,EVENT_URL替换为上报域名
例如:产品域名为product.cc,上报域名为product.com,则修改如下
const BASE_URL = 'https://product.cc';
const EVENT_URL = 'https://product.com/v2/event/list';
代码示例
use DataTester\Client\AbClient;
// 初始化ABTest分流类,token获取方式详见接口描述-AbClient
$abClient = new AbClient("ede2cd734827cccf9c051005bd1b24c1");
// 第2个缺省值,日志接口,可根据业务需要传入自定义实现类,SDK提供默认实现
// 第3个缺省值,实验Meta信息管理接口,可根据业务需要传入自定义实现类,SDK提供默认实现
// 第4个缺省值,进组曝光事件上报接口,可根据业务需要传入自定义实现类,SDK提供默认实现
// 第5个缺省值,进组信息持久化接口,可根据业务需要传入自定义实现类,SDK提供默认实现(不持久化)
// $abClient = new AbClient("ede2cd734827cccf9c051005bd1b24c1", $logger, $configManager, $eventDispatcher,$userAbInfoHandler);
// trackId 事件上报用户标识,用于事件上报,请替换为客户的真实用户标识
$trackId = "uuid";
// decisionID: 本地分流用户标识,不用于事件上报,请替换为客户的真实用户标识
$decisionId = "decisionID";
// defaultValue: 当分流未命中时返回该值,根据业务需要使用,可传null
$defaultValue = "default_value";
// attributes: 用户属性,仅用于分流,不随埋点上报,可参考https://www.volcengine.com/docs/6287/65826
$attributes = [];
// 推荐接口 abtest_param为需要通过分流下发的参数名称
$value = $abClient->activate(
"abtest_param",
$decisionId,
$trackId,
$attributes,
$defaultValue);
if ($value === "param_raw") {
// 对照组
} elseif ($value === "param_test") {
// 实验组
} else {
// 默认处理
}
接口描述
AbClient
初始化ABTest分流类
__construct(
$token,
LoggerInterface $logger = null,
ProductConfigManagerInterface $productConfigManager = null,
EventDispatcherInterface $eventDispatcher = null,
UserAbInfoHandler $userAbInfoHandler = null
)
参数
activate
获取特定key的分流结果,并上报曝光事件
activate($variantKey, $decisionId, $trackId, $attributes, $defaultValue): object
参数
返回值
该函数返回命中版本的参数值,未命中时返回默认值
参数类型为string,返回值为string "a"
参数类型为number,返回值为float 123.456
参数类型为boolean,返回值为boolean true
参数类型为json,返回值为array ["key" => "a"]
activateWithoutImpression
获取特定key的分流结果,且不上报曝光事件
activateWithoutImpression($variantKey, $decisionId, $attributes): array
参数
返回值
该函数返回命中版本的参数值,未命中时返回空数组
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:
[]
getExperimentVariantName
获取用户命中的特定实验的变体名称
getExperimentVariantName($experimentId, $decisionId, $attributes): ?string
参数
返回值
该函数返回用户命中的特定实验的变体名称
getExperimentConfigs
获取用户命中的特定实验的变体详情
getExperimentConfigs($experimentId, $decisionId, $attributes): ?array
参数
返回值
该函数返回命中变体的array对象,表明用户命中某个实验的变体详情,通常仅能命中一个变体
[
'string' =>
[
'val' => 'b',
'vid' => '36872'
],
'number' =>
[
'val' => 789.123,
'vid' => '36872'
],
'json' =>
[
'val' =>
[
'key' => 'b'
],
'vid' => '36872'
],
'boolean' =>
[
'val' => false,
'vid' => '36872'
]
]
getAllExperimentConfigs
获取用户命中的所有实验的变体详情
getAllExperimentConfigs($decisionId, $attributes): ?array
参数
返回值
该函数返回命中变体的array对象,表明用户命中所有实验的变体详情,通常命中多个变体
[
'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'
]
]
getFeatureConfigs
获取用户命中的特定feature的变体详情
getFeatureConfigs($featureId, $decisionId, $attributes): ?array
参数
返回值
该函数返回命中变体的array对象,表明用户命中某个feature的变体详情,通常仅能命中一个变体
[
'feature_key' =>
[
'val' => 'prod',
'vid' => '20006421'
]
]
getAllFeatureConfigs
获取用户命中的所有feature的变体详情
getAllFeatureConfigs($decisionId, $attributes): ?array
参数
返回值
该函数返回命中变体的array对象,表明用户命中所有feature的变体详情,通常命中多个变体
[
'feature_key' =>
[
'val' => 'prod',
'vid' => '20006421'
],
'feature_key_color' =>
[
'val' => true,
'vid' => '20006423'
]
]
1、含有“WithImpression”字样的接口均会自动上报曝光事件
2、请务必填写trackId字段,否则会导致上报失效
getExperimentVariantNameWithImpression
同接口“getExperimentVariantName”
getExperimentConfigsWithImpression
同接口“getExperimentConfigs”
getFeatureConfigsWithImpression
同接口“getFeatureConfigs”
其他
LoggerInterface
日志打印接口,提供默认实现;如有业务需要,可自定义实现类处理,实例化AbClient时传入
ProductConfigManagerInterface
配置管理接口,请求meta服务拉取应用下的实验信息,提供默认实现,每次实例化AbClient时实时拉取;如有业务需要,可自定义实现类处理,实例化AbClient时传入
PHP本身不支持内存级别的缓存,可以通过文件(大多数第三方库的选择)或者借助Redis等进行缓存,通过定时任务去拉取meta信息,避免实时拉取
使用Redis缓存示例(仅供参考)
$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);
}
}
EventDispatcherInterface
事件上报接口,上报进组曝光事件,提供默认实现,调用activate与WithImpression接口时实时上报;如有业务需要,可自定义实现类处理,实例化AbClient时传入
不使用扩展PHP并不支持多线程,可以通过第三方库或者使用mq等进行异步发送,避免实时上报
基于kafka等消息队列,在实例化AbClient对象时传入EventDispatcherInterface的实现类;事件直接写入kafka,通过其他服务去消费kafka并上报(上报可参考 DefaultEventDispatcher的实现),写入和消费kafka的逻辑需自行实现
$client = new AbClient("token", null, null, new KafkaEventDispatcher());
class KafkaEventDispatcher implements EventDispatcherInterface
{
public function dispatchEvent($events)
{
// need to implement it yourself
kafka.send(JsonParse::transferArray2JsonStr($events));
}
}
UserAbInfoHandler
用户信息处理接口,冻结实验、进组不出组场景下使用
冻结实验和进组不出组需要持久化用户的进组信息,SDK提供的默认实现不进行数据持久化;如有业务需要,则实现UserAbInfoHandler接口,结合Redis或其他外部存储对用户进组信息进行持久化处理,初始化AbClient时传入。使用方式:
- 初始化AbClient时不传入UserAbInfoHandler,则默认使用空实现,不启用“进组不出组”功能
- 继承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;
}
}
匿名上报
无法获取uuid的用户,可以通过填充device_id或web_id进行事件上报(私有化场景下也支持bddid)
- 实例化AbClient后修改事件上报相关配置,setEventBuilderConfig第一个参数(true/开启,false/关闭)匿名上报,第二个参数(true/saas,false/私有化)
enable anonymously tracking
$this->_abClient->setEventBuilderConfig(true, true);
- 将device_id、web_id、bddid添加到用户属性$attributes中,trackId固定传入空字符串""
$trackId = "";
$attributes["device_id"] = 1234; int
$attributes["web_id"] = 5678; int
$attributes["bddid"] = "91011"; string
- 请求activate或其他'WithImpression'接口即可匿名上报