Helpers - evansims/openfga-php GitHub Wiki
The OpenFGA PHP SDK provides a collection of helper functions that dramatically simplify common authorization operations. These helpers reduce boilerplate code and make your authorization logic more readable and maintainable.
All examples in this guide assume the following setup:
<?php
declare(strict_types=1);
use OpenFGA\Client;
require_once __DIR__ . '/vendor/autoload.php';
$client = new Client(
url: $_ENV['FGA_API_URL'] ?? 'http://localhost:8080',
);
The tuple()
helper simplifies creating relationship tuples:
Helper usage:
use function OpenFGA\tuple;
$tuple = tuple(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
);
Standard long-form:
use OpenFGA\Models\TupleKey;
$tuple = new TupleKey(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
);
With conditions:
Helper usage:
use OpenFGA\Models\Condition;
use function OpenFGA\tuple;
$tuple = tuple(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
condition: new Condition(name: 'in_office_hours', expression: /* ... */),
);
Standard long-form:
use OpenFGA\Models\{Condition, TupleKey};
$tuple = new TupleKey(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
condition: new Condition(name: 'in_office_hours', expression: /* ... */),
);
The tuples()
helper creates collections for batch operations:
Helper usage:
use function OpenFGA\{tuple, tuples};
$tupleCollection = tuples(
tuple(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
),
tuple(
user: 'user:bob',
relation: 'editor',
object: 'document:budget',
),
tuple(
user: 'user:charlie',
relation: 'owner',
object: 'document:budget',
),
);
Standard long-form:
use OpenFGA\Models\TupleKey;
use OpenFGA\Models\Collections\TupleKeys;
$tupleCollection = new TupleKeys([
new TupleKey(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
),
new TupleKey(
user: 'user:bob',
relation: 'editor',
object: 'document:budget',
),
new TupleKey(
user: 'user:charlie',
relation: 'owner',
object: 'document:budget',
),
]);
The check()
helper creates BatchCheckItem instances for batch authorization checks. If no correlation ID is provided, one is automatically generated based on the tuple key:
Helper usage (with auto-generated correlation ID):
use function OpenFGA\{check, tuple};
$checkItem = check(
tupleKey: tuple(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
)
);
Helper usage (with explicit correlation ID):
use function OpenFGA\{check, tuple};
$checkItem = check(
tupleKey: tuple(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
),
correlation: 'anne-budget-check'
);
Standard long-form:
use OpenFGA\Models\{BatchCheckItem, TupleKey};
$checkItem = new BatchCheckItem(
tupleKey: new TupleKey(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
),
correlationId: 'anne-budget-check'
);
With context and contextual tuples:
use function OpenFGA\{check, tuple, tuples};
$checkItem = check(
tupleKey: tuple(
user: 'user:bob',
relation: 'editor',
object: 'document:budget',
),
correlation: 'bob-budget-edit',
contextualTuples: tuples(
tuple(
user: 'user:bob',
relation: 'member',
object: 'team:finance',
)
),
context: (object)['time' => '10:00', 'department' => 'finance']
);
Standard long-form (with context and contextual tuples):
use OpenFGA\Models\{BatchCheckItem, TupleKey, TupleKeys};
$checkItem = new BatchCheckItem(
tupleKey: new TupleKey(
user: 'user:bob',
relation: 'editor',
object: 'document:budget',
),
correlationId: 'bob-budget-edit',
contextualTuples: new TupleKeys([
new TupleKey(
user: 'user:bob',
relation: 'member',
object: 'team:finance',
)
]),
context: (object)['time' => '10:00', 'department' => 'finance']
);
The store()
helper creates a store and returns its ID directly:
Helper usage:
use function OpenFGA\store;
$storeId = store(
name: 'my-application',
client: $client,
);
Standard long-form:
$response = $client->createStore(name: 'my-application')->unwrap();
$storeId = $response->getId();
The dsl()
helper parses DSL strings into authorization models:
Helper usage:
use function OpenFGA\dsl;
$model = dsl(
client: $client,
dsl: '
model
schema 1.1
type user
type document
relations
define viewer: [user]
define editor: [user]
define owner: [user]
',
);
Standard long-form:
$model = $client->dsl('
model
schema 1.1
type user
type document
relations
define viewer: [user]
define editor: [user]
define owner: [user]
')->unwrap();
The model()
helper creates an authorization model and returns its ID:
Helper usage:
use function OpenFGA\model;
$modelId = model(
model: $model,
client: $client,
store: $storeId,
);
Standard long-form:
$response = $client->createAuthorizationModel(
store: $storeId,
typeDefinitions: $authModel->getTypeDefinitions(),
conditions: $authModel->getConditions(),
schemaVersion: $authModel->getSchemaVersion()
)->unwrap();
$modelId = $response->getModel();
The write()
helper provides the simplest way to write tuples:
Helper usage (single tuple):
use function OpenFGA\{tuple, tuples, write};
write(
client: $client,
store: $storeId,
model: $modelId,
tuples: tuples(
tuple(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
),
),
);
Standard long-form (single tuple):
use OpenFGA\Models\{TupleKey, TupleKeys};
$client->writeTuples(
store: $storeId,
model: $modelId,
writes: new TupleKeys(
new TupleKey(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
)
),
transactional: true
)->unwrap();
Helper usage (multiple tuples):
use function OpenFGA\{tuple, tuples, write};
write(
client: $client,
store: $storeId,
model: $modelId,
tuples: tuples(
tuple(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
),
tuple(
user: 'user:bob',
relation: 'editor',
object: 'document:forecast',
),
),
);
Standard long-form (multiple tuples):
use OpenFGA\Models\{TupleKey, TupleKeys};
$client->writeTuples(
store: $storeId,
model: $modelId,
writes: new TupleKeys([
new TupleKey(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
),
new TupleKey(
user: 'user:bob',
relation: 'editor',
object: 'document:forecast',
),
]),
transactional: true
)->unwrap();
Non-transactional mode:
// Helper - allows partial success
write(
client: $client,
store: $storeId,
model: $modelId,
tuples: $tuples,
transactional: false,
);
// Standard - allows partial success
$client->writeTuples(
store: $storeId,
model: $modelId,
writes: $tuples,
transactional: false
)->unwrap();
The delete()
helper simplifies tuple deletion:
Helper usage:
use function OpenFGA\{tuple, delete};
delete(
client: $client,
store: $storeId,
model: $modelId,
tuple: tuple(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
),
);
Standard long-form:
use OpenFGA\Models\{TupleKey, TupleKeys};
$client->writeTuples(
store: $storeId,
model: $modelId,
deletes: new TupleKeys(
new TupleKey(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
),
),
transactional: true
)->unwrap();
The allowed()
helper returns a boolean directly with guaranteed error-safe behavior:
Helper usage:
use function OpenFGA\{tuple, allowed};
// Returns true only if explicitly allowed, false for denied or any error
if (allowed(
client: $client,
store: $storeId,
model: $modelId,
tuple: tuple(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
),
)) {
// User has access
}
// Safe to use even with network issues, invalid stores, etc.
$canRead = allowed(
client: $client,
store: $storeId,
model: $modelId,
tuple: tuple(
user: 'user:anne',
relation: 'reader',
object: 'document:budget',
),
);
$canEdit = allowed(
client: $client,
store: $storeId,
model: $modelId,
tuple: tuple(
user: 'user:anne',
relation: 'editor',
object: 'document:budget',
),
);
// Both will return false if there are any errors (network, auth, validation, etc.)
Standard long-form:
use OpenFGA\Models\TupleKey;
// Standard approach requires explicit error handling
try {
$response = $client->check(
store: $storeId,
model: $modelId,
tupleKey: new TupleKey(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
)
)->unwrap();
if ($response->getAllowed()) {
// User has access
}
} catch (Throwable $error) {
// Handle network issues, authentication failures, etc.
// Must decide what to do with errors
}
With advanced options:
use function OpenFGA\{tuple, allowed};
// Helper with all options - still error-safe
$hasAccess = allowed(
$client,
$storeId,
$modelId,
tuple('user:anne', 'viewer', 'document:budget'),
trace: true,
context: (object)['time' => '2024-01-15T10:00:00Z'],
contextualTuples: tuples(
tuple(
user: 'user:anne',
relation: 'member',
object: 'team:engineering',
)
),
consistency: Consistency::FULL
);
// Returns false for any error, true only if explicitly allowed
use OpenFGA\Models\{TupleKey, TupleKeys};
// Standard long-form - requires error handling
try {
$response = $client->check(
store: $storeId,
model: $modelId,
tupleKey: new TupleKey(
user: 'user:anne',
relation: 'viewer',
object: 'document:budget',
),
trace: true,
context: (object)['time' => '2024-01-15T10:00:00Z'],
contextualTuples: new TupleKeys(
new TupleKey(
user: 'user:anne',
relation: 'member',
object: 'team:engineering',
)
),
consistency: Consistency::FULL
)->unwrap();
$hasAccess = $response->getAllowed();
} catch (Throwable $error) {
// Handle errors explicitly
$hasAccess = false; // or throw, or log, etc.
}
The objects()
helper simplifies finding all objects a user has access to with guaranteed error-safe behavior:
Helper usage:
use function OpenFGA\objects;
// Find all documents Anne can view - returns empty array on any error
$documents = objects(
client: $client,
store: $storeId,
model: $modelId,
type: 'document',
relation: 'viewer',
user: 'user:anne',
);
// Returns: ['document:budget', 'document:forecast', 'document:report'] or [] on error
// Find all folders Bob owns - safe to use even with network issues
$folders = objects(
client: $client,
store: $storeId,
model: $modelId,
type: 'folder',
relation: 'owner',
user: 'user:bob',
);
// Returns: ['folder:shared', 'folder:personal'] or [] on error
// Safe to use even with invalid stores, authentication failures, etc.
$userDocs = objects(
client: $client,
store: $invalidStore,
model: $modelId,
type: 'document',
relation: 'viewer',
user: 'user:anne',
);
// Will return [] instead of throwing an exception
Standard long-form:
$documents = [];
// Standard approach requires explicit error handling
try {
$generator = $client->streamedListObjects(
store: $storeId,
model: $modelId,
type: 'document',
relation: 'viewer',
user: 'user:anne'
)->unwrap();
foreach ($generator as $streamedResponse) {
$documents[] = $streamedResponse->getObject();
}
} catch (Throwable $error) {
// Handle network issues, authentication failures, etc.
}
With advanced options:
use function OpenFGA\{objects, tuple, tuples};
// Helper with contextual tuples and consistency - still error-safe
$accessibleDocs = objects(
$client,
$storeId,
$modelId,
'document',
'viewer',
'user:anne',
context: (object)['department' => 'engineering'],
contextualTuples: tuples(
tuple(
user: 'user:anne',
relation: 'member',
object: 'team:engineering',
)
),
consistency: Consistency::HIGHER_CONSISTENCY
);
// Returns array of accessible documents or [] on any error
use OpenFGA\Models\{TupleKey, TupleKeys};
$accessibleDocs = [];
// Standard long-form equivalent - requires error handling
try {
$generator = $client->streamedListObjects(
store: $storeId,
model: $modelId,
type: 'document',
relation: 'viewer',
user: 'user:anne',
context: (object)['department' => 'engineering'],
contextualTuples: new TupleKeys(
new TupleKey(
user: 'user:anne',
relation: 'member',
object: 'team:engineering',
)
),
consistency: Consistency::HIGHER_CONSISTENCY
)->unwrap();
foreach ($generator as $streamedResponse) {
$accessibleDocs[] = $streamedResponse->getObject();
}
} catch (Throwable $error) {
// Handle errors explicitly
}
The models()
helper simplifies retrieving all authorization models with automatic pagination:
Helper usage:
use function OpenFGA\models;
// Get all authorization models in a store
$allModels = models(
client: $client,
store: $storeId,
);
foreach ($allModels as $model) {
echo "Model: {$model->getId()}\n";
}
// Find the latest authorization model
$allModels = models(
client: $client,
store: $storeId,
);
$latestModel = end($allModels);
Standard long-form:
$allModels = [];
$continuationToken = null;
do {
$response = $client->listAuthorizationModels(
store: $storeId,
continuationToken: $continuationToken
)->unwrap();
// Add models from current page to collection
foreach ($response->getModels() as $model) {
$allModels[] = $model;
}
// Get continuation token for next page
$continuationToken = $response->getContinuationToken();
} while (null !== $continuationToken);
foreach ($allModels as $model) {
echo "Model: {$model->getId()}\n";
}
The writes()
helper handles large-scale tuple operations with automatic chunking:
Helper usage:
use function OpenFGA\{tuple, tuples, writes};
$result = writes(
client: $client,
store: $storeId,
model: $modelId,
writes: tuples(
tuple(
user: 'user:anne',
relation: 'viewer',
object: 'document:1',
),
tuple(
user: 'user:bob',
relation: 'viewer',
object: 'document:2',
),
// ... hundreds more tuples
),
maxParallelRequests: 10,
maxTuplesPerChunk: 100,
maxRetries: 3,
stopOnFirstError: false
);
echo "Success rate: " . ($result->getSuccessRate() * 100) . "%\n";
Standard long-form:
use OpenFGA\Models\{TupleKey, TupleKeys};
$result = $client->writeTuples(
store: $storeId,
model: $modelId,
writes: new TupleKeys(
new TupleKey(
user: 'user:anne',
relation: 'viewer',
object: 'document:1',
),
new TupleKey(
user: 'user:bob',
relation: 'viewer',
object: 'document:2',
),
// ... hundreds more tuples
),
transactional: false,
maxParallelRequests: 10,
maxTuplesPerChunk: 100,
maxRetries: 3,
retryDelaySeconds: 1.0,
stopOnFirstError: false
)->unwrap();
echo "Success rate: " . ($result->getSuccessRate() * 100) . "%\n";
The checks()
helper simplifies performing multiple authorization checks in a single request:
Helper usage (with auto-generated correlation IDs):
use function OpenFGA\{checks, check, tuple};
// Check multiple permissions using the check() helper with auto-generated correlation IDs
$results = checks($client, $storeId, $modelId,
check(tuple('user:anne', 'viewer', 'document:budget')),
check(tuple('user:bob', 'editor', 'document:budget')),
check(tuple('user:charlie', 'owner', 'document:budget'))
);
// Returns: ['8a2c3e4f5d6...' => true, '9b3d4f5e6c7...' => false, 'a4e5f6d7c8...' => true]
foreach ($results as $correlationId => $allowed) {
echo "$correlationId: " . ($allowed ? 'allowed' : 'denied') . "\n";
}
Helper usage (with explicit correlation IDs):
use function OpenFGA\{checks, check, tuple};
// Check multiple permissions using the check() helper with explicit correlation IDs
$results = checks($client, $storeId, $modelId,
check(tuple('user:anne', 'viewer', 'document:budget'), 'anne-check'),
check(tuple('user:bob', 'editor', 'document:budget'), 'bob-check'),
check(tuple('user:charlie', 'owner', 'document:budget'), 'charlie-check')
);
// Returns: ['anne-check' => true, 'bob-check' => false, 'charlie-check' => true]
foreach ($results as $correlationId => $allowed) {
echo "$correlationId: " . ($allowed ? 'allowed' : 'denied') . "\n";
}
Standard long-form:
use OpenFGA\Models\Collections\BatchCheckItems;
use OpenFGA\Models\BatchCheckItem;
$batchItems = new BatchCheckItems(
new BatchCheckItem(
tupleKey: new TupleKey('user:anne', 'viewer', 'document:budget'),
correlationId: 'anne-check'
),
new BatchCheckItem(
tupleKey: new TupleKey('user:bob', 'editor', 'document:budget'),
correlationId: 'bob-check'
),
new BatchCheckItem(
tupleKey: new TupleKey('user:charlie', 'owner', 'document:budget'),
correlationId: 'charlie-check'
)
);
$batchCheckItems = new BatchCheckItems($batchItems);
$response = $client->batchCheck(
store: $storeId,
model: $modelId,
checks: $batchCheckItems
)->unwrap();
$results = [];
foreach ($response->getResult() as $correlationId => $result) {
$results[$correlationId] = $result->getAllowed();
}
foreach ($results as $correlationId => $allowed) {
echo "$correlationId: " . ($allowed ? 'allowed' : 'denied') . "\n";
}
Helper usage (with context and contextual tuples):
use function OpenFGA\{checks, check, tuple};
// Check with context and contextual tuples using check() helper
$results = checks($client, $storeId, $modelId,
check(
tupleKey: tuple('user:anne', 'viewer', 'document:budget'),
correlation: 'anne-budget-view'
),
check(
tupleKey: tuple('user:bob', 'editor', 'document:budget'),
correlation: 'bob-budget-edit',
context: (object)['time' => '10:00', 'ip' => '192.168.1.1']
),
check(
tupleKey: tuple('user:charlie', 'owner', 'document:budget'),
correlation: 'charlie-budget-own',
contextualTuples: tuples(
tuple('user:charlie', 'member', 'team:finance')
)
)
);
// Returns: ['anne-budget-view' => true, 'bob-budget-edit' => false, 'charlie-budget-own' => true]
Standard long-form (with context and contextual tuples):
use OpenFGA\Models\Collections\BatchCheckItems;
use OpenFGA\Models\{BatchCheckItem, TupleKey};
$batchItems = [
new BatchCheckItem(
tupleKey: new TupleKey('user:anne', 'viewer', 'document:budget'),
correlationId: 'anne-budget-view'
),
new BatchCheckItem(
tupleKey: new TupleKey('user:bob', 'editor', 'document:budget'),
correlationId: 'bob-budget-edit',
context: (object)['time' => '10:00', 'ip' => '192.168.1.1']
),
new BatchCheckItem(
tupleKey: new TupleKey('user:charlie', 'owner', 'document:budget'),
correlationId: 'charlie-budget-own',
contextualTuples: new TupleKeys([
new TupleKey('user:charlie', 'member', 'team:finance')
])
)
];
$batchCheckItems = new BatchCheckItems($batchItems);
$results = [];
$response = $client->batchCheck(
store: $storeId,
model: $modelId,
checks: $batchCheckItems
)->unwrap();
foreach ($response->getResult() as $correlationId => $result) {
$results[$correlationId] = $result->getAllowed();
}
Helper usage:
use function OpenFGA\{ok, err};
// Create a Success
$success = ok('Operation completed');
// Create a Failure
$failure = err(new Exception('Operation failed'));
Standard long-form:
use OpenFGA\Results\{Failure, Success};
// Create a Success
$success = new Success('Operation completed');
// Create a Failure
$failure = new Failure(new Exception('Operation failed'));
The result()
helper provides unified handling:
Helper usage:
use function OpenFGA\result;
// Execute a closure safely
$result = result(function () {
// Some operation that might throw
return performRiskyOperation();
});
// Unwrap a Result
$value = result($someResult);
Standard long-form:
use OpenFGA\Results\{Failure, Success};
// Execute a closure safely
try {
$value = performRiskyOperation();
$result = new Success($value);
} catch (Throwable $e) {
$result = new Failure($e);
}
// Unwrap a Result
if ($someResult->failed()) {
throw $someResult->err();
}
$value = $someResult->val();
Helper usage:
use function OpenFGA\{success, failure, unwrap};
// Handle success
success($result, function ($value) {
echo "Success: $value\n";
});
// Handle failure
failure($result, function ($error) {
echo "Error: " . $error->getMessage() . "\n";
});
// Unwrap with fallback
$value = unwrap($result, fn() => 'default value');
Standard long-form:
// Handle success
if ($result->succeeded()) {
$value = $result->val();
echo "Success: $value\n";
}
// Handle failure
if ($result->failed()) {
$error = $result->err();
echo "Error: " . $error->getMessage() . "\n";
}
// Unwrap with fallback
$value = $result->unwrap(fn() => 'default value');
Here's how helpers simplify building a complete authorization system:
Using helpers:
use function OpenFGA\{allowed, store, dsl, model, write, tuples, tuple};
// 1. Create a store
$storeId = store(client: $client, name: 'document-sharing-app');
// 2. Define the authorization model
$authModel = dsl(client: $client, dsl: '
model
schema 1.1
type user
type team
relations
define member: [user]
type document
relations
define owner: [user]
define editor: [user, team#member]
define viewer: [user, team#member] or editor
');
// 3. Create the model in the store
$modelId = model(client: $client, store: $storeId, model: $authModel);
// 4. Write relationships
write(client: $client, store: $storeId, model: $modelId, tuples: tuples(
// Direct permissions
tuple('user:alice', 'owner', 'document:budget'),
tuple('user:bob', 'editor', 'document:budget'),
// Team membership
tuple('user:charlie', 'member', 'team:finance'),
tuple('user:david', 'member', 'team:finance'),
// Team permissions
tuple('team:finance#member', 'viewer', 'document:budget')
));
// 5. Check permissions
$users = ['alice', 'bob', 'charlie', 'david', 'eve'];
$relations = ['owner', 'editor', 'viewer'];
foreach ($users as $user) {
foreach ($relations as $relation) {
if (allowed(client: $client, store: $storeId, model: $modelId, tupleKey: tuple("user:$user", $relation, 'document:budget'))) {
echo "$user can $relation document:budget\n";
}
}
}
Standard long-form equivalent:
use OpenFGA\Models\Collections\TupleKeys;
use OpenFGA\Models\TupleKey;
// 1. Create a store
$storeResponse = $client->createStore(name: 'document-sharing-app')->unwrap();
$storeId = $storeResponse->getId();
// 2. Define the authorization model
$authModel = $client->dsl('
model
schema 1.1
type user
type team
relations
define member: [user]
type document
relations
define owner: [user]
define editor: [user, team#member]
define viewer: [user, team#member] or editor
')->unwrap();
// 3. Create the model in the store
$modelResponse = $client->createAuthorizationModel(
store: $storeId,
typeDefinitions: $authModel->getTypeDefinitions(),
conditions: $authModel->getConditions(),
schemaVersion: $authModel->getSchemaVersion()
)->unwrap();
$modelId = $modelResponse->getModel();
// 4. Write relationships
$client->writeTuples(
store: $storeId,
model: $modelId,
writes: new TupleKeys([
// Direct permissions
new TupleKey('user:alice', 'owner', 'document:budget'),
new TupleKey('user:bob', 'editor', 'document:budget'),
// Team membership
new TupleKey('user:charlie', 'member', 'team:finance'),
new TupleKey('user:david', 'member', 'team:finance'),
// Team permissions
new TupleKey('team:finance#member', 'viewer', 'document:budget')
]),
transactional: true
)->unwrap();
// 5. Check permissions
$users = ['alice', 'bob', 'charlie', 'david', 'eve'];
$relations = ['owner', 'editor', 'viewer'];
foreach ($users as $user) {
foreach ($relations as $relation) {
$checkResponse = $client->check(
store: $storeId,
model: $modelId,
tupleKey: new TupleKey("user:$user", $relation, 'document:budget')
)->unwrap();
if ($checkResponse->getAllowed()) {
echo "$user can $relation document:budget\n";
}
}
}
- You want concise, readable code
- You're prototyping or exploring the API
- You're writing scripts or simple applications
- You prefer functional-style programming
- You want to reduce boilerplate in tests
- You want fail-safe behavior where errors default to "false/denied"
- You're building UI components that need graceful degradation
- You need fine-grained control over error handling
- You're building complex error recovery logic
- You want to access all response metadata (like trace information)
- You need to distinguish between "permission denied" and "error occurred"
- You're building abstractions on top of the SDK
- Your team prefers explicit object construction
- You want to handle different types of errors differently
- Reduced Boilerplate: Helpers eliminate repetitive code patterns
- Improved Readability: Authorization logic becomes more declarative
- Faster Development: Less typing means faster prototyping
- Fewer Errors: Less code means fewer opportunities for mistakes
- Consistent Patterns: Helpers enforce best practices by default
Helpers have minimal overhead - they're thin wrappers around the standard methods:
-
tuple()
andtuples()
are simple constructors -
write()
,delete()
add one function call -
allowed()
andobjects()
add one function call plus try-catch overhead (negligible) -
writes()
andchecks()
delegate directly to the client's batch processing - Result helpers add negligible overhead for error handling
For performance-critical paths, both approaches perform identically after PHP's optimizer runs.
Note: The allowed()
and objects()
helpers' error-safe behavior does add a try-catch block, but this has no performance impact when no exceptions occur, which is the common case.
- Explore the Tuples Guide for more details on relationship tuples
- Learn about Batch Operations for handling large datasets
- Understand Result Patterns for robust error handling
- See Integration Examples for real-world usage patterns