webmozart/assert
Lightweight PHP assertion library for validating method input/output. Provides fast, readable checks via Webmozart\Assert\Assert with consistent error-message placeholders, throwing InvalidArgumentException on failure. Ideal for safer, less repetitive validation code.
Installation:
composer require webmozart/assert
No additional configuration is required—just import the Assert class.
First Use Case: Validate constructor parameters or method inputs in a Laravel service/class:
use Webmozart\Assert\Assert;
class UserService {
public function __construct(private string $apiKey) {
Assert::stringNotEmpty($this->apiKey, 'API key must be a non-empty string');
}
}
Where to Look First:
%s (value), %2$s (additional params) for custom error messages.stringNotEmpty() over string() + empty() checks.Pattern: Validate all constructor dependencies upfront.
class OrderProcessor {
public function __construct(
private string $orderId,
private array $items,
private ?int $discount = null
) {
Assert::uuid($orderId, 'Order ID must be a valid UUID');
Assert::isNonEmptyList($items, 'Order must have items');
Assert::greaterThanEq($discount ?? 0, 0, 'Discount cannot be negative');
}
}
Pattern: Use assertions in setter methods or public APIs.
class UserRepository {
public function updateEmail(string $userId, string $email): void {
Assert::uuid($userId, 'Invalid user ID');
Assert::email($email, 'Invalid email format');
// Proceed with DB update...
}
}
Pattern: Reuse base messages with placeholders for consistency.
// Reusable message for type checks
const MESSAGE_INVALID_TYPE = 'Expected %s, got %s';
Assert::string($value, sprintf(MESSAGE_INVALID_TYPE, 'string', gettype($value)));
Pattern: Combine with Laravel’s validation or form requests.
// In a Form Request
public function rules(): array {
return ['email' => 'required|email'];
}
public function withValidator($validator) {
$validator->after(function ($validator) {
Assert::email($this->email, 'Custom error: Invalid email');
});
}
Pattern: Extend assertions for business logic (e.g., Assert::validStatus()).
class OrderAssertions {
public static function validStatus(string $status): void {
Assert::oneOf($status, ['pending', 'shipped', 'cancelled'],
'Invalid order status: %s');
}
}
Pattern: Use assertions in unit tests to validate outputs.
public function testCalculateDiscount() {
$discount = $this->service->calculateDiscount(100, 0.2);
Assert::greaterThan($discount, 0, 'Discount must be positive');
Assert::lessThan($discount, 100, 'Discount cannot exceed total');
}
Performance Overhead:
classExists() for static checks).Placeholder Order:
%s is always the tested value. Additional placeholders (e.g., %2$s for ranges) vary by method.// Wrong: %2$s appears before %s
Assert::range($age, 18, 65, 'Age must be between %2$s and %s');
Type Casting:
integerish() casts strings like "123" to integers but fails for "abc".integer() if you need strict integer types.Resource Assertions:
resource() checks require PHP’s is_resource() (deprecated in PHP 8.1+).GuzzleHttp\Psr7\StreamInterface or similar for HTTP resources.Laravel-Specific:
Custom Exceptions:
Webmozart\Assert\InvalidArgumentException for graceful handling:
try {
Assert::email($email);
} catch (InvalidArgumentException $e) {
return back()->withErrors(['email' => $e->getMessage()]);
}
Assertion Chaining:
Assert::all(
[$id, $name, $email],
fn ($value) => Assert::notEmpty($value, 'Field cannot be empty')
);
Dynamic Messages:
sprintf for dynamic values in messages:
Assert::minLength($password, 8,
'Password must be at least %d characters (got %s)');
Testing Edge Cases:
null, empty strings, false, 0.Assert::unicodeLetters()).Assert::range($value, 0, 1) with $value = 0 or 1).Custom Assertions:
Assert class or create static methods:
class AppAssert extends Assert {
public static function validPhone(string $phone): void {
Assert::regex($phone, '/^\+?[0-9]{10,15}$/', 'Invalid phone format');
}
}
Integration with Laravel:
Assert::macro('validModelId', function ($id, $modelClass) {
Assert::uuid($id);
Assert::notNull($modelClass::find($id), 'Model not found');
});
Performance Optimization:
Assert::that() with a closure:
Assert::that($user->role, fn ($role) =>
Assert::oneOf($role, ['admin', 'editor', 'user'])
);
Localization:
trans() helper:
Assert::string($name, trans('validation.string', ['attribute' => 'name']));
How can I help you explore Laravel packages today?