Shipeasy

PHP

The Shipeasy PHP server SDK — PHP-FPM friendly per-request init, local evaluation, configs, experiments, and tracking.

Production readyOn this page · 4 min readUpdated · June 18, 2026Works with · PHP 8.1+ · Laravel · WordPress · Symfony

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/sdk

Configure

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_MATCH

Read 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 cookie

Works 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.

Was this page helpful?
✎ Edit this page

On this page