Skip to content
This repository has been archived by the owner on Sep 12, 2023. It is now read-only.

shrink/examples

Repository files navigation

Examples

Packagist

Compose example objects.

use Shrink\Examples\E;
use Shrink\Examples\Examples;

final class Person
{
  public function __construct(
    public readonly string $name,
    public readonly int $age
  ) {
  }
}

$examplePersonDefinition = E::define(Person::class, name: "Alice", age: 30);

($examples = new Examples())->register($examplePersonDefinition);

$person = $examples->make(E::g(Person::class, name: "Bob"));

self::assertSame(
  "Hello, Bob (age 30).",
  "Hello, {$person->name} (age {$person->age})."
);

Usage

  1. Install the library with composer
  2. Define examples
  3. Make objects

Install

dev:~$ composer require shrink/examples --dev

🧢 The latest version of Examples requires PHP 8.1, use Examples v1 for PHP 7.4 and PHP 8.0 support.

Instantiate Examples

An Examples::class instance holds your example definitions and creates your objects from these definitions.

use Shrink\Examples\Examples;

$examples = new Examples();

Define Examples

The E::define() method accepts a class type and zero or more named arguments, which map to the type's constructor arguments. E::define() returns a definition to register with your instance of Examples.

use Shrink\Examples\E;

$examples->register(E::define(Person::class, name: "Alice", age: 30));

✨ Since v2, named arguments are used instead of a parameters array.

🧬 E::define() is a shortcut to create a simple example definition, see Internals -> Definition for building your own implementation.

Make An Object

The E::g() method accepts a class type (referring to a registered example) and zero or more named arguments to overwrite the example defaults. E::g() returns an example configuration, which your instance of Examples will make().

use Shrink\Examples\E;

$example = $examples->make(E::g(Person::class, name: "Bob"));

echo "Hello, {$example->name} (age {$example->age}).";
// Hello, Bob (age 30).

🧬 E::g() is a shortcut to create a simple example configuration, see Internals -> Creation for building your own implementation.

Features

Nested Examples

Examples::class will resolve any example definitions it encounters when making an example, allowing for many levels of nested example definitions and configuration.

final class Person
{
  public function __construct(
    public readonly string $name,
    public readonly int $age,
    public readonly ?Location $location
  ) {
  }
}

final class Location
{
  public function __construct(
    public readonly string $streetAddress,
    public readonly string $country
  ) {
  }
}

$examples = new Examples();

$examples->register(
  E::define(
    Location::class,
    streetAddress: "123 Default Street",
    country: "England"
  )
);

$examples->register(
  E::define(
    Person::class,
    name: "Alice",
    age: 30,
    location: E::g(Location::class, country: "United States")
  )
);

$person = $examples->make(
  E::g(
    Person::class,
    name: "Bob",
    location: E::g(Location::class, country: "The Netherlands")
  )
);

self::assertSame(
  "Hello, {$person->name} (age {$person->age}) from {$person->location->country}.",
  "Hello, Bob (age 30) from The Netherlands."
);

Internals

Definition

Examples are registered using an example definition (DefinesExample) which in turn uses a builder (BuildsExampleInstances) to create an object using optional configuration.

use Shrink\Examples\Definition;
use Shrink\Examples\Examples;
use Shrink\Examples\Example;

$examples = new Examples();

$examples->register(new Definition(
    Person::class,
    BuildsExampleInstances $builder,
    array $defaults
));

$person = $examples->make(new Example(
    Person::class,
    array $parameters
));

Implicit instance building is handled through Reflection by ReflectionBuilder which accepts a class name to build.

use Shrink\Examples\Definition;
use Shrink\Examples\ReflectionBuilder;

$examples->register(
  new Definition(Person::class, new ReflectionBuilder(Person::class), [
    "name" => "Alice",
    "age" => 30,
  ])
);

E::define() is a shortcut for creating an example definition with implicit building. Explicit instance building is handled by providing a callable which is called with the Example parameters as method parameters.

use Shrink\Examples\CallableBuilder;
use Shrink\Examples\Definition;

$examples->register(
  new Definition(
    Person::class,
    new CallableBuilder(
      fn(string $name, int $age): Person => new Person($name, $age)
    ),
    [
      "name" => "Alice",
      "age" => 30,
    ]
  )
);

Creation

Objects are made, from an example, with an optional configuration of parameters. Ask the Examples instance to make(ConfiguresExample $configuration). A default implementation of ConfiguresExample is included which is constructed with the type and parameters.

use Shrink\Examples\Example;

$person = $examples->make(new Example(Person::class));

Parameters may be provided to overwrite any defaults.

use Shrink\Examples\Example;

$person = $examples->make(
  new Example(Person::class, [
    "name" => "Alice",
  ])
);

License

Examples is open-sourced software licensed under the MIT license.