Segments Manager

PHP-specific segments handling

ConvertSdk\SegmentsManager is the PHP SDK's implementation of visitor segmentation: it evaluates custom segment rules, filters reporting segments, and persists both through the DataManager so they ride along on tracking payloads.

For the cross-SDK concepts — what a segment is, how it differs from an audience, and when to use each — read Segments first. This page covers the PHP surface: exact signatures, return types, and the stored shape.

Public API

You normally reach the manager through the visitor context rather than directly — see Code Examples → Segments.

Context methodDelegates toReturns
setDefaultSegments(array $segments)putSegments()void
runCustomSegments(array $segmentKeys, ?array $attributes = null)selectCustomSegments()?array — the visitor's custom-segment ids, or null
setCustomSegments(array $segmentKeys, ?array $attributes = null)runCustomSegments()Same — deprecated alias

The manager itself exposes:

namespace ConvertSdk;

class SegmentsManager implements SegmentsManagerInterface
{
    public function __construct(
        Config $config,
        DataManagerInterface $dataManager,
        RuleManagerInterface $ruleManager,
        ?LogManagerInterface $loggerManager = null,
    );

    public function getSegments(string $visitorId): VisitorSegments;

    public function putSegments(string $visitorId, ?array $segments): void;

    public function selectCustomSegments(
        string $visitorId,
        array $segmentKeys,
        ?array $segmentRule = null,
    ): VisitorSegments|RuleError|null;

    public function selectCustomSegmentsByIds(
        string $visitorId,
        array $segmentIds,
        ?array $segmentRule = null,
    ): VisitorSegments|RuleError|null;
}

selectCustomSegments() resolves the segment definitions by key; selectCustomSegmentsByIds() resolves them by id. Both then run the same private matching routine.

Default (reporting) segments

Default segments are the standard dimensions that appear in Convert reports.

$context = $sdk->createContext('user123', ['country' => 'US']);

$context->setDefaultSegments([
    'country'  => 'US',
    'browser'  => 'chrome',
    'devices'  => 'desktop',
    'source'   => 'organic',
]);

Only these keys are recognised — they are the cases of the SegmentsKeys enum:

browser, devices, source, campaign, visitorType, country, plus customSegments for the rule-matched set.

setDefaultSegments() runs its argument through DataManager::filterReportSegments(), which splits the array into recognised segment keys and everything else. Only the recognised keys are persisted — any other key passed here is dropped, and nothing is written at all when none match. (The same filter runs on createContext()'s attributes, but there the unrecognised keys are kept as visitor properties for targeting.)

visitorType and customSegments are camelCase. Earlier releases stored them as visitor_type and custom_segments; the keys were renamed to match the JavaScript SDK and the served config, so a visitor record written by an older SDK version will not have its custom segments read back.

Custom segments

Custom segments are matched by rules rather than assigned directly.

$matched = $context->runCustomSegments(
    ['premium-users', 'high-value'],
    ['ruleData' => ['plan' => 'enterprise', 'lifetime_value' => 5000]]
);

The rule data goes under a ruleData key — Context::runCustomSegments() reads $attributes['ruleData'], deep-merges it over the visitor's in-memory properties and stored segments, and passes the result to the manager as $segmentRule. A flat array of properties at the top level is ignored.

Returns the visitor's accumulated custom-segment ids as a plain array, or null when nothing new matched. A RuleError from rule evaluation is swallowed at the Context boundary and surfaces as null — call SegmentsManager::selectCustomSegments() directly if you need to distinguish the two.

How matching works

For each resolved segment definition, in order:

  1. If a $segmentRule was supplied and nothing has matched yet, the segment's own rules tree is evaluated against it via RuleManager::isRuleMatched(). A RuleError short-circuits the whole call and is returned immediately.
  2. A segment is accepted when there is no $segmentRule at all, or once a match has been found. Once one segment matches, the remaining segments in the same call are accepted without evaluating their own rules — pass one key per call if you need each rule tree evaluated independently.
  3. Ids already present in the visitor's stored customSegments are skipped, with a warning logged.

Newly accepted ids are appended to the stored set and persisted; the method returns a VisitorSegments built from the merged data, or null when nothing was added.

Stored shape

Segments live inside the visitor's record in the data store, alongside bucketing decisions:

[
    'segments' => [
        'country'        => 'US',
        'browser'        => 'chrome',
        'devices'        => 'desktop',
        'visitorType'    => 'new',
        'customSegments' => ['1001', '1002'],  // segment ids, as strings
    ],
    'bucketing' => [ /* experienceId => variationId */ ],
]

getSegments() reads that record, re-filters it through filterReportSegments(), and returns a VisitorSegments. putSegments() applies the same filter on write, so an unrecognised key can never enter the store through this path.

Because the PSR-16 cache doubles as the data store, segments persist across requests exactly as far as that cache does — in-memory ArrayCache means per-request only. See Configuration → Persistent DataStore.

Next Steps


Did this page help you?