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 autoload the Webmozart\Assert\Assert facade or class.
First Use Case: Validate constructor arguments in a Laravel model or service:
use Webmozart\Assert\Assert;
class UserService {
public function __construct(private int $maxRetries) {
Assert::integer($maxRetries, 'Max retries must be an integer. Got: %s');
Assert::greaterThan($maxRetries, 0, 'Max retries must be positive. Got: %s');
}
}
Where to Look First:
%s (value), %2$s (additional context like min/max). Example:
Assert::minLength($name, 3, 'Name must be at least %2$s characters. Got: %s');
Workflow:
Assert::isInstanceOf() for type-hinted parameters (redundant but explicit):
public function __construct(private UserRepository $users) {
Assert::isInstanceOf($users, UserRepository::class);
}
Pattern:
Replace Laravel’s FormRequest with lightweight assertions in controllers:
public function store(Request $request) {
Assert::string($request->name, 'Name is required.');
Assert::email($request->email);
Assert::minLength($request->password, 8, 'Password must be 8+ chars.');
// ...
}
Example: UUID Handling
public function findByUuid(string $uuid) {
Assert::uuid($uuid, 'Invalid UUID format.');
// Proceed with DB query...
}
Template:
Assert::string($value, 'Expected %s, got: %s', ['string', gettype($value)]);
Use Case: Override default messages for API responses (e.g., JSON-friendly errors).
ValidatorPattern:
Use assertions in Validator rules for reusable logic:
Validator::extend('custom_rule', function ($attribute, $value, $parameters) {
Assert::string($value);
Assert::minLength($value, 5);
return true;
});
Pattern: Validate test inputs/outputs:
public function testCreateUser() {
$user = new User('invalid@email');
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid email format.');
}
Type Juggling:
Assert::integer() rejects floats (use Assert::integerish() for loose checks).Assert::numeric() allows strings like "123" (be explicit if needed).Resource Assertions:
Assert::resource() requires PHP’s is_resource()—avoid in modern Laravel (use SplFileObject or StreamInterface instead).Performance:
regex(), uuid()) in loops can slow down code. Cache results if reused.Custom Classes:
Assert::isInstanceOf() checks exact class names. For abstract classes, use Assert::isAOf():
Assert::isAOf($value, AbstractModel::class);
Placeholder Order:
%1$s won’t work—use %s (value) and %2$s (context).Silent Failures:
try-catch for graceful degradation:
try {
Assert::email($email);
} catch (InvalidArgumentException $e) {
Log::error($e->getMessage());
return response()->json(['error' => 'Invalid email'], 400);
}
Dynamic Messages:
sprintf-like placeholders for context:
Assert::greaterThan($age, 18, 'Age must be >18. Got: %s (min: 18)');
Testing Assertions:
Assert in unit tests to verify validation paths:
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid format.');
Custom Assertions:
Assert class or create a trait:
trait CustomAssertions {
public static function validSlug(string $slug) {
Assert::string($slug);
Assert::regex($slug, '/^[a-z0-9\-]+$/i');
}
}
Laravel Service Provider:
// app/Providers/AppServiceProvider.php
public function register() {
$this->app->bind('assert', function () {
return new CustomAssertions();
});
}
Integration with Laravel Pipes:
namespace App\Pipes;
use Webmozart\Assert\Assert;
class ValidateUserPipe {
public function handle($request, Closure $next) {
Assert::string($request->name);
return $next($request);
}
}
webmozart/assert has no config file. All behavior is code-driven.Webmozart\Assert\InvalidArgumentException for consistent error handling.Combine Assertions:
Assert::string($value)
->minLength(3)
->maxLength(255);
(Note: Requires a fluent interface wrapper—see this gist for examples.)
Laravel Blade: Use assertions in Blade templates (carefully—avoid performance hits):
@php
use Webmozart\Assert\Assert;
Assert::string($user->name);
@endphp
API Responses: Normalize error messages for APIs:
try {
Assert::email($email);
} catch (InvalidArgumentException $e) {
return response()->json(['errors' => ['email' => $e->getMessage()]]);
}
How can I help you explore Laravel packages today?