# beberlei/assert: guard clauses for PHP business models

> A thin PHP assertion library that replaces if-clauses with guard methods and throws on failure. It suits library authors and domain code that validate input at the boundary, not form-heavy applications that need translated messages.

**beberlei/assert** — Thin assertion library for use in libraries and business-model

- Repository: https://github.com/beberlei/assert
- Stars: 2,433 · Forks: 186
- Language: PHP
- License: NOASSERTION
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/beberlei-assert

## The problem beberlei/assert removes from model code

Domain code and library entry points tend to accumulate the same shape of check before any real work starts: is this string non-empty, is this value an integer, does this file exist. Written by hand, each check costs an if-clause, a return path or a thrown exception, and the branches multiply. The README frames the goal as reducing the amount of code for implementing assertions and simplifying the code paths, so that a failed assertion throws instead of leaving an if-clause behind.

The audience is narrow on purpose. The README says the library is for input validation, not filtering, in business-model code, libraries and application low-level code, and that it can express pre- and post-conditions on input data. That is a different job from validating an HTTP form payload and rendering field-by-field errors to a user. If your validation output has to be translated, this is not the tool the README is describing.

## Why the library avoids Symfony and Zend Validators

The README gives an explicit reason for not building on existing validator components: the checks have to be low-level, fast, non-object-oriented code. Using Symfony or Zend Validators, it argues, requires instantiating several objects and pulling in a locale component and translations, which it calls too much bloat for this purpose.

That is a design trade-off, and it cuts both ways. You get static calls that can be dropped into any function without wiring a container or a validator service. You give up the message infrastructure those components bring. There is no catalogue of translated failure messages here; the second argument to most assertions is a plain string you write yourself, as the Azure Blob Storage example in the README shows with calls like Assertion::notEmpty($containerName, 'Container name is not specified').

## Installing beberlei/assert and writing a first guard

Installation goes through Composer. The README gives a single command, and it pulls the package from Packagist under the name beberlei/assert:

```bash
composer require beberlei/assert
```

The README's own example wraps a function in guards before doing any work. The assertions run first, and any failure throws before the loop is reached, so the body of the function stays free of validation branches:

```php
<?php
use Assert\Assertion;

function duplicateFile($file, $times)
{
    Assertion::file($file);
    Assertion::digit($times);

    for ($i = 0; $i < $times; $i++) {
        copy($file, $file . $i);
    }
}
```

Calling duplicateFile with a path that is not a file throws from Assertion::file, and a non-digit $times throws from Assertion::digit. When the value may legitimately be null, the README documents a nullOr prefix that accepts null or applies the assertion: Assertion::nullOrMax(null, 42) and Assertion::nullOrMax(1, 42) both succeed, while Assertion::nullOrMax(1337, 42) throws. The all prefix does the same across a collection, so Assertion::allIsInstanceOf(array(new \stdClass, new \stdClass), 'stdClass') passes and the same call against 'PDO' throws.

## Assert::that() chaining and lazy assertions for form-shaped input

Static calls get verbose when one value has to satisfy several rules. From version 2.6.7, the README states, the Assert class offers a fluent API that takes the value once. Assert::that($value)->notEmpty()->integer() checks both conditions on the same value, and Assert::that($values)->all()->float() applies the float check across a collection. Shortcuts Assert::thatNullOr() and Assert::thatAll() cover the nullOr and all cases.

Lazy assertions address the opposite problem: you want every failure, not the first one. The chain collects errors and only throws when verifyNow() is called, and each that() call takes a property path so failures can be told apart:

```php
Assert::lazy()
    ->that(10, 'foo')->string()
    ->that(null, 'bar')->notEmpty()
    ->that('string', 'baz')->isArray()
    ->verifyNow();
```

On failure verifyNow() throws Assert\LazyAssertionException with a combined message listing each failed assertion by its property path, as the README shows in its three-line example. The individual AssertionFailedExceptions are available through getErrorExceptions(), which the README suggests using to build a failure response. For several failures on one value, tryAll() runs all assertions against that value instead of stopping at the first; the README notes that placing tryAll() directly after Assert::lazy() applies the behaviour to the whole chain.

## Where beberlei/assert is the wrong tool

The README draws the boundary itself: this is input validation, not filtering. Nothing here sanitises a value, strips tags, or converts a string to an integer for you. A guard that passes means the value satisfied the check, not that the value is now safe to use in a query.

The message story is the second limit. Because the library deliberately avoids locale and translation components, the failure strings are whatever you pass in. A web form that must show localised errors per field will end up rebuilding the translation layer the README chose to leave out, or mapping AssertionFailedException instances onto its own error structure. The README does not document a message catalogue, a translator hook, or a locale-aware formatter, so anyone expecting one should treat its absence as the design, not an oversight. There is also no documented behaviour for collecting errors across separate lazy chains; verifyNow() is the point at which the exception is raised.

## How this differs from a full validator component

Symfony Validator and Zend Validator are the alternatives the README names, and the difference is architectural rather than cosmetic. Those components model validation as objects: a constraint, a validator, a context, a message catalogue, and a locale. That structure pays for itself when validation rules come from configuration or annotations and when messages must be translated.

beberlei/assert goes the other way. The checks are static method calls on values, with no constraint objects and no locale component, which is what makes them usable inside a domain method that has no container and no configuration. The cost is that rule sets are code, not data. If you need to define a rule set once and reuse it across forms, or render messages in several languages, the object-oriented components are the better fit, and the README's own reasoning for avoiding them is exactly the reason they are the wrong comparison here.

## Maintenance, upgrades and the licence question

The repository is not archived, and the last push was on 2026-06-10, the same day as the v3.3.4 release. The release history shows the cadence is uneven rather than continuous: v3.3.3 landed on 2024-10-30 and v3.3.2 on 2021-12-17, so two and a half years separate v3.3.2 from v3.3.3. A dependency on this package will not see frequent version bumps, which is fine for a small assertion surface but means new features should not be expected on a schedule.

The repository root contains a CHANGELOG.md, which is where the changes between v3.3.3 and v3.3.4 are recorded; the README does not describe the upgrade path or any backward-incompatible changes. On licensing, the metadata reports NOASSERTION and the README does not state a licence, while a LICENSE file exists at the repository root. Read that file directly to determine the terms that apply to your use; nothing in the README substitutes for it.

## Conclusion

Adopt beberlei/assert in PHP libraries and domain models where a failed precondition should abort with an exception and the message is for developers, not end users. Skip it if you need locale-aware, translated validation messages for form input, since the README states the library deliberately avoids Symfony and Zend Validators and their locale and translation components. Before committing, read the LICENSE file in the repository root, because the metadata reports the licence as NOASSERTION and the README does not name a licence, then check CHANGELOG.md for what changed between v3.3.3 and v3.3.4.

## FAQ

### How do I install beberlei/assert?

The README gives one command, composer require beberlei/assert, which installs the package from Packagist. There are no other installation steps documented.

### How do I use beberlei/assert in PHP code?

You call static methods on Assert\Assertion, such as Assertion::file($file) and Assertion::digit($times), and a failed check throws an exception instead of returning a boolean. For several rules on one value, the README documents the fluent Assert::that($value)->notEmpty()->integer() form.

### What is the difference between Assert::that() and lazy assertions in beberlei/assert?

Assert::that() throws as soon as an assertion fails, while the lazy API collects errors and only throws when verifyNow() is called. The README states that lazy chains require a property path on each that() call so failures can be told apart, and that verifyNow() throws Assert\LazyAssertionException with a combined message.

### Does beberlei/assert filter or sanitise input values?

No. The README describes the library as containing assertions and guard methods for input validation, not filtering, and says a failed assertion throws an exception. Passing a guard means the value satisfied the check, not that it was cleaned.

### What licence does beberlei/assert use?

The README does not state a licence, and the repository metadata reports it as NOASSERTION. A LICENSE file exists at the repository root, so read that file to determine the terms.

## Sources

- [beberlei/assert on GitHub](https://github.com/beberlei/assert)
- [Issues](https://github.com/beberlei/assert/issues)
- [README](https://github.com/beberlei/assert/blob/master/README.md)
- [Releases](https://github.com/beberlei/assert/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/beberlei-assert
