beberlei/assert
Lightweight assertion library for validating method arguments and input data in PHP. Provides a fluent, readable API with many built-in rules (string, numeric, email, UUID, collection, etc.), clear exceptions, and easy extensibility for custom constraints.
Install via Composer: composer require beberlei/assert.
Start by validating method arguments at the boundary of your services or domain logic—especially in value objects, DTOs, or service methods where inputs must conform to strict contracts. For example:
use function BeberleiAssert\assert;
public function transfer(float $amount, Account $toAccount): void
{
assert::float($amount, 'Transfer amount must be a float');
assert::greaterThan($amount, 0, 'Transfer amount must be positive');
assert::notNull($toAccount, 'Target account cannot be null');
// ... rest of logic
}
The first use case is typically replacing verbose if (!condition) throw new Exception(...) blocks with expressive one-liners.
DTO & Value Object Validation: Enforce invariants inside constructors or static factory methods:
class Money
{
private function __construct(private float $amount, private string $currency) {}
public static function create(float $amount, string $currency): self
{
assert::greaterThan($amount, 0);
assert::length($currency, 3, 'Currency must be ISO 3-letter code');
return new self($amount, $currency);
}
}
Request Validation Layer: Use assertions in Laravel form requests or service classes before dispatching to domain logic—especially when dealing with non-validated external data (e.g., APIs, queues):
$payload = json_decode($request->getContent(), true);
assert::keyExists($payload, 'user_id');
assert::integer($payload['user_id']);
Collection & Array Validation: Validate nested structures with all() and subclassOf():
assert::all('is_int', $ids);
assert::subclassOf($users, User::class); // for arrays of objects
Custom Assertion Extensions: Define reusable predicates via Callback or subclassing:
$isVatRegistered = assert::callback(fn($code) => strlen($code) === 11 && starts_with($code, 'GB'), 'Invalid VAT number');
Integration with Laravel: Wrap assertions in custom Rule classes or service providers for app-wide consistency.
Namespace collision: The package uses assert as a function name—ensure assert() calls aren’t shadowed. Use use function BeberleiAssert\assert; or assert\assert() alias if needed.
Performance impact: While lightweight, avoid assertions in hot paths (e.g., inner loops processing thousands of items). Wrap in if (self::ASSERT_RUNTIME) checks in production-critical code.
Exception types: Throws BeberleiAssert\AssertException by default. You can map these to your own exceptions via custom AssertionFailed handler (e.g., in a Laravel middleware or custom wrapper).
Lazy error messages: Pass closures for expensive messages to avoid unnecessary work:
assert::greaterThan($balance, 0, fn() => "Balance {$balance} is negative for user #{$userId}");
No native Laravel validation integration: Unlike Validator, this is not for HTTP request rules. Use it alongside—inside Laravel’s validation layer, not as a replacement—for domain-level guarantees.
Type coercion awareness: Assertions like integer() cast strings to integers before validating. Prefer strict checks (integerStrict()) where behavior depends on exact types (e.g., API params).
How can I help you explore Laravel packages today?