PHP
The Shipeasy PHP server SDK — PHP-FPM friendly per-request init, local evaluation, configs, experiments, and tracking.
Server-side flags, configs, experiments, and tracking for PHP. PHP-FPM friendly — init() fetches once per request, no background thread. Evaluates locally against the fetched blob — see the shared evaluation model.
Install
composer require shipeasy/sdkConfigure
Call Shipeasy\configure() once with the server key, plus an optional attributes transform that maps your user object onto the Shipeasy attribute map. Under PHP-FPM this fetches once per request; for long-running runtimes (Swoole, RoadRunner, queue workers) refresh it from a periodic task.
Shipeasy\configure(
getenv('SHIPEASY_SERVER_KEY'),
fn($u) => ['user_id' => $u->id, 'plan' => $u->plan],
);Bind a client to the user
Construct a lightweight Shipeasy\Client from your user object — the attributes transform turns it into the evaluation context, so the getters take no user argument:
$flags = new Shipeasy\Client($currentUser);Evaluate a feature flag
$enabled = $flags->getFlag('new_checkout');An optional default is returned only when the gate can't be evaluated (client not ready or gate absent) — a gate that evaluates falsy returns false:
$flags->getFlag('new_checkout', true);For the value plus the reason, use getFlagDetail — see Evaluation reasons:
$d = $flags->getFlagDetail('new_checkout');
$d->value; // bool
$d->reason; // e.g. FlagDetail::RULE_MATCHRead a dynamic config
$cfg = $flags->getConfig('billing_copy', ['headline' => 'Welcome']);Resolve an experiment
$r = $flags->getExperiment('checkout_button', ['color' => 'blue']);
if ($r->inExperiment) {
$r->group; // 'treatment'
$r->params; // ['color' => ...]
}Track an event
$flags->track('purchase', ['amount' => 49]);Anonymous visitors
Call Identity::ensure() once early in your bootstrap (before any output) to read or mint the shared __se_anon_id cookie, so logged-out traffic buckets like the browser:
use Shipeasy\Identity;
Identity::ensure();
(new Shipeasy\Client($anonUser))->getFlag('new_checkout'); // buckets on the cookieWorks in plain PHP, WordPress, Laravel, Symfony, and Slim — anywhere $_COOKIE / setcookie() exist.
Testing
Engine::forTesting() does zero network — no key, init/track are no-ops. Seed with override* and reset with clearOverrides. See Testing.
$engine = Shipeasy\Engine::forTesting();
$engine->overrideFlag('new_checkout', true);
$engine->getFlag('new_checkout', ['user_id' => 'u1']); // true
$engine->clearOverrides();Errors & feedback
Report a handled exception with see() so it folds into the errors primitive with a one-sentence consequence — what feature broke and how it degraded. see() rides the same Shipeasy\configure() boot (server key); there is no separate error SDK or second key.
try {
chargeCard($order, $prices);
} catch (\Throwable $e) {
Shipeasy\see($e)->causesThe('checkout')->to('use cached prices')->extras(['order_id' => $order->id]);
}Use Shipeasy\seeViolation('large query') for a non-exception problem. Full grammar — consequence phrasing, control-flow exceptions, anti-patterns — is in Error reporting with see().
The in-app bug & feature report overlay is a standalone <script> tag you drop into your frontend — platform-agnostic, no server SDK required. See The devtools overlay.