Download the PHP package guidelytech/guidely-php without Composer
On this page you can find all versions of the php package guidelytech/guidely-php. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download guidelytech/guidely-php
More information about guidelytech/guidely-php
Files in guidelytech/guidely-php
Package guidely-php
Short Description Guidely feature flags and experiments for PHP: local evaluation, caching, sticky bucketing, remote evaluation and encrypted payloads.
License MIT
Homepage https://guidelytech.com
Informations about the package guidely-php
Guidely feature flags for PHP
guidelytech/guidely-php evaluates Guidely feature flags and experiments
inside your PHP application. Rules are evaluated locally, so a flag check costs no network round
trip. The payload is cached between requests and revalidated in the background of the next read.
- Feature flags, percentage rollouts, scheduled ramps, percentage options and A/B experiments
- Targeting by attributes, segments, prerequisites, flag conditions and holdouts
- Sticky bucketing, namespaces and bucket versions for experiments
- File, APCu, in-memory and any PSR-16 (Redis, Memcached, Laravel, Symfony) payload cache
- Encrypted payloads, remote evaluation, local overrides for tests and environment-variable overrides for CI
- Usage counters and experiment exposures reported to Guidely
Requirements: PHP 8.1 or later (64-bit) with ext-json, ext-mbstring and ext-hash.
ext-openssl is needed only for encrypted payloads, and ext-curl is used when it is installed
(otherwise PHP streams).
Install
Quick start
Every environment has a public key (pk_…), the same key the Guidely browser SDK uses for
tracking. It is all most servers need:
Getters never throw. When a flag is missing, disabled for everyone without a value, of the wrong
type, or the payload cannot be loaded, you get your fallback and the problem is reported through
onError (or your logger, or error_log when neither is configured).
With a server key
A secret API key (gly_sk_…, scope flags:read) sees the full payload, including server-only
flags and environments that hide their rules from public keys. Secret keys are tied to a project, so
name the environment:
Never ship a secret key to a browser or a mobile app.
Reading flags
| Method | Returns |
|---|---|
isEnabled($key, $attributes = [], $fallback = false) |
bool: the flag's boolean value, else $fallback |
getValue($key, $fallback = null, $attributes = []) |
the raw value, $fallback when it is null |
getString / getNumber / getBool / getJson($key, $fallback, $attributes) |
the value when it has that JSON type, else $fallback |
getDetails($key, $fallback = null, $attributes = []) |
EvaluationResult (value, reason, ruleId, variationId, inExperiment, experiment, errorMessage) |
getAll($attributes = []) |
array<string, EvaluationResult> for every flag (no usage counting or exposures) |
forUser($attributes) |
a UserContext with the same getters, minus the attributes argument |
Attributes are a JSON-like array. Nested values are addressed with dot paths in the dashboard
(account.plan). Dates can be DateTimeInterface objects, ISO 8601 strings or Unix seconds.
JSON objects come back from getJson() as associative arrays; because PHP cannot tell [] from
{}, an empty JSON object is returned as stdClass (pass new stdClass() as an attribute when you
mean an empty object).
Frameworks
Laravel
Symfony
Inject GuidelyFlags into controllers and services as usual.
Caching and freshness
PHP processes are short-lived, so the client loads lazily:
- On the first flag read it takes the payload from the cache.
- When the cached copy is older than
cacheTtlSeconds(default 60), it revalidates it withIf-None-Match; a304just refreshes the timestamp, so polling costs almost nothing. - If the API cannot be reached, the stale payload keeps serving and every worker retries after
another
cacheTtlSeconds. refresh()forces a fetch; a long-running worker (Swoole, RoadRunner, queue consumers) revalidates by itself once its copy is older than the TTL.
Pick the cache that matches your hosting:
| Cache | When |
|---|---|
FileCache (default) |
Zero setup. JSON files in sys_get_temp_dir()/guidely-flags-<uid>, written atomically. |
ApcuCache |
One host with PHP-FPM: shared memory, the fastest option. Needs ext-apcu. |
| any PSR-16 cache | Several hosts or containers: Redis, Memcached, Laravel's Cache::store(), Symfony's Psr16Cache. Passed objects are detected by their get / set methods; psr/simple-cache is not required. |
InMemoryCache / 'cache' => false |
Tests, or when every process may fetch its own copy. |
Your own storage only needs GuidelyTech\Flags\Cache\CacheInterface (get($key) and
set($key, $value, $ttlSeconds)).
Options
| Option | Default | Meaning |
|---|---|---|
sdkKey (alias projectId) |
— | pk_… public key or gly_sk_… secret key. Without one the SDK only serves payload / overrides. |
environment |
— | development, staging or production. Required with a gly_sk_ key. |
apiUrl |
https://guidelytech.com |
API origin (self-hosted / testing). |
cacheTtlSeconds |
60 |
Age after which the cached payload is revalidated. |
cache |
FileCache |
A CacheInterface, any PSR-16 cache, or false for memory only. |
payload |
— | Bootstrap payload (array or JSON string). It is served as-is and nothing is fetched until refresh(). |
decryptionKey |
— | The environment's decryption key, for encrypted payloads. |
overrides |
[] |
Flag key ⇒ value. |
overrideBehaviour |
localOverRemote |
localOnly (never fetch), localOverRemote (override wins), remoteOverLocal (override only for flags missing remotely). String or OverrideBehaviour enum. |
devOverrides |
true |
Read dev overrides from GUIDELY_FLAG_OVERRIDES* environment variables. |
defaultAttributes |
[] |
Attributes merged under every call's attributes. |
stickyBucketService |
— | A StickyBucketServiceInterface to keep users in their experiment variation. |
trackingCallback |
— | fn (array $experiment, EvaluationResult $result), called once per experiment, user and variation. |
onFlagEvaluated |
— | fn (EvaluationResult $result) after every getter call. |
onError |
— | fn (Throwable $error) for network, cache, decryption and callback errors. |
logger |
— | A PSR-3 logger (anything with error($message, $context); warning() is used when present). |
reportUsage |
true |
Send per-flag evaluation counts to Guidely. |
reportExposures |
true |
Send experiment exposures to Guidely. |
timeoutSeconds |
5 |
HTTP timeout. |
httpClient |
cURL / streams | A GuidelyTech\Flags\Http\HttpClientInterface (e.g. to wrap Guzzle, or a fake in tests). |
offline |
false |
No network at all; the cached payload keeps serving. Also setOffline(). |
remoteEval |
false |
Let Guidely evaluate (see below). |
clock |
microtime(true) |
fn (): float current Unix time, for tests. |
Options can also be built as an object: new GuidelyFlags(new Options(sdkKey: 'pk_…', cacheTtlSeconds: 30)).
Unknown option names throw an InvalidArgumentException so typos surface immediately.
Experiments
An experiment rule assigns each user a variation deterministically from their hash attribute (id
by default). Read the flag as usual; the result says whether the user is in the experiment:
Exposures are also sent to Guidely (reportExposures), so the dashboard shows results without
extra work. Read experiment flags with the getters rather than getAll(), which records nothing.
Sticky bucketing keeps users in their variation when you change weights or coverage. Implement
StickyBucketServiceInterface on your database or Redis (documents keyed "id||u_123", mapping
"<experiment>__<bucketVersion>" to a variation id), or use InMemoryStickyBucketService in
long-running workers:
Overrides in tests
Overridden flags report reason OVERRIDE and are not counted in usage. Overrides apply to the flag
you read; prerequisites and flag conditions of other flags still use the payload's values. To test
against real rules without the network, pass a payload exported from the dashboard as payload.
A localOnly client makes no requests at all and never reads a payload cached by an earlier run, so
tests are hermetic.
Dev overrides (CI)
CI and test runs can pin flags without changing the app. The client reads these environment
variables once, when it is created (getenv(), then $_ENV, then $_SERVER):
| Variable | Holds |
|---|---|
GUIDELY_FLAG_OVERRIDES |
key:value items separated by commas or newlines (new-checkout:true,limit:5,theme:"dark"; values are JSON when they parse, text otherwise), or a JSON object ({"new-checkout": true}) |
GUIDELY_FLAG_OVERRIDES_FILE |
the path of a UTF-8 file holding the same text |
GUIDELY_FLAG_OVERRIDE_BEHAVIOUR |
localOnly, localOverRemote or remoteOverLocal; replaces overrideBehaviour |
A sample overrides file is in Testing with flags in CI.
Per flag, the environment variable wins over the file, which wins over the overrides option;
setOverrides() replaces only the option's values. When any variable is in use the client logs one
warning naming it, so a variable left set in production is visible. A malformed value, an unreadable
file or an unknown behaviour is reported through onError / the logger and ignored. Pass
'devOverrides' => false to ignore all three variables.
Remote evaluation
When an environment's exposure mode is remote, public keys cannot download its rules
(GET /flags answers 403 remote_evaluation_required, reported as a
RemoteEvaluationRequiredException). On a server, prefer a gly_sk_ key and keep evaluating
locally. Otherwise let Guidely evaluate:
Results are fetched once per distinct attribute set and reused for the rest of the client's life
(call refresh() to drop them).
Encrypted payloads
With encryption on, the payload is AES-256-GCM encrypted. Pass the environment's decryption key from the dashboard:
The cache stores the payload still encrypted. A missing or wrong key is reported through onError
and the previous payload keeps serving. Requires ext-openssl.
Usage reporting
Unless reportUsage is off, the SDK counts evaluations per flag and served variation / value, and
sends them with any experiment exposures to POST /api/v1/sdk/flags/events: at the end of the
request (shutdown function and destructor), after 60 seconds of activity in long-running
processes, or when you call flush(). Overridden flags are not counted, and a localOnly client
sends nothing.
Evaluating without the client
GuidelyTech\Flags\Evaluator is the pure evaluation engine shared by every Guidely SDK, if you
manage the payload yourself:
Development
The evaluator follows docs/feature-flags-spec.md and passes the shared conformance vectors in
sdks/conformance/flag-vectors.json.
Without a local PHP, run the suite in Docker from the repository root. The image in
docker/ is the official CLI image plus Composer and ext-apcu enabled on the
CLI, so the ApcuCache tests run too (on other images they are skipped):
Repeat with PHP_VERSION=8.3 to cover the newest supported release. The suite mounts all of
sdks/ because it reads the shared vectors in sdks/conformance.
Releasing
Packagist only reads a composer.json at a repository root, so this directory is mirrored to
github.com/GuidelyTech/guidely-php, which is the repository
registered on Packagist. Develop here; the mirror is distribution only (.gitattributes keeps
tests/ and docker/ out of installs, and the conformance vectors stay in this monorepo).
One-time setup:
- Create the empty public repository
GuidelyTech/guidely-php. -
Create a deploy key, add the public half to that repository (Settings → Deploy keys, allow write access) and the private half to this repository as the secret
PHP_SDK_DEPLOY_KEY: - Run the first release (below), then submit
https://github.com/GuidelyTech/guidely-phpat packagist.org/packages/submit and enable its GitHub hook so later tags appear automatically.
Each release: Actions → Release PHP SDK → Run workflow with the version (e.g. 0.1.0). It is a
dry run by default — tests, splits sdks/php and lists the files users would get, pushing
nothing. Untick dry run (from main) to push the split to the mirror's main, tag it v<version>
there and tag this repository php-sdk-v<version>. Versions are permanent on Packagist, so the
workflow refuses one the mirror already has.
License
MIT
All versions of guidely-php with dependencies
ext-hash Version *
ext-json Version *
ext-mbstring Version *