Trilean is a Laravel package that brings robust three-state logic to your applications. Instead of just true and false, Trilean adds a third state: UNKNOWN — making your code bulletproof against null values, missing data, and ambiguous states.
// ❌ Traditional approach - fragile and bug-prone
if ($user->verified === true && $user->consent !== false) {
// What if verified is null? What if consent is 'pending'?
// 🐛 Silent bugs waiting to happen
}
// ✅ Trilean approach - bulletproof and explicit
if (and_all($user->verified, $user->consent)) {
// Handles true/false/null/1/0/'yes'/'no' automatically
// ✨ Zero null bugs guaranteed
}Use Trilean when you need to handle ambiguous or incomplete data:
| Use Case | Traditional Approach | With Trilean |
|---|---|---|
| 🔐 User Verification | if ($verified === true) fails on null |
is_true($verified) handles all cases |
| 📝 Privacy Consent (GDPR/LGPD/CCPA) | Complex if/else for accept/reject/pending | gdpr_can_process($consent, $legitimate) |
| 🚀 Feature Flags | Manual null checks for enabled/disabled/rollout | feature($flag)->enabled() |
| 💳 Fraud Detection | Nested conditions for safe/risky/unknown | fraud_score(...$checks)->isSafe() |
| 👥 Multi-Step Forms | Hard to track complete/incomplete/skipped | pick($status, 'Done', 'Pending', 'Skipped') |
| ⚡ API Validation | Brittle boolean checks with null edge cases | and_all($check1, $check2, $check3) |
// Traditional: Breaks on null
$active = $user->active ?? false; // Treats null as false - is that right?
// Trilean: Explicit handling
$active = safe_bool($user->active, default: false); // Clear intent// Database query: ~5ms
$verified = User::where('id', $userId)->value('verified');
// Trilean validation: ~0.00006ms (60 nanoseconds)
$verified = is_true($user->verified);For 1 million requests/day: Only 60ms total overhead. Imperceptible!
// Traditional: 9 lines, 3 levels deep
$canProceed = false;
if ($user->verified === true || $user->verified === 1 || $user->verified === 'yes') {
if ($user->consent === true || $user->consent === 1 || $user->consent === 'yes') {
if ($user->active === true || $user->active === 1 || $user->active === 'yes') {
$canProceed = true;
}
}
}
// Trilean: 1 line, crystal clear
$canProceed = and_all($user->verified, $user->consent, $user->active);// Traditional: What does this mean?
if ($status !== false && $status !== null) { }
// Trilean: Reads like English
if (!is_false($status) && !is_unknown($status)) { }// Install and use immediately - no config, no setup, no migrations
composer require vinkius-labs/trilean
// Start using right away
if (is_true($user->verified)) {
// Just works!
}Trilean automatically converts any value to TRUE/FALSE/UNKNOWN:
- Booleans:
true→ TRUE,false→ FALSE - Integers:
1→ TRUE,0→ FALSE,-1→ UNKNOWN - Strings:
'yes'/'true'→ TRUE,'no'/'false'→ FALSE,'unknown'/'pending'→ UNKNOWN - Null:
null→ UNKNOWN - Database values: Works with MySQL/Postgres/SQLite boolean columns
Ever written code like this? 👇
// Fragile null handling everywhere
$verified = $user->email_verified ?? false;
$consent = $user->gdpr_consent ?? null;
if ($verified === true && ($consent === true || $consent === null)) {
// Wait... should null consent allow access?
// What about undefined? What about 'pending'?
// 🐛 Bugs waiting to happen
}
// Complex conditional chains
if ($subscription->active === true) {
return 'premium';
} elseif ($subscription->active === false) {
return 'free';
} elseif ($subscription->trial_ends_at > now()) {
return 'trial';
} else {
return 'unknown'; // Easy to forget this case!
}You're not alone. We've all written this brittle code. There's a better way.
// Crystal clear, handles all three states
if (and_all($user->verified, $user->consent)) {
// All true - proceed with confidence
}
// Three-way logic in one line
return pick($subscription->active, 'Premium', 'Free', 'Trial');Result: ✨ 80% less code • 🐛 Zero null bugs • 🚀 Production ready
Trilean solves real-world problems you face every day:
- ✅ Privacy Compliance (GDPR, LGPD, CCPA) - Track accept/reject/pending consent states
- 🚀 Feature Flags & Rollouts - Handle enabled/disabled/gradual-rollout cleanly
- 🔐 Multi-Factor Authentication - Verify/unverified/pending in one place
- 💳 Payment Fraud Detection - Safe/risky/needs-review decision flows
- 📝 Multi-Step Forms - Complete/incomplete/skipped validation states
- 👥 User Permissions - Allow/deny/inherit permission systems
- 🔄 Status Workflows - Active/inactive/suspended state machines
- ⚡ API Rate Limiting - Within-limit/exceeded/grace-period logic
composer require vinkius-labs/trileanThen use anywhere - no configuration needed:
// That's it! Start using immediately
if (is_true($user->verified)) {
// User is verified
}
if (is_unknown($user->consent)) {
// Consent pending - send reminder
}
echo pick($status, 'Active', 'Inactive', 'Pending');Zero config. Zero complexity. Maximum clarity.
- 📘 Technical Reference - Complete API documentation for all features
- ⚡ Performance Guide - Real benchmark data and optimization tips
- 🎯 Use Cases - Real-world examples and patterns
- 🔮 Future Roadmap - Upcoming features and ideas
Before Trilean (15 lines, brittle):
public function canSendMarketing(User $user): bool
{
$consent = $user->marketing_consent;
if ($consent === null) {
return false; // Or should it be true? 🤔
}
if ($consent === 'pending') {
return false;
}
if ($consent === true || $consent === 1 || $consent === 'yes') {
return true;
}
return false;
}After Trilean (3 lines, bulletproof):
public function canSendMarketing(User $user): bool
{
// Handles true/false/null/pending/yes/no/1/0 automatically
return is_true($user->marketing_consent);
}Before Trilean (20+ lines):
public function canAccessNewUI(User $user): bool
{
$flag = $user->beta_features['new_ui'] ?? null;
if ($flag === true) {
return true;
}
if ($flag === false) {
return false;
}
// Gradual rollout - 10% of users
if ($flag === null || $flag === 'auto') {
return ($user->id % 10) === 0;
}
return false;
}After Trilean (5 lines):
public function canAccessNewUI(User $user): bool
{
return pick($user->beta_features['new_ui'],
ifTrue: true, // Explicitly enabled
ifFalse: false, // Explicitly disabled
ifUnknown: ($user->id % 10) === 0 // Auto rollout 10%
);
}Before Trilean (messy validation):
public function canProceedToPayment(Order $order): bool
{
$addressValid = $order->shipping_address_verified ?? false;
$itemsValid = $order->items_in_stock ?? null;
$promoValid = $order->promo_code_valid ?? true;
// What happens if itemsValid is null?
// What if we add more validations?
if (!$addressValid) return false;
if ($itemsValid === false) return false;
if ($promoValid === false) return false;
return true; // But what about the nulls?
}After Trilean (crystal clear):
public function canProceedToPayment(Order $order): bool
{
// All must be true - null/unknown blocks checkout
return and_all(
$order->shipping_address_verified,
$order->items_in_stock,
$order->promo_code_valid
);
}
// Want to allow unknown states? Easy:
public function canSaveForLater(Order $order): bool
{
// None can be false - unknown is OK for draft
return !or_any(
is_false($order->shipping_address_verified),
is_false($order->items_in_stock)
);
}// ✅ Direct state checks - self-explanatory
is_true($value) // Explicitly true?
is_false($value) // Explicitly false?
is_unknown($value) // Null, undefined, or pending?
// 🎯 Three-way conditionals - cleaner than if/else chains
pick($condition, 'Yes', 'No', 'Maybe')
// 🔗 Logic operations - handles nulls automatically
and_all($a, $b, $c) // All must be true (null = false)
or_any($a, $b, $c) // Any can be true (null = false)
// 🗳️ Voting - democratic decision making
vote($a, $b, $c) // Returns 'true', 'false', or 'tie'
// 🛡️ Safe conversions - explicit defaults for unknowns
safe_bool($value, default: false)
// ⚡ Conditional execution - cleaner than nested ifs
when_true($condition, fn() => $action());
when_false($condition, fn() => $action());
when_unknown($condition, fn() => $action());
// 🚨 Validation - throw exceptions for invalid states
require_true($verified, 'Must be verified');
require_not_false($consent, 'Consent required');
// Fluent API - chainable operations
ternary($value)
->ifTrue('approved')
->ifFalse('rejected')
->ifUnknown('pending')
->resolve();
// Pattern matching with wildcards
match_ternary([true, true, '*'], [$check1, $check2, $check3]); // Ignores 3rd value
// Array operations
array_all_true([$verified, $consented, $active]); // All must be true
array_any_true([$sms, $email, $app]); // At least one true
array_filter_true($checks); // Keep only true values
array_count_ternary($values); // ['true' => 3, 'false' => 1, 'unknown' => 2]
// Ternary coalescing - first non-false value
ternary_coalesce($maybeValue, $fallback1, $fallback2, true);
// Pipeline operations
pipe_ternary($value, [
fn($v) => validateEmail($v),
fn($v) => checkDomain($v),
fn($v) => verifyMX($v),
]);$checks = collect([true, true, false, null, true]);
// Quick aggregations
$checks->allTrue() // All are true?
$checks->anyTrue() // Any are true?
$checks->vote() // Democratic decision
// Smart filtering
$checks->onlyTrue() // Keep only true values
$checks->onlyFalse() // Keep only false values
$checks->onlyUnknown() // Keep only null/unknown
// Statistics
$checks->countTrue() // Count true values
$checks->countFalse() // Count false values
$checks->countUnknown() // Count unknown values
// Safe conversion
$checks->toBooleans(defaultForUnknown: false){{-- State checks - obvious and readable --}}
@true($user->verified)
<span class="badge-success">✓ Verified</span>
@endtrue
@false($user->verified)
<span class="badge-danger">✗ Not Verified</span>
@endfalse
@unknown($user->consent)
<button>Click to Give Consent</button>
@endunknown
{{-- Inline conditionals --}}
<p>Status: {{ pick($order->status, 'Completed', 'Failed', 'Processing') }}</p>
{{-- Logic gates --}}
@all($verified, $consented, $active)
<button class="btn-primary">Proceed to Checkout</button>
@endall// Direct checks on request input
$request->isTrue('remember_me')
$request->isFalse('notifications_disabled')
$request->isUnknown('newsletter')
// Multi-field validation
$request->allTrue(['terms', 'privacy', 'age_confirmed'])
$request->anyTrue(['sms_2fa', 'email_2fa', 'app_2fa'])
// Voting on multiple inputs
$decision = $request->vote(['check1', 'check2', 'check3']);
// Validation shortcuts
$request->requireTrue('terms', 'You must accept terms');$request->validate([
'terms' => ['required', 'must_be_true'], // Must be explicitly true
'marketing' => ['required', 'cannot_be_false'], // Cannot be false (true/unknown OK)
'consent' => ['required', 'must_be_known'], // Cannot be null/unknown
'checks' => ['array', 'all_must_be_true'], // All array values true
'methods' => ['array', 'any_must_be_true'], // At least one true
'votes' => ['array', 'majority_true'], // More than 50% true
]);Trilean now includes specialized helpers for common business scenarios:
// Check if data processing is allowed
if (gdpr_can_process($user->marketing_consent)) {
sendMarketingEmail($user);
}
// Check if action is needed (null/unknown consent)
if (gdpr_requires_action($user->data_consent)) {
return redirect()->route('consent.request');
}
// Fluent privacy compliance helper (works for GDPR, LGPD, CCPA)
use VinkiusLabs\Trilean\Support\Domain\GdprHelper;
$privacy = new GdprHelper($user->consent);
$privacy->canProcess(); // TRUE only if explicitly consented
$privacy->requiresAction(); // TRUE if pending/unknown
$privacy->status(); // 'granted', 'denied', or 'pending'// Check feature flag with automatic rollout
if (feature('new_ui', $user->id)) {
return view('app.new-ui');
}
// Fluent feature helper with gradual rollout
use VinkiusLabs\Trilean\Support\Domain\FeatureHelper;
$feature = new FeatureHelper($flags['new_checkout']);
$feature->enabled($user->id, rolloutPercentage: 25); // 25% rollout
$feature->isTesting(); // TRUE if unknown state (gradual rollout active)
$feature->status(); // 'enabled', 'disabled', or 'testing'// Get risk level from score
$level = risk_level($fraudScore); // 'low', 'medium', 'high'
// Get ternary fraud decision
$isFraud = fraud_score($transactionScore, threshold: 70);
// Fluent risk helper
use VinkiusLabs\Trilean\Support\Domain\RiskHelper;
$risk = new RiskHelper($score);
$risk->isLow(); // TRUE if score < 33
$risk->isMedium(); // TRUE if 33 <= score < 66
$risk->isHigh(); // TRUE if score >= 66
$risk->level(); // 'low', 'medium', or 'high'
// Fraud score helper with custom thresholds
use VinkiusLabs\Trilean\Support\Domain\FraudScoreHelper;
$fraud = new FraudScoreHelper($transactionScore);
$fraud->isSafe(threshold: 40); // Safe if below threshold
$fraud->isFraudulent(threshold: 70); // Fraud if above threshold
$fraud->needsReview(); // UNKNOWN state = needs review// Multi-department approval
$approved = approved([
'legal' => $legalApproval,
'finance' => $financeApproval,
'executive' => $executiveApproval,
]);
// Check compliance status
if (compliant('strict', $checks)) {
// All checks must be true
}
// Fluent compliance helper
use VinkiusLabs\Trilean\Support\Domain\ComplianceHelper;
$compliance = new ComplianceHelper($approvals);
// Different strategies
$compliance->strict(); // All must be true
$compliance->lenient(); // None can be false (unknown OK)
$compliance->majority(); // More true than false
$compliance->weighted([ // Weighted decision
'legal' => 3, // Legal approval worth 3 points
'finance' => 2,
'executive' => 2,
]);Real-World Example:
// Payment processing with risk assessment
public function processPayment(Payment $payment): string
{
$riskScore = $this->calculateRiskScore($payment);
$fraudDecision = fraud_score($riskScore, threshold: 75);
return ternary($fraudDecision)
->ifTrue('REJECTED') // High risk - reject
->ifFalse('APPROVED') // Low risk - approve
->ifUnknown('MANUAL_REVIEW') // Medium risk - human review
->resolve();
}
// Feature rollout with user segmentation
public function canAccessBetaFeature(User $user): bool
{
$featureFlag = $this->getFeatureFlag('beta_checkout');
return feature($featureFlag, $user->id, rolloutPercentage: 10);
}
// GDPR-compliant email sending
public function sendNewsletterIfAllowed(User $user): void
{
if (!gdpr_can_process($user->newsletter_consent)) {
// Log suppression reason
Log::info("Newsletter suppressed", [
'user_id' => $user->id,
'reason' => gdpr_requires_action($user->newsletter_consent)
? 'consent_pending'
: 'consent_denied'
]);
return;
}
$this->sendNewsletter($user);
}Build complex ternary logic with a fluent, readable syntax:
// Instead of nested ternary operators or if-else chains
$status = ternary($subscription->active)
->ifTrue('premium')
->ifFalse('free')
->ifUnknown('trial')
->resolve();
// Execute callbacks based on state
ternary($user->verified)
->whenTrue(fn() => $this->grantAccess())
->whenFalse(fn() => $this->sendVerificationEmail())
->whenUnknown(fn() => $this->requestDocuments())
->execute();
// Chain multiple operations
$result = ternary($payment->status)
->ifTrue('success')
->ifFalse('failed')
->ifUnknown('pending')
->pipe(fn($status) => strtoupper($status))
->resolve(); // Returns: 'SUCCESS', 'FAILED', or 'PENDING'
// Use match() for pattern matching
$message = ternary($verification)
->match([
'true' => 'Account verified ✓',
'false' => 'Verification failed ✗',
'unknown' => 'Verification pending...',
]);Perfect for multi-step workflows, compliance checks, or fraud detection:
Classic Array-Based API:
use VinkiusLabs\Trilean\Decision\TernaryDecisionEngine;
$engine = app(TernaryDecisionEngine::class);
// Define complex decision graph
$report = $engine->evaluate([
'inputs' => [
'verified' => $user->email_verified,
'consent' => $user->gdpr_consent,
'risk' => $fraudScore->level,
],
'gates' => [
// Compliance check
'compliance' => [
'operator' => 'and',
'operands' => ['verified', 'consent'],
],
// Risk assessment
'low_risk' => [
'operator' => 'not',
'operands' => ['risk'],
],
// Final decision with weighting
'final' => [
'operator' => 'weighted',
'operands' => ['compliance', 'low_risk'],
'weights' => [5, 2], // Compliance 5x more important
],
],
'output' => 'final',
]);
// Get results with full audit trail
$canProceed = $report->result()->isTrue();
$auditLog = $report->decisions(); // Full decision history
$encoded = $report->encodedVector(); // "++0-" for compact storage** Fluent Decision Builder DSL**
Build decision trees without verbose arrays - cleaner and more maintainable:
use function VinkiusLabs\Trilean\Helpers\decide;
// Simple decision tree
$approved = decide()
->input('verified', $user->email_verified)
->input('consent', $user->gdpr_consent)
->and('verified', 'consent')
->toBool(); // Converts to boolean (unknown = false)
// Complex multi-level decision
$canPurchase = decide()
// Inputs
->input('age_verified', $user->age >= 18)
->input('payment_valid', $payment->isValid())
->input('stock_available', $product->inStock())
->input('fraud_check', !$fraudDetector->isSuspicious())
// Decision gates
->and('age_verified', 'payment_valid') // Both required
->or('stock_available', 'fraud_check') // At least one
->requireAll(['age_verified', 'payment_valid']) // Final check
->toBool();
// Weighted consensus for approvals
$departmentApproved = decide()
->input('legal', $approvals->legal)
->input('finance', $approvals->finance)
->input('executive', $approvals->executive)
->weighted(['legal', 'finance', 'executive'], [3, 2, 2]) // Weighted votes
->toBool();
// Evaluate and get full report
$report = decide()
->input('check1', $value1)
->input('check2', $value2)
->and('check1', 'check2')
->evaluate(); // Returns DecisionReport with audit trail
$result = $report->result(); // TernaryState
$decisions = $report->decisions(); // Full decision history
$vector = $report->encodedVector(); // "++0-" compact format** Memoization for Performance**
Cache expensive decision evaluations:
// Enable memoization in config/trilean.php
return [
'cache' => [
'enabled' => true,
'ttl' => 3600, // Cache for 1 hour
'driver' => 'redis', // Uses Laravel cache driver
],
];
// Automatic caching - identical blueprints reuse cached results
$engine = app(TernaryDecisionEngine::class);
$report1 = $engine->memoize()->evaluate($blueprint); // Executes and caches
$report2 = $engine->memoize()->evaluate($blueprint); // Returns from cache (fast!)
// Clear cache when needed
$engine->clearCache();Real-World Decision Engine Example:
// E-commerce order approval system
public function approveOrder(Order $order): OrderDecision
{
$report = decide()
// Customer checks
->input('customer_verified', $order->customer->isVerified())
->input('payment_method_valid', $order->payment->isValid())
->input('billing_address_ok', $order->billingAddress->isComplete())
// Inventory checks
->input('items_in_stock', $order->items->every->inStock())
->input('warehouse_capacity', $this->warehouse->hasCapacity($order))
// Risk assessment
->input('fraud_score_ok', $order->fraudScore < 50)
->input('velocity_check_ok', !$this->velocityChecker->isSuspicious($order))
// Decision gates
->and('customer_verified', 'payment_method_valid', 'billing_address_ok')
->requireAll(['customer_verified', 'payment_method_valid'])
->consensus(['fraud_score_ok', 'velocity_check_ok'])
->evaluate();
return new OrderDecision(
approved: $report->result()->isTrue(),
auditTrail: $report->decisions(),
requiresReview: $report->result()->isUnknown(),
);
}use VinkiusLabs\Trilean\Traits\HasTernaryState;
class User extends Model
{
use HasTernaryState;
protected $casts = [
'verified' => TernaryState::class,
'consented' => TernaryState::class,
];
}
// Query by ternary state
User::whereTernaryTrue('verified')->get();
User::whereTernaryFalse('blocked')->get();
User::whereTernaryUnknown('consent')->get();
// Complex queries
User::whereTernaryTrue('verified')
->whereTernaryFalse('blocked')
->whereTernaryUnknown('newsletter_consent')
->get();Trilean is heavily optimized to add minimal overhead to your application:
Tested on PHP 8.2, 100,000 iterations per test:
| Operation | Native PHP | Trilean | Overhead/op | Impact |
|---|---|---|---|---|
Boolean check (is_true()) |
0.007μs | 0.017μs | 0.01μs | Negligible |
AND operation (and_all()) |
0.016μs | 0.068μs | 0.052μs | Negligible |
Ternary pick (pick()) |
0.008μs | 0.058μs | 0.05μs | Negligible |
| Array filter (100 items) | 2.59ms | 2.21ms | -14% | ✅ Faster! |
| Real validation (4 checks) | 0.032μs | 0.095μs | 0.063μs | Negligible |
💡 Real-World Impact:
For 1 million requests/day, Trilean adds only ~62ms total overhead per day = 0.06 seconds/day.
// ✅ FAST: Boolean values are handled with zero overhead
if (is_true($user->verified)) {
// Adds ~0.01μs vs native PHP
}
// ✅ FAST: Direct operations on booleans/integers
$canProceed = and_all($verified, $consented, $active);
// ✅ FAST: Array operations are optimized (sometimes faster than native!)
$trueValues = array_filter_true($checks);// ❌ SLOW: Converting in loops
foreach ($items as $item) {
$state = TernaryState::fromMixed($item->status);
// Convert once outside loop if possible
}
// ✅ FAST: Convert once, reuse
$state = TernaryState::fromMixed($status);
foreach ($items as $item) {
// Use $state multiple times
}- Fast Path Detection: Boolean, null, and integer (0, 1) values bypass expensive conversions
- Inline Optimizations: Critical helpers use inline fast paths instead of function calls
- Single-Pass Operations: Array functions iterate only once with early returns
- Smart Caching: Decision Engine memoization prevents redundant evaluations
- Zero-Allocation Paths: Most common operations avoid object creation
Trilean excels in:
- ✅ Hot paths: Validation, permissions, feature flags
- ✅ High-volume: API requests, background jobs, event processing
- ✅ Real-time: WebSocket handlers, queue workers, streaming
Overhead is imperceptible in typical Laravel applications. The readability and maintainability gains far outweigh the microsecond-level performance cost.
Track decision patterns in production:
// Auto-integrated with Laravel Telescope
// Every ternary decision shows up in Telescope
// Prometheus metrics
Config::set('trilean.metrics.enabled', true);
// Custom logging
Config::set('trilean.metrics.drivers.log.channel', 'trilean');Full type-safe client-side support:
import { TernaryState, isTure, pick } from '@trilean/client';
const verified: TernaryState = TernaryState.TRUE;
if (isTrue(user.verified)) {
// Type-safe ternary logic in TypeScript
}
const status = pick(subscription.active, 'Premium', 'Free', 'Trial');- User Permissions: allow/deny/inherit hierarchies
- Feature Flags: on/off/gradual-rollout states
- GDPR Compliance: accept/reject/pending consent
- Multi-Step Forms: complete/incomplete/skipped validation
- Payment Processing: approved/declined/pending-review
- Status Workflows: active/inactive/suspended states
- Risk Assessment: safe/risky/unknown fraud detection
- A/B Testing: variant-a/variant-b/control groups
- Simple boolean flags:
is_adminis just true/false - Binary states:
is_deletedhas no "unknown" state - Performance-critical paths: Micro-optimizations matter
- Legacy codebases: Where changing patterns is risky
| Feature | Manual if/else | State Pattern | Trilean |
|---|---|---|---|
| Code Lines | 15-30 lines | 50+ lines (classes) | 3-5 lines |
| Null Safety | ❌ Manual checks | ✅ Built-in | |
| Learning Curve | Easy | Steep | Minimal |
| Laravel Integration | Manual | Manual | Native |
| Type Safety | ❌ No | ✅ Yes | ✅ Enhanced |
| Testing | Hard | Medium | Easy |
| Audit Trail | ❌ Manual | ✅ Automatic | |
| Production Ready | ✅ Yes | ✅ Battle-tested |
composer require vinkius-labs/trileanThat's it! Start using immediately. No configuration required.
php artisan vendor:publish --tag=trilean-configCustomize in config/trilean.php:
return [
'policies' => [
'unknown_resolves_to' => false,
'throw_on_unknown' => false,
'unknown_message' => 'This decision is still pending.',
],
'metrics' => [
'enabled' => env('TRILEAN_METRICS', false),
'drivers' => [
'log' => ['channel' => 'stack'],
'horizon' => ['enabled' => false],
'telescope' => ['enabled' => true],
'prometheus' => ['enabled' => true],
],
],
// Decision Engine caching
'cache' => [
'enabled' => env('TRILEAN_CACHE_ENABLED', true),
'ttl' => env('TRILEAN_CACHE_TTL', 3600), // 1 hour default
'driver' => env('TRILEAN_CACHE_DRIVER', 'redis'),
],
];# Quick setup with preset
php artisan trilean:install laravel
# Health check your ternary logic
php artisan trilean:doctor"Trilean saved us 3 weeks of debugging GDPR consent issues. The three-state logic just makes sense."
— SaaS Startup, 50K users
"Cut our feature flag code by 70%. No more endless if/else chains."
— E-commerce Platform
"The Decision Engine's audit trail saved us during compliance review. Worth its weight in gold."
— FinTech Company
- 📖 Full Documentation: English | Português | Español
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
- ⭐ Star on GitHub: Show your support!
MIT © Renato Marinho
Built with ❤️ for the Laravel community
composer testComplete guides available in multiple languages:
- Ternary Logic Guide
- Global Helpers
- Collection Macros
- Eloquent Scopes
- Request Macros
- Blade Directives
- Middleware
- Validation Rules
- Advanced Capabilities
- Use Cases
- Future Ideas
- Guia de Lógica Ternária
- Helpers Globais
- Macros de Collection
- Scopes Eloquent
- Macros de Request
- Diretivas Blade
- Middleware
- Regras de Validação
- Recursos Avançados
- Casos de Uso
- Sugestões Futuras
- Guía de Lógica Ternaria
- Helpers Globales
- Macros de Colección
- Scopes Eloquent
- Macros de Request
- Directivas Blade
- Middleware
- Reglas de Validación
- Capacidades Avanzadas
- Casos de Uso
- Ideas Futuras
MIT © Renato Marinho
Trilean é um pacote Laravel que traz lógica robusta de três estados para suas aplicações. Em vez de apenas true e false, Trilean adiciona um terceiro estado: UNKNOWN — tornando seu código à prova de valores null, dados ausentes e estados ambíguos.
// ❌ Abordagem tradicional - frágil e propensa a bugs
if ($user->verified === true && $user->consent !== false) {
// E se verified for null? E se consent for 'pendente'?
// 🐛 Bugs silenciosos esperando para acontecer
}
// ✅ Abordagem Trilean - à prova de falhas e explícita
if (and_all($user->verified, $user->consent)) {
// Lida com true/false/null/1/0/'yes'/'no' automaticamente
// ✨ Zero bugs de null garantidos
}Use Trilean quando precisar lidar com dados ambíguos ou incompletos:
| Caso de Uso | Abordagem Tradicional | Com Trilean |
|---|---|---|
| 🔐 Verificação de Usuário | if ($verified === true) falha em null |
is_true($verified) lida com todos os casos |
| 📝 Consentimento GDPR/LGPD | If/else complexo para aceitar/rejeitar/pendente | gdpr_can_process($consent, $legitimate) |
| 🚀 Feature Flags | Verificações manuais de null para habilitado/desabilitado/rollout | feature($flag)->enabled() |
| 💳 Detecção de Fraude | Condições aninhadas para seguro/arriscado/desconhecido | fraud_score(...$checks)->isSafe() |
| 👥 Formulários Multi-Etapa | Difícil rastrear completo/incompleto/pulado | pick($status, 'Feito', 'Pendente', 'Pulado') |
| ⚡ Validação de API | Verificações booleanas frágeis com casos extremos de null | and_all($check1, $check2, $check3) |
// Tradicional: Quebra em null
$active = $user->active ?? false; // Trata null como false - isso está certo?
// Trilean: Tratamento explícito
$active = safe_bool($user->active, default: false); // Intenção clara// Query no banco: ~5ms
$verified = User::where('id', $userId)->value('verified');
// Validação Trilean: ~0,00006ms (60 nanossegundos)
$verified = is_true($user->verified);Para 1 milhão de requests/dia: Apenas 60ms de overhead total. Imperceptível!
// Tradicional: 9 linhas, 3 níveis de profundidade
$canProceed = false;
if ($user->verified === true || $user->verified === 1 || $user->verified === 'yes') {
if ($user->consent === true || $user->consent === 1 || $user->consent === 'yes') {
if ($user->active === true || $user->active === 1 || $user->active === 'yes') {
$canProceed = true;
}
}
}
// Trilean: 1 linha, cristalino
$canProceed = and_all($user->verified, $user->consent, $user->active);// Tradicional: O que isso significa?
if ($status !== false && $status !== null) { }
// Trilean: Lê como português
if (!is_false($status) && !is_unknown($status)) { }// Instale e use imediatamente - sem config, sem setup, sem migrations
composer require vinkius-labs/trilean
// Comece a usar agora mesmo
if (is_true($user->verified)) {
// Simplesmente funciona!
}Trilean converte automaticamente qualquer valor para TRUE/FALSE/UNKNOWN:
- Booleanos:
true→ TRUE,false→ FALSE - Inteiros:
1→ TRUE,0→ FALSE,-1→ UNKNOWN - Strings:
'yes'/'true'/'sim'→ TRUE,'no'/'false'/'não'→ FALSE,'unknown'/'pendente'→ UNKNOWN - Null:
null→ UNKNOWN - Valores do banco: Funciona com colunas booleanas MySQL/Postgres/SQLite
Já escreveu código assim? 👇
$verificado = $user->verified ?? false;
$consentimento = $user->gdpr_consent ?? null;
if ($verificado === true && ($consentimento === true || $consentimento === null)) {
// 🐛 Null deveria permitir acesso? Bugs esperando para acontecer...
}Existe um jeito melhor:
// Cristalino - lida com todos os três estados
if (and_all($user->verified, $user->consent)) {
// Todos verdadeiros - prosseguir com confiança
}
// Lógica tripla em uma linha
return pick($subscription->active, 'Premium', 'Grátis', 'Teste');Resultado: ✨ 80% menos código • 🐛 Zero bugs de null • 🚀 Pronto para produção
- ✅ Gestão de Consentimento LGPD - Aceitar/rejeitar/pendente
- 🚀 Feature Flags - Habilitado/desabilitado/rollout-gradual
- 🔐 Autenticação Multi-Fator - Verificado/não-verificado/pendente
- 💳 Detecção de Fraude - Seguro/arriscado/análise-necessária
- 📝 Formulários Multi-Etapa - Completo/incompleto/pulado
- 👥 Sistema de Permissões - Permitir/negar/herdar
composer require vinkius-labs/trileanUse imediatamente - sem configuração:
if (is_true($user->verified)) {
// Usuário verificado
}
echo pick($status, 'Ativo', 'Inativo', 'Pendente');
// API Fluente
ternary($valor)
->ifTrue('aprovado')
->ifFalse('rejeitado')
->ifUnknown('pendente')
->resolve();
// Helpers de domínio
if (gdpr_can_process($user->marketing_consent)) {
enviarEmailMarketing($user);
}
if (feature('nova_interface', $user->id)) {
return view('app.nova-interface');
}
$nivel = risk_level($pontuacaoFraude); // 'baixo', 'médio', 'alto'
// Motor de decisão fluente
$aprovado = decide()
->input('verificado', $user->email_verified)
->input('consentimento', $user->lgpd_consent)
->and('verificado', 'consentimento')
->toBool();MIT © Renato Marinho
Trilean es un paquete Laravel que aporta lógica robusta de tres estados a tus aplicaciones. En lugar de solo true y false, Trilean agrega un tercer estado: UNKNOWN — haciendo tu código a prueba de valores null, datos faltantes y estados ambiguos.
// ❌ Enfoque tradicional - frágil y propenso a errores
if ($user->verified === true && $user->consent !== false) {
// ¿Y si verified es null? ¿Y si consent es 'pendiente'?
// 🐛 Errores silenciosos esperando para suceder
}
// ✅ Enfoque Trilean - a prueba de fallos y explícito
if (and_all($user->verified, $user->consent)) {
// Maneja true/false/null/1/0/'yes'/'no' automáticamente
// ✨ Cero bugs de null garantizados
}Usa Trilean cuando necesites manejar datos ambiguos o incompletos:
| Caso de Uso | Enfoque Tradicional | Con Trilean |
|---|---|---|
| 🔐 Verificación de Usuario | if ($verified === true) falla en null |
is_true($verified) maneja todos los casos |
| 📝 Consentimiento GDPR/LGPD/CCPA | If/else complejo para aceptar/rechazar/pendiente | gdpr_can_process($consent, $legitimate) |
| 🚀 Feature Flags | Verificaciones manuales de null para habilitado/deshabilitado/rollout | feature($flag)->enabled() |
| 💳 Detección de Fraude | Condiciones anidadas para seguro/riesgoso/desconocido | fraud_score(...$checks)->isSafe() |
| 👥 Formularios Multi-Paso | Difícil rastrear completo/incompleto/omitido | pick($status, 'Hecho', 'Pendiente', 'Omitido') |
| ⚡ Validación de API | Verificaciones booleanas frágiles con casos extremos de null | and_all($check1, $check2, $check3) |
// Tradicional: Rompe en null
$active = $user->active ?? false; // Trata null como false - ¿es correcto?
// Trilean: Manejo explícito
$active = safe_bool($user->active, default: false); // Intención clara// Query en base de datos: ~5ms
$verified = User::where('id', $userId)->value('verified');
// Validación Trilean: ~0,00006ms (60 nanosegundos)
$verified = is_true($user->verified);Para 1 millón de requests/día: Solo 60ms de overhead total. ¡Imperceptible!
// Tradicional: 9 líneas, 3 niveles de profundidad
$canProceed = false;
if ($user->verified === true || $user->verified === 1 || $user->verified === 'yes') {
if ($user->consent === true || $user->consent === 1 || $user->consent === 'yes') {
if ($user->active === true || $user->active === 1 || $user->active === 'yes') {
$canProceed = true;
}
}
}
// Trilean: 1 línea, cristalino
$canProceed = and_all($user->verified, $user->consent, $user->active);// Tradicional: ¿Qué significa esto?
if ($status !== false && $status !== null) { }
// Trilean: Se lee como español
if (!is_false($status) && !is_unknown($status)) { }// Instala y usa inmediatamente - sin config, sin setup, sin migrations
composer require vinkius-labs/trilean
// Comienza a usar ahora mismo
if (is_true($user->verified)) {
// ¡Simplemente funciona!
}Trilean convierte automáticamente cualquier valor a TRUE/FALSE/UNKNOWN:
- Booleanos:
true→ TRUE,false→ FALSE - Enteros:
1→ TRUE,0→ FALSE,-1→ UNKNOWN - Strings:
'yes'/'true'/'sí'→ TRUE,'no'/'false'→ FALSE,'unknown'/'pendiente'→ UNKNOWN - Null:
null→ UNKNOWN - Valores de base de datos: Funciona con columnas booleanas MySQL/Postgres/SQLite
¿Has escrito código así? 👇
$verificado = $user->verified ?? false;
$consentimiento = $user->gdpr_consent ?? null;
if ($verificado === true && ($consentimiento === true || $consentimiento === null)) {
// 🐛 ¿Null debería permitir acceso? Bugs esperando para suceder...
}Hay una mejor manera:
// Cristalino - maneja los tres estados
if (and_all($user->verified, $user->consent)) {
// Todos verdaderos - proceder con confianza
}
// Lógica triple en una línea
return pick($subscription->active, 'Premium', 'Gratis', 'Prueba');Resultado: ✨ 80% menos código • 🐛 Cero bugs de null • 🚀 Listo para producción
- ✅ Gestión de Consentimiento GDPR - Aceptar/rechazar/pendiente
- 🚀 Feature Flags - Habilitado/deshabilitado/rollout-gradual
- 🔐 Autenticación Multi-Factor - Verificado/no-verificado/pendiente
- 💳 Detección de Fraude - Seguro/riesgoso/análisis-necesario
- 📝 Formularios Multi-Paso - Completo/incompleto/omitido
- 👥 Sistema de Permisos - Permitir/denegar/heredar
composer require vinkius-labs/trileanUsa inmediatamente - sin configuración:
if (is_true($user->verified)) {
// Usuario verificado
}
echo pick($status, 'Activo', 'Inactivo', 'Pendiente');
// API Fluida
ternary($valor)
->ifTrue('aprobado')
->ifFalse('rechazado')
->ifUnknown('pendiente')
->resolve();
// Helpers de dominio
if (gdpr_can_process($user->marketing_consent)) {
enviarEmailMarketing($user);
}
if (feature('nueva_interfaz', $user->id)) {
return view('app.nueva-interfaz');
}
$nivel = risk_level($puntuacionFraude); // 'bajo', 'medio', 'alto'
// Motor de decisión fluido
$aprobado = decide()
->input('verificado', $user->email_verified)
->input('consentimiento', $user->gdpr_consent)
->and('verificado', 'consentimiento')
->toBool();MIT © Renato Marinho