将SDK下载至项目路径下,当前SDK版本:v3.0.0
git clone https://github.com/volcengine/datatester-php-sdk.git // 项目结构如下 ├── src ├── datatester-php-sdk ├── composer.json ├── composer.lock └── vendor
说明:需要采用本地依赖的方式。
"repositories": [ { "type": "path", "url": "./datatester-php-sdk/" } ]
composer require -W datatester/datatester-php-sdk
源文件路径datatester-php-sdk/src/DataTester/Consts/Urls.php
部署版本 | 域名 | 配置说明 |
---|---|---|
SaaS-国内 |
| 项目默认使用的是saas国内环境的域名,无需修改 |
SaaS-海外 |
| 项目默认使用的是saas国内环境的域名,海外环境需要修改BASE_URL和EVENT_URL,替换为BASE_URL_I18N与EVENT_URL_I18N即可 |
SaaS-云原生 |
| |
私有化 | 例如:产品域名为product.cc,上报域名为product.com,则修改如下
| 私有化部署时会有产品域名和上报域名,BASE_URL替换为产品域名,EVENT_URL替换为上报域名 |
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 { }
接口:
__construct(
$token,
LoggerInterface $logger=null,
ProductConfigManagerInterface $productConfigManager = null,
EventDispatcherInterface $eventDispatcher=null,
UserAbInfoHandler $userAbInfoHandler=null
)
描述: 初始化ABTest分流类
参数:
token:表明您的Tester应用。出于安全考虑,此处使用的token=appKey,而非appId。
在集团中接入一个应用后,您可以在集团相关页面查看应用的AppKey等信息,详情请参考:如何创建应用。
说明
1、LoggerInterface、ProductConfigManagerInterface、EventDispatcherInterface、UserAbInfoHandler详见文档末尾。
2、请尽早初始化AbClient,以免影响您的分流服务和埋点上报服务。
接口: 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字段,否则上报失效
接口: 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: []
接口: getExperimentVariantName($experimentId, $decisionId, $attributes): ?string
描述: 获取用户命中的特定实验的版本名称
参数:
experimentId:指定分流的实验Id
decisionId:本地分流用户标识
attributes:用户属性
返回值: 该函数返回用户命中的特定实验的版本名称
返回值示例:
返回值为string "对照版本" / "实验版本1"
接口: 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' ] ]
接口: 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' ], ]
接口: getFeatureConfigs($featureId, $decisionId, $attributes): ?array
描述: 获取用户命中的特定feature的变体详情
参数:
featureId:feature Id
decisionId:本地分流用户标识
attributes:用户属性
返回值: 该函数返回命中变体的array对象,表明用户命中某个feature的变体详情,通常仅能命中一个变体
返回值示例:
[ 'feature_key' => [ 'val' => 'prod', 'vid' => '20006421' ] ]
接口: getAllFeatureConfigs($decisionId, $attributes): ?array
描述: 获取用户命中的所有feature的变体详情
参数:
decisionId:本地分流用户标识
attributes:用户属性
返回值: 该函数返回命中变体的array对象,表明用户命中所有feature的变体详情,通常命中多个变体。
返回值示例:
与getFeatureConfigs返回结构相同,只是将多个feature的返回结果合并为一个数组
[ 'feature_key' => [ 'val' => 'prod', 'vid' => '20006421' ], 'feature_key_color' => [ 'val' => true, 'vid' => '20006423' ] ]
同接口“getExperimentVariantName”(同时上报曝光事件,需要传入trackId)
同接口“getExperimentConfigs”(同时上报曝光事件,需要传入trackId)
同接口“getFeatureConfigs”(同时上报曝光事件,需要传入trackId)
日志打印接口,提供默认实现;如有业务需要,可自定义实现类处理,实例化AbClient时传入
配置管理接口,请求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); } }
事件上报接口,上报进组曝光事件,提供默认实现,调用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)); } }
用户信息处理接口,冻结实验、进组不出组场景下使用
冻结实验和进组不出组需要持久化用户的进组信息,SDK提供的默认实现不进行数据持久化;
如有业务需要,则实现UserAbInfoHandler接口,结合Redis或其他外部存储对用户进组信息进行持久化处理,初始化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)
$client = new AbClient("token"); // enable anonymously tracking $client->setEventBuilderConfig(true, true);
$trackId = ""; $attributes["device_id"] = 1234; int $attributes["web_id"] = 5678; int $attributes["bddid"] = "91011"; string