Argument Resolvers
Wire provides two different autowiring argument resolvers, one for callables like functions, closures, etc and another for constructors. These resolvers are used internally by the creator.
Resolve callable arguments
To create an associative array of callable arguments, create
a CallableResolver
instance using the Wire
factory and pass the callable to
the resolve
method. You can then pass the arguments to the
callable via the ...
operator, for example.
Functions
use Conia\Wire\Wire;
class Value
{
public string $str = 'value property';
}
function readValue(Value $value): string
{
return $value->str;
}
$resolver = Wire::callableResolver();
$args = $resolver->resolve('readValue');
assert(readValue(...$args) === 'value property');
Closures
use Conia\Wire\Wire;
class Value
{
public string $str = 'value property';
}
$closure = function (Value $value): string {
return $value->str;
};
$resolver = Wire::callableResolver();
$args = $resolver->resolve($closure);
assert($closure(...$args) === 'value property');
Instance methods
use Conia\Wire\Wire;
class Value
{
public string $str = 'value property';
}
class Model
{
public function readValue(Value $value): string
{
return $value->str;
}
}
$model = new Model();
$resolver = Wire::callableResolver();
$args = $resolver->resolve([$model, 'readValue']);
assert($model->readValue(...$args) === 'value property');
Static methods
use Conia\Wire\Wire;
class Value
{
public string $str = 'value property';
}
class Model
{
public static function readValue(Value $value): string
{
return $value->str;
}
}
$resolver = Wire::callableResolver();
$args = $resolver->resolve([Model::class, 'readValue']);
assert(Model::readValue(...$args) === 'value property');
Resolve constructor arguments
You simply pass the fully qualified class name to the resolve
method of the
ConstructorResolver
instance created by the Wire
factory:
use Conia\Wire\Wire;
class Value
{
public string $str = 'value property';
}
class Model
{
public function __construct(public Value $value)
{
}
}
$resolver = Wire::constructorResolver();
$args = $resolver->resolve(Model::class);
assert((new Model(...$args))->value->str === 'value property');
Factory methods
If you have a class with a factory method you can use the callable resolver as shown in the static methods example.
Assist resolvers with arguments that are already available
If you have some of the necessary arguments already at hand, you can pass them
converted to an associative array to the resolve
method's predefinedArgs
and/or predefinedTypes
parameters. The array's keys must match the names or types of
the parameters of the callable to be resolved.
For more information, especially the difference between
predefinedArgs
and predefinedTypes
, see Creator
's section about the same
topic,
which works in a similar way.
An example using the callable resolver:
use Conia\Wire\Wire;
class Value
{
public string $str = 'value property';
}
class Model
{
public Value $value;
public string $arg;
public string $type;
public static function create(string $arg, string $type, Value $value)
{
$model = new self();
$model->value = $value;
$model->arg = $arg;
$model->type = $type;
return $model;
}
}
$resolver = Wire::callableResolver();
$args = $resolver->resolve(
[Model::class, 'create'],
predefinedArgs: ['arg' => 'predefined argument'],
predefinedTypes: ['string' => 'predefined type'],
);
$model = Model::create(...$args);
assert($model->value->str === 'value property');
assert($model->arg === 'predefined argument');
assert($model->type === 'predefined type');
The constructor resolver works the same way:
use Conia\Wire\Wire;
class Value
{
public string $str = 'value property';
}
class Model
{
public function __construct(
public string $arg,
public string $type,
public Value $value
) {
}
}
$resolver = Wire::constructorResolver();
$args = $resolver->resolve(
Model::class,
predefinedArgs: ['arg' => 'predefined argument'],
predefinedTypes: ['string' => 'predefined type']
);
$model = new Model(...$args);
assert($model->value->str === 'value property');
assert($model->arg === 'predefined argument');
assert($model->type === 'predefined type');
Using a PSR-11 container
Like the creator, resolvers can be initialized with a container to help with unresolvable parameter arguments. (See also: PSR-11 Containers)
use Conia\Wire\Tests\Fixtures\Container;
use Conia\Wire\Wire;
class Value
{
public function __construct(protected string $str)
{
}
public function get(): string
{
return $this->str;
}
}
class Model
{
public function __construct(protected Value $value)
{
}
public function get(): string
{
return $this->value->get();
}
}
$container = new Container();
$container->add(Value::class, new Value('Model value'));
$resolver = Wire::constructorResolver($container);
$args = $resolver->resolve(Model::class);
assert((new Model(...$args))->get() === 'Model value');
An example using the callable resolver:
use Conia\Wire\Tests\Fixtures\Container;
use Conia\Wire\Wire;
class Value
{
public function __construct(protected string $str)
{
}
public function get(): string
{
return $this->str;
}
}
function readValue(Value $value): string
{
return $value->get();
}
$container = new Container();
$container->add(Value::class, new Value('Model value'));
$resolver = Wire::callableResolver($container);
$args = $resolver->resolve('readValue');
assert(readValue(...$args) === 'Model value');
Creating the resolvers without the Wire
factory
Internally the Wire
factory initializes the resolvers with the creator like shown here:
use Conia\Wire\CallableResolver;
use Conia\Wire\ConstructorResolver;
use Conia\Wire\Creator;
// A PSR-11 container implementation like
// https://conia.dev/registry or https://php-di.org
use Conia\Wire\Tests\Fixtures\Container;
$container = new Container();
$creator = new Creator($container);
$callableresolver = new CallableResolver($creator);
$constructorResolver = new ConstructorResolver($creator);
// Or without container
$creator = new Creator();
$callableresolver = new CallableResolver($creator);
$constructorResolver = new ConstructorResolver($creator);