Skip to main content

Core Library Usage

Learn how to use the Toggly PHP SDK core library in vanilla PHP or custom frameworks.

Installation​

composer require toggly/feature-management-php

Basic Setup​

1. Create Settings​

use Toggly\FeatureManagement\Config\TogglySettings;

$settings = new TogglySettings([
'app_key' => 'your-app-key',
'environment' => 'Production',
'base_url' => 'https://definitions.toggly.io',
'use_signed_definitions' => true,
'refresh_interval' => 300, // 5 minutes
]);

2. Setup HTTP Client​

You need a PSR-18 HTTP client and PSR-17 HTTP factory. For example, with Guzzle:

use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use Toggly\FeatureManagement\Http\TogglyHttpClient;

$httpClient = new Client();
$requestFactory = new HttpFactory();
$togglyHttpClient = new TogglyHttpClient($httpClient, $requestFactory, $settings->getBaseUrl());

3. Initialize Services​

use Toggly\FeatureManagement\Core\FeatureStateService;
use Toggly\FeatureManagement\Core\FeatureProvider;
use Toggly\FeatureManagement\Core\UsageStatsProvider;
use Toggly\FeatureManagement\Core\FeatureManager;
use Toggly\FeatureManagement\Core\MetricsService;
use Toggly\FeatureManagement\Core\MetricsRegistryService;

// State service for notifications
$featureStateService = new FeatureStateService();

// Feature provider
$featureProvider = new FeatureProvider(
$settings,
$togglyHttpClient,
$featureStateService
);

// Usage stats provider
$usageStatsProvider = new UsageStatsProvider(
$settings,
$togglyHttpClient,
null, // context provider (optional)
null // logger (optional)
);

// Metrics service
$metricsRegistryService = new MetricsRegistryService();
$metricsService = new MetricsService(
$settings,
$togglyHttpClient,
$metricsRegistryService,
null // logger (optional)
);

// Feature manager
$featureManager = new FeatureManager(
$featureProvider,
$usageStatsProvider,
$featureProvider, // secure provider (same instance)
null, // authorization service (optional)
null // logger (optional)
);

4. Use Feature Manager​

if ($featureManager->isEnabled('my-feature')) {
// Feature is enabled
echo "Feature is on!";
} else {
// Feature is disabled
echo "Feature is off!";
}

Filter parity (segments + UserClaims)​

Core FeatureManager evaluates shared catalog filters locally, including HTTP segments and UserClaims. Supply context on each check:

use Toggly\FeatureManagement\Core\HttpRequestMapper;

$context = [
'identity' => $userId,
'groups' => ['beta'],
'claims' => ['role' => 'admin'], // UserClaims — from auth, not headers
'request' => [
'userAgent' => $_SERVER['HTTP_USER_AGENT'] ?? null,
'acceptLanguage' => $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? null,
'country' => 'US',
],
];

// Or map headers (cf-ipcountry / x-vercel-ip-country / cloudfront-viewer-country):
$context = HttpRequestMapper::mergeIntoContext($headers, [
'identity' => $userId,
'claims' => ['role' => $roleFromAuth],
]);

$enabled = $featureManager->isEnabled('MobileCheckout', $context);

Built-in names include AlwaysOn / AlwaysOff, Percentage, TimeWindow, Targeting, BrowserFamily, BrowserLanguage, Country / CountryFamily, DeviceType, OS / OperatingSystem, and UserClaims. Unknown filters and missing segment Percentage fail closed.

Laravel classes under Toggly\Laravel\Filters\ are legacy — core evaluation is the path above. Matrix: SDK × filter matrix.

Context Provider​

Provide user context for targeting and rollouts:

use Toggly\FeatureManagement\Contracts\FeatureContextProviderInterface;

class MyContextProvider implements FeatureContextProviderInterface
{
public function getContextIdentifier(): ?string
{
return $_SESSION['user_id'] ?? null;
}

public function getContextIdentifierWithContext($context): ?string
{
if (is_array($context) && isset($context['identity'])) {
return (string) $context['identity'];
}

return $this->getContextIdentifier();
}

public function accessedInRequest(string $featureName): bool
{
$key = 'toggly_accessed_' . $featureName;
if (!empty($_SESSION[$key])) {
return true;
}
$_SESSION[$key] = true;
return false;
}

public function accessedInRequestWithContext(string $featureName, $context): bool
{
return $this->accessedInRequest($featureName);
}
}

// Use in UsageStatsProvider
$contextProvider = new MyContextProvider();
$usageStatsProvider = new UsageStatsProvider(
$settings,
$togglyHttpClient,
$contextProvider
);

Snapshot Providers​

Use snapshot providers for offline support and persistence:

Cache Provider (PSR-16)​

use Toggly\FeatureManagement\Storage\SnapshotProviders\CacheSnapshotProvider;
use Toggly\FeatureManagement\Storage\SnapshotSettings;

$cache = /* your PSR-16 cache implementation */;
$snapshotProvider = new CacheSnapshotProvider(
$cache,
new SnapshotSettings(['document_name' => 'toggly_features']),
86400
);

// Set on feature provider
$featureProvider->setSnapshotProvider($snapshotProvider);

Database Provider (PDO)​

use Toggly\FeatureManagement\Storage\SnapshotProviders\DatabaseSnapshotProvider;
use Toggly\FeatureManagement\Storage\SnapshotSettings;

$pdo = new PDO('mysql:host=localhost;dbname=toggly', $user, $pass);
$snapshotProvider = new DatabaseSnapshotProvider(
$pdo,
new SnapshotSettings(['document_name' => 'toggly_features'])
);
// Tables are created automatically in the constructor.

// Set on feature provider
$featureProvider->setSnapshotProvider($snapshotProvider);

File Provider​

use Toggly\FeatureManagement\Storage\SnapshotProviders\FileSnapshotProvider;
use Toggly\FeatureManagement\Storage\SnapshotSettings;

$snapshotProvider = new FileSnapshotProvider(
'/path/to/snapshots',
new SnapshotSettings(['document_name' => 'toggly_features'])
);

// Set on feature provider
$featureProvider->setSnapshotProvider($snapshotProvider);

State Change Notifications​

Register callbacks for feature state changes:

$featureStateService->whenFeatureTurnsOn('my-feature', function () {
error_log('My feature was enabled!');
// Send notification, update cache, etc.
});

$featureStateService->whenFeatureTurnsOff('my-feature', function () {
error_log('My feature was disabled!');
// Cleanup, notify users, etc.
});

// Listen for any definition changes
$featureStateService->whenDefinitionsChange(function (array $changedFeatures) {
foreach ($changedFeatures as $featureName) {
error_log("Feature {$featureName} changed");
}
});

Usage Statistics​

Usage statistics are automatically collected when using FeatureManager. To send them:

// Send collected stats
$usageStatsProvider->sendStats();

Stats include:

  • Feature enabled/disabled checks
  • Unique users per feature
  • Actual usage tracking

Custom Metrics​

Record custom metrics for experiments:

// Record a measurement (aggregated over time)
$metricsService->measure('checkout-time', 2.5);

// Record an observation (point-in-time)
$metricsService->observe('button-click', 1);

// Increment a counter
$metricsService->incrementCounter('page-views', 1);

// Send metrics
$metricsService->sendMetrics();

Secure Features​

For secure features, implement an authorization service:

use Toggly\FeatureManagement\Contracts\FeatureAuthorizationServiceInterface;

class MyAuthorizationService implements FeatureAuthorizationServiceInterface
{
public function isAuthorized(string $featureName, ?array $context = null): bool
{
// Check if user has permission for this feature
$user = $context['user'] ?? null;
if (!$user) {
return false;
}

// Example: Check user role
return in_array('admin', $user['roles'] ?? []);
}
}

// Use in FeatureManager
$authService = new MyAuthorizationService();
$featureManager = new FeatureManager(
$featureProvider,
$usageStatsProvider,
$featureProvider,
$authService
);

Refreshing Features​

Manually refresh feature definitions:

// Refresh from API
$featureProvider->refreshFeatures();

// Or let it auto-refresh based on refresh_interval

Error Handling​

The SDK handles errors gracefully:

  • Network errors: Falls back to cached/snapshot values
  • Invalid responses: Uses cached values
  • Signature verification failures: Logs error and uses unsigned definitions (if configured)

Always check logs for errors:

use Psr\Log\LoggerInterface;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('toggly');
$logger->pushHandler(new StreamHandler('toggly.log', Logger::WARNING));

// Pass logger to services
$featureProvider = new FeatureProvider(
$settings,
$togglyHttpClient,
$featureStateService,
null, // snapshot provider
null, // websocket client
$logger
);

Best Practices​

  1. Initialize Once: Create services once and reuse them
  2. Use Snapshot Providers: For offline support and persistence
  3. Handle Errors: Always provide fallback behavior
  4. Monitor Logs: Check logs for errors and warnings
  5. Refresh Periodically: Set up a cron job or scheduled task to refresh features
  6. Send Stats/Metrics: Regularly send usage stats and metrics
  7. Use Context: Provide user context for accurate targeting