Skip to content

ClassArbitrary ​

Rasuvaeff\PropertyTesting\Arbitrary\ClassArbitrary

Class — Package: property-testing-core — Source — Version: v1.0.0-1-g88fdee2

Implements: ArbitraryInterface

Type parameters:

  • TValue of object = mixed

Instances of a class, generated from what its constructor already declares.

PHP has no macros, so this is reflection — but in a codebase with promoted constructor properties and psalm annotations, the information a derive(Arbitrary) macro would need is already written down and currently goes to waste. A parameter typed int<0, 100> describes its value space exactly; guessing int there and letting the constructor reject four generated values in five is the difference between a usable generator and a demo.

php
Gen::forClass(Money::class);
Gen::forClass(Money::class, ['amount' => Gen::intPositive()]);   // override one parameter

Types are read in this order, per parameter: an explicit override, then the docblock (psalm subset — int<0, 100>, positive-int, non-empty-string, list<T>, array<K, V>, 'a'|'b', ?T, unions), then the native type — a bare float meaning floatBetween(-1e6, 1e6). The docblock is read in the three spellings psalm and PHPStan accept: @psalm-param / @phpstan-param win over @param, and a @var on the promoted property itself counts when the constructor's docblock says nothing about that parameter. Anything it cannot read is an exception naming the parameter, never a widened guess: a generator that does not match the domain turns into somebody else's failing test.

A validating constructor is not a special case. Constructors in this family reject bad input, and by default a rejection propagates — it says the generator does not match the domain, and an override or a narrower annotation is the fix. skipInvalid: true is the deliberate opposite: the value is discarded and redrawn, up to Arbitrary\MAX_ATTEMPTS times, exactly as Gen::filter() does. Only exceptions are discarded, never Errors: a TypeError means the generator produced the wrong type, which is a bug rather than a rejected value.

Constructor ​

php
__construct(
    class-string<\Arbitrary\TValue> $class,
    array<string,\ArbitraryInterface> $overrides = [],
    bool $skipInvalid = false,
    int $maxDepth = 3,
)
ParameterTypeDefaultDescription
$classclass-string<\Arbitrary\TValue>requiredThe class to instantiate. Must be concrete and constructible.
$overridesarray<string,\ArbitraryInterface>[]Generators by constructor parameter name, winning over anything the parameter declares. The way to narrow a value space the type cannot express, and to break a recursion this cannot.
$skipInvalidboolfalseWhether a constructor that rejects a generated value discards it and redraws instead of failing the run.
$maxDepthint3How deep to follow class-typed parameters before refusing. Cycles are an error rather than a hang, and the message names the chain.

Methods ​

generate() ​

php
generate(\Random $random): Shrinkable

Produce one random value from this arbitrary's space, together with its shrink tree. Candidates must be ordered most aggressive first (typically toward a zero/empty/identity element) and every branch of the tree must be finite, so shrinking terminates.

Documentation inherited from ArbitraryInterface.

  • $random — The run's source of randomness, threaded through every parameter's generator.