Arg
Rasuvaeff\Understudy\Arg
Class — Package: rasuvaeff/understudy — Source — Version: v0.4.1
Argument matchers, usable only inside a specification closure:
when(fn () => $repository->find(Arg::any()))->returns($book);Every matcher is declared to return mixed rather than the internal ArgumentMatcher type. That is not vagueness — it is what the matcher means. A matcher stands in for a value of whatever type the parameter declares, and it is never consumed as a value: the runtime intercepts it while recording the call specification. Declaring the concrete class instead would make find(Arg::any()) a type error in every IDE and analyser for a contract that says find(int $id), on the first line of the first example anyone copies — while mixed is accepted everywhere and stays honest.
understudy-psalm narrows this to the parameter's declared type, so users of the plugin get a real check rather than mixed.
Methods
any()
static any(): mixedMatches any argument, including null.
int()
static int(?int $min = NULL, ?int $max = NULL): mixedMatches an int, optionally within bounds. A numeric string does not match: the matcher pins the declared type as well as the value.
float()
static float(?float $min = NULL, ?float $max = NULL): mixedMatches a float, optionally within bounds. An int does not match.
string()
static string(non-empty-string|null $matches = NULL): mixedMatches a string, optionally against a PCRE pattern.
$matches— delimiters included, e.g./^ord-/
bool()
static bool(): mixedsame()
static same(mixed $value): mixedStrict identity — for objects, the very same instance.
not()
static not(mixed $value): mixedNegates a literal or another matcher: not(5), not(Arg::instanceOf(…)).
allOf()
static allOf(mixed $operands): mixedMatches an argument every operand accepts. An operand is a matcher or a literal, the same pair not() takes.
$operands— at least one; a tail matcher is not one of them
anyOf()
static anyOf(mixed $operands): mixedMatches an argument at least one operand accepts. With literals it reads as a set: anyOf('draft', 'review').
$operands— at least one; a tail matcher is not one of them
instanceOf()
static instanceOf(class-string $type): mixedcaptor()
static captor(class-string<\T>|null $class = NULL): CaptorA typed argument captor. Its capture() goes where the argument to observe goes, matches like instanceOf() — or like any() for the untyped form — and records the value once the whole specification matched:
$options = Arg::captor(DeliveryOptions::class);
when(fn () => $store->temporaryUrl(Arg::any(), Arg::any(), $options->capture()))
->returns('https://…');
$subject->run();
$options->last(); // DeliveryOptions, typed
$options->all(); // list<DeliveryOptions>, in call orderThe typed replacement for reading args[N] out of the call log: last() and all() carry the class through, so no instanceof narrowing ritual is needed at the read site.
satisfies()
static satisfies(
callable $predicate,
non-empty-string $description = 'satisfies(…)',
): mixedMatches whatever the predicate accepts.
$description— shown in failure messages
containing()
static containing(array<array-key,mixed> $entries): mixedMatches an array containing these entries and possibly more: a list by value, a map by key and value.
count()
static count(int<0, max>|null $minimum = NULL, int<0, max>|null $maximum = NULL): mixedMatches an array or Countable whose size is within bounds.
which()
static which(non-empty-string $method, mixed $value): mixedMatches an object whose getter answers this value.
$method— public, non-static, no required arguments
none()
static none(): mixedRequires the variadic tail to be empty. Only valid as the last argument.
remaining()
static remaining(): mixedMatches the whole variadic tail, of any length including none. Only valid as the last argument.
rest()
static rest(): mixed"The arguments before this one matter, the rest of the arity does not." Only valid as the last argument, and the one matcher that lets a specification stop before the method's required parameters run out:
when(fn () => $storage->recordOutcome('svc', Arg::rest()))
->throws(new RuntimeException('storage unavailable'));The distinction from remaining(): remaining() stands for the variadic tail a method declares; rest() stands for declared parameters the specification chose not to spell out. A later, narrower specification for the same call still wins over the broad prefix stub, the way overlapping matchers already compose.