wikimedia/assert
A lightweight PHP assertion library from Wikimedia providing methods for parameter type checks, preconditions, postconditions and invariants. Enforce contracts and validate input in MediaWiki-style projects with clear, descriptive exceptions and no extra dependencies.
wikimedia/assert is a tiny, dependency-free library that gives you a static Wikimedia\Assert\Assert facade for fail-fast precondition/postcondition checks. It is the assertion utility extracted from MediaWiki core and is used across the MediaWiki extension ecosystem.
Install and get the first call working:
composer require wikimedia/assert
use Wikimedia\Assert\Assert;
function greet( $name ) {
Assert::parameterType( 'string', $name, '$name' );
return "Hello, {$name}";
}
Where to look first:
README.md — short, describes the intent and the type-string syntax.src/Assert.php — the entire public API surface; read it in five minutes. The interesting methods are parameterType(), parameter(), precondition(), postcondition(), and invariant().src/AssertException.php — the exception type thrown on failure; check its parent class so you know what catch blocks will also swallow it.First real use case: guard the boundary of a service or value object — constructor arguments, public method parameters, and internal invariants — so that a bad call fails immediately with a message naming the offending parameter, instead of producing a confusing TypeError or a corrupted object three call frames later.
class Money {
private $amount;
private $currency;
public function __construct( $amount, string $currency ) {
Assert::parameterType( 'integer|float', $amount, '$amount' );
Assert::parameterType( 'string', $currency, '$currency' );
Assert::parameter( $currency !== '', '$currency', 'must not be empty' );
$this->amount = $amount;
$this->currency = $currency;
}
}
Guard clauses at the top of public methods. Treat Assert like executable PHPDoc. It complements native type hints where they are too weak (array element types, union values, non-empty strings), and it documents intent for the next reader.
public function addUsers( array $users ) {
Assert::parameterType( 'string[]', $users, '$users' );
Assert::precondition( count( $users ) > 0, 'user list must not be empty' );
// ...
}
The type-string DSL. The parameter type is a string, not a callable, and it supports a small grammar:
string, integer, float, boolean, array, callable, object, resource, null, mixed.'My\\Namespace\\Foo', 'Psr\\Log\\LoggerInterface'.[] suffix: 'string[]', 'integer[]', 'Foo[]'.|: 'string|false', 'integer|float', 'Foo|Bar'.Use Assert::parameterElementType() when you only need to validate the array's contents and want the failure message to point at the element type rather than the whole array.
Separate the three assertion kinds. This is the pattern MediaWiki contributors follow and it keeps the checks meaningful:
precondition() — what must be true on entry to a method (caller's responsibility).postcondition() — what the method guarantees on exit (callee's responsibility).invariant() — what must remain true across a loop or state transition.Using the right kind makes the resulting exception message readable and tells a debugger whose bug it is.
Convert at the edges. AssertException is a programmer-error signal (a 500, not a 400). At the boundary of your application — an HTTP controller, a queue consumer, a CLI command — let it propagate, or catch it and rethrow a domain exception so your error handler can tag it as a bug:
try {
$service->process( $payload );
} catch ( AssertException $e ) {
throw new LogicException( 'Contract violation in ProcessService', 0, $e );
}
Inside the service, never catch it. Catching an assertion locally defeats the fail-fast purpose.
Use it in tests to fail loudly. Wrapping fixture setup in Assert::precondition() gives you a clear message when a test's assumptions break, rather than a null-property error deep in the subject under test. It also pairs well with expectException( AssertException::class ) when you are deliberately testing the guard itself.
Prefer it over assert(). PHP's built-in assert() is compiled out when zend.assertions=-1 (the production default), so it silently does nothing in the environment where you most need a stack trace. wikimedia/assert always throws, which is both the feature and the cost you need to budget for.
$_POST, query params, or JSON payloads. It throws programmer-facing exceptions with developer messages; use a validator (or explicit checks returning user-facing errors) for untrusted data, then assert the normalized result internally.[] suffix, and a class name must match the runtime instanceof check exactly (leading backslashes and case matter). A wrong type string fails the assertion at runtime, not at parse time, so it is easy to get wrong and easy to miss until that code path executes.AssertException extends a standard SPL exception (verify the parent in src/AssertException.php). If it extends InvalidArgumentException or LogicException, existing catch blocks in your codebase may already be swallowing it — a real hazard when adding assertions to legacy code. Add the assertions, then run the test suite and watch for behavior changes in broad catch handlers.$. Assert::parameterType( 'string', $x, '$x' ) produces a message that reads like source code. Omitting the sigil makes trace output ambiguous.if ( $x ) { ... } is not an assertion. Assert::precondition() documents a contract; using it to branch on user state is a code smell that confuses error handling.Assert is a static facade and is not designed for injection, logging, or custom exception types. If you need to report assertion failures to an error tracker or swap behavior in tests, wrap it in your own thin assert helper class rather than calling Wikimedia\Assert\Assert directly everywhere.composer.json and read the changelog before upgrading; the API is stable but the release cadence is not.wikimedia/assert is already a transitive dependency — do not re-bundle it, and follow core's convention of using it for parameter contracts rather than the PHP assert() function.How can I help you explore Laravel packages today?