hamcrest/hamcrest-php
Official PHP port of Hamcrest matchers for expressive assertions in tests. Use MatcherAssert::assertThat() or convenient global functions (assertThat, equalTo, is, both/andAlso, either/orElse) to build readable, composable matchers with PHP-friendly typing.
Start by installing via Composer:
composer require --dev hamcrest/hamcrest-php
Hamcrest integrates directly with PHPUnit—no additional setup is required. In your tests, import matchers via the Hamcrest\Matchers namespace or use PHPUnit's built-in shortcuts (e.g., assertThat(), equalTo(), arrayHasKey()). For your first use case, replace verbose assertions like:
$this->assertTrue(in_array('foo', $items) && count($items) > 0);
with intent-clear Hamcrest syntax:
$this->assertThat($items, both(isArray())->and(hasItem('foo')));
Begin with built-in matchers in Hamcrest\Matchers—prioritize equalTo(), isEmpty(), arrayHasKey(), stringContains(), and anything().
Note for PHP 8.5+ users: Version 3.0.0 introduces native type hints across all Hamcrest classes (e.g., describeMismatch(mixed $item): void), eliminating legacy null return type ambiguities. No code changes are needed for basic usage, but custom matchers should now explicitly declare return types (e.g., public function matches(mixed $item): bool).
Chain matchers for complex conditions:
$this->assertThat($user->getEmail(), allOf(
notNullValue(),
stringContains('@'),
endsWith('.com')
));
Extend Hamcrest\Core\Matcher with strict typing (PHP 8.5+):
class HasValidId extends Matcher {
public function matches(mixed $item): bool { /* ... */ }
public function describeTo(Description $description): void { /* ... */ }
public function describeMismatch(mixed $item, Description $description): void { /* ... */ }
}
Leverage assertThat() with Hamcrest’s expressive matchers:
$this->assertThat($result, arrayWithKey('data'));
$this->assertThat($result['data'], equalTo(['id' => 42]));
Use throws() for expressive exception assertions:
$this->assertThat(fn() => $service->process(), throws(\InvalidArgumentException::class));
Explicitly type method parameters/returns in custom matchers:
public function matches(mixed $item): bool { /* ... */ }
public function describeMismatch(?object $item, Description $description): void { /* ... */ }
mixed for dynamic inputs). Custom matchers should mirror this to avoid runtime deprecation warnings.hasItem() remain O(n) for arrays. For large datasets, pre-filter collections or use arrayHasKey() where applicable.describeMismatch() is now more reliable with PHP 8.5’s type system. Test edge cases to verify custom mismatch descriptions.use Hamcrest\* imports—explicitly import matchers (e.g., use Hamcrest\Matchers\ArrayMatchers) to prevent collisions with Laravel/PHPUnit helpers.mixed or ?Type to align with Hamcrest’s new type hints.--strict-types to catch type-related issues early. Example:
phpunit --strict-types
How can I help you explore Laravel packages today?