loipv/growthbook-php

GrowthBook 的 PHP SDK,一个功能标志和 A/B 测试平台

dev-master 2023-12-13 03:50 UTC

This package is not auto-updated.

Last update: 2024-09-19 05:49:13 UTC


README

GrowthBook - PHP

为 PHP 提供强大的功能标志和 A/B 测试。

Build Status

  • 无外部依赖(除了 PSR 接口)
  • 非常快,所有评估都发生在本地
  • PHP 7.1+,100% 测试覆盖率和最高级别的 phpstan
  • 高级用户和页面定位
  • 使用您现有的事件跟踪(GA、Segment、Mixpanel、自定义)
  • 调整变体权重和定位而无需部署新代码

安装

GrowthBook 可在 Composer 上使用

composer require growthbook/growthbook

快速使用

// Create a GrowthBook instance
$growthbook = Growthbook\Growthbook::create()
  ->withAttributes([
    // Targeting attributes
    'id' => $userId,
    'someCustomAttribute' => true
  ]);

// Load feature flags from the GrowthBook API
// Make sure to use caching in production! (see 'Loading Features' below)
$growthbook->loadFeatures("sdk-abc123", "https://cdn.growthbook.io");

// Feature gating
if ($growthbook->isOn("my-feature")) {
  echo "It's on!";
} else {
  echo "It's off :(";
}

// Remote configuration with fallback
$color = $growthbook->getValue("button-color", "blue");
echo "<button style='color:${color}'>Click Me!</button>";

您评估的一些功能标志可能背后正在运行 A/B 测试,您可能希望在自己的分析系统中跟踪。

请求结束时,您可以通过循环遍历所有实验并按自己的方式跟踪它们

$impressions = $growthbook->getViewedExperiments();
foreach($impressions as $impression) {
  // Whatever you use for event tracking
  Segment::track([
    "userId" => $userId,
    "event" => "Experiment Viewed",
    "properties" => [
      "experimentId" => $impression->experiment->key,
      "variationId" => $impression->result->key
    ]
  ]);
}

加载功能

将功能加载到 SDK 中有两种方式。您可以使用带客户端密钥和 API 主机的 loadFeatures,或者您可以手动获取和缓存功能标志,并使用 withFeatures 方法传递。

loadFeatures 方法

loadFeatures 方法可以为您从 GrowthBook API 获取功能。

默认情况下,没有启用缓存。您可以通过将任何 PSR16 兼容的实例传递给 withCache 方法来启用它。

缓存对于生产使用是必需的

// Any psr-16 library will work
use Cache\Adapter\Apcu\ApcuCachePool;

$cache = new ApcuCachePool()

$growthbook = Growthbook\Growthbook::create()
  ->withCache($cache);

// You can optionally pass in a TTL (default 60s)
$growthbook = Growthbook\Growthbook::create()
  ->withCache($cache, 120); // Cache for 120s instead

要加载功能,我们需要安装一个兼容 PSR-17(HttpClient)和 PSR-18(RequestFactoryInterface)的库,例如 Guzzle。

我们将自动发现大多数 HTTP 库而无需任何配置,但如果您更喜欢显式指定它,您可以使用 withHttpClient 方法。注意 - 您需要指定一个 HttpClient 和一个 RequestFactoryInterface 实现。

loadFeatures 方法接受 3 个参数

  • $clientKey(必需)- 从 GrowthBook 中的 SDK 连接中获取此信息。
  • $apiHost(可选)- 默认为 https://cdn.growthbook.io。如果您正在自托管 GrowthBook,请将其设置为您的 API 主机。
  • $decryptionKey(可选)- 仅当您已为 SDK 连接启用加密时才需要。

withFeatures 方法

如果您更喜欢完全控制获取/缓存行为,则可以使用 withFeatures 方法,将功能数组传递给 SDK。

// From the GrowthBook API, a custom cache layer, or somewhere else
$featuresJSON = '{"my-feature":{"defaultValue":true}}';

// Decode into an associative array
$features = json_decode($featuresJSON, true);

// Pass into the Growthbook instance
$growthbook = Growthbook\Growthbook::create()
  ->withFeatures($features);

Growthbook 类

Growthbook 类具有许多属性。您可以使用流畅接口或使用关联数组传递到构造函数中设置这些属性。每个属性也可以有获取方法,以下是一个示例

// Using the fluent interface
$growthbook = Growthbook\Growthbook::create()
  ->withFeatures($features)
  ->withAttributes($attributes);

// Using the constructor
$growthbook = new Growthbook\Growthbook([
  'features' => $features,
  'attributes' => $attributes
]);

// Getter methods
print_r($growthbook->getFeatures());
print_r($growthbook->getAttributes());

注意:您还可以在任何时间点使用流畅方法(例如 withFeatures)来更新属性。

属性

您可以指定有关当前用户和请求的属性。这些用于以下两个方面

  1. 功能定位(例如,付费用户得到一个值,免费用户得到另一个值)
  2. 在 A/B 测试中分配持久性变体(例如,用户 id "123" 总是得到变体 B)

属性可以是任何 JSON 数据类型 - 布尔值、整数、浮点数、字符串或数组。

$attributes = [
  'id' => "123",
  'loggedIn' => true,
  'deviceId' => "abc123def456",
  'age' => 21,
  'tags' => ["tag1", "tag2"],
  'account' => [
    'age' => 90
  ]
];

如果您以后想更新属性,请注意,withAttributes 方法会完全覆盖属性对象。如果您只想更新部分字段,请使用 array_merge

// Only update the url attribute
$growthbook->withAttributes(array_merge(
  $growthbook->getAttributes(),
  [
    'url' => '/checkout'
  ]
));

跟踪实验

每当进行实验以确定某个特征值时,您都希望在自己的分析系统中跟踪该事件。

您可以通过回调函数来完成此操作

$trackingCallback = function (
  Growthbook\InlineExperiment $experiment, 
  Growthbook\ExperimentResult $result
) {  
  // Segment.io example
  Segment::track([
    "userId" => $userId,
    "event" => "Experiment Viewed",
    "properties" => [
      "experimentId" => $experiment->key,
      "variationId" => $result->key
    ]
  ]);
};

// Fluent interface
$growthbook = Growthbook\Growthbook::create()
  ->withTrackingCallback($callback);

// Using the constructor
$growthbook = new Growthbook([
  'trackingCallback' => $trackingCallback
]);

// Getter method
$trackingCallback = $growthbook->getTrackingCallback();

或者通过遍历数组在请求结束时跟踪所有事件

$impressions = $growthbook->getViewedExperiments();
foreach($impressions as $impression) {
  // Segment.io example
  Segment::track([
    "userId" => $userId,
    "event" => "Experiment Viewed",
    "properties" => [
      "experimentId" => $impression->experiment->key,
      "variationId" => $impression->result->key
    ]
  ]);
}

或者,您可以将展示传递到前端,并从那里触发分析事件。为此,只需在模板中添加一个块(此处以纯PHP展示,但类似思路适用于Twig、Blade等)。

<script>
<?php foreach($growthbook->getViewedExperiments() as $impression): ?>
  // tracking code goes here
<?php endforeach; ?>
</script>

以下是几个流行的前端跟踪库的示例

谷歌分析

ga('send', 'event', 'experiment', 
  "<?= $impression->experiment->key ?>", 
  "<?= $impression->result->variationId ?>", 
  {
    // Custom dimension for easier analysis
    'dimension1': "<?= 
      $impression->experiment->key.':'.$impression->result->key 
    ?>"
  }
);

Segment

analytics.track("Experiment Viewed", <?=json_encode([
  "experimentId" => $impression->experiment->key,
  "variationId" => $impression->result->key 
])?>);

Mixpanel

mixpanel.track("Experiment Viewed", <?=json_encode([
  'Experiment name' => $impression->experiment->key,
  'Variant name' => $impression->result->key 
])?>);

日志记录

GrowthBook可以将日志消息输出以帮助您调试功能标志和实验。

我们支持任何PSR-3兼容的记录器。我们实现了流畅的接口(withLogger)以及标准LoggerAware接口(setLogger)。

// Fluent interface
$growthbook
  ->withLogger($logger)
  ->with...;

// Setter
$growthbook->setLogger($logger);

使用功能

交互功能主要有三种方法。

  • $growthbook->isOn("feature-key")如果功能处于开启状态,则返回true
  • $growthbook->isOff("feature-key")如果功能处于开启状态,则返回false
  • $growthbook->getValue("feature-key", "default")返回功能的值,并提供默认值

此外,您还可以使用$growthbook->getFeature("feature-key")获取一个具有以下属性的FeatureResult对象

  • value - 特征的JSON解码值(如果没有定义则为null
  • onoff - 将JSON解码值转换为布尔值
  • source - 为什么要将值分配给用户。可以是unknownFeaturedefaultValueforceexperiment之一
  • experiment - 关于实验的信息(如果有的话),该实验用于将值分配给用户
  • experimentResult - 用于将值分配给用户的实验的结果(如果有的话)

内联实验

除了在代码中预先声明所有功能并按id引用它们之外,您还可以直接运行实验。这是通过$growthbook->runInlineExperiment方法完成的

$exp = Growthbook\InlineExperiment::create(
  "my-experiment", 
  ["red", "blue", "green"]
);

// Either "red", "blue", or "green"
echo $growthbook->runInlineExperiment($exp)->value; 

如您所见,实验需要两个必需参数:一个字符串键和一个变体数组。变体可以是任何数据类型,而不仅仅是字符串。

有一些额外的设置可以控制实验的行为。所有方法都是链式的。以下是一个显示所有可能设置的示例

$exp = Growthbook\InlineExperiment::create("my-experiment", ["red","blue"])
  // Run a 40/60 experiment instead of the default even split (50/50)
  ->withWeights([0.4, 0.6])
  // Only include 20% of users in the experiment
  ->withCoverage(0.2)
  // Targeting conditions using a MongoDB-like syntax
  ->withCondition([
    'country' => 'US',
    'browser' => [
      '$in' => ['chrome', 'firefox']
    ]
  ])
  // Use an alternate attribute for assigning variations (default is 'id')
  ->withHashAttribute("sessionId")
  // Namespaces are used to run mutually exclusive experiments
  // Another experiment in the "pricing" namespace with a non-overlapping range
  //   will be mutually exclusive (e.g. [0.5, 1])
  ->withNamespace("pricing", 0, 0.5);

内联实验返回值

runInlineExperiment的调用将返回一个具有一些有用属性的ExperimentResult对象

$result = $growthbook->runInlineExperiment($exp);

// If user is part of the experiment
echo($result->inExperiment); // true or false

// The index of the assigned variation
echo($result->variationId); // e.g. 0 or 1

// The key used to identify this variation when tracking the event
echo($result->key); // e.g. "control"

// The value of the assigned variation
echo($result->value); // e.g. "A" or "B"

// If the variations was randomly assigned based on a hash
echo($result->hashUsed); // true or false

// The user attribute that was hashed
echo($result->hashAttribute); // "id"

// The value of that attribute
echo($result->hashValue); // e.g. "123"

inExperiment标志将在用户因任何原因(例如,未通过定位条件)被排除在实验之外时为false。

hashUsed标志只有在用户被随机分配一个变体时才为true。如果用户被强制进入一个特定的变体,则此标志为false。