factory icon indicating copy to clipboard operation
factory copied to clipboard

More comfortable way to create an object using a factory

Open Tigrov opened this issue 1 year ago • 10 comments

$factory->create(EngineInterface::class, 146);

instead of

$factory->create([
    'class' => EngineInterface::class,
    '__construct()' => [
        'power' => 146,
    ],
]);

Tigrov avatar Mar 27 '24 12:03 Tigrov

https://github.com/yiisoft/factory/blob/master/src/Factory.php#L102

As I can see it's almost possible now to create a class with only class reference, but the rest params must be two arrays:

  1. params for constructor method
  2. the rest configuration of methods calls and etc

So I'd suggest to make it possible to use add a few options params and the merge it into another one so it can convert into the original structure:

$f->create(MyClass::class, ['userId' => 5], ['setUserId()' => [5]]);

function create(mixed $config); // before

function create(mixed $config, array $constructor = [], array $restConfig = []) // after
{
  if (is_string($config) && !empty($constructor) && !empty($restConfig)) {
    $config = ['__class' => $config, ...array_merge($restConfig, ['__construct()' => $constructor])];
  }
  ... // original function body
}

xepozz avatar Mar 29 '24 16:03 xepozz

As we create a concrete instance, no need to pass ['setUserId()' => [5]].

I'd preffer this way:

$obj = $f->create(MyClass::class, userId: 5);
$obj->setUserId(10);

function create(mixed $config, mixed ...$constructor)
{
    ...
}

Tigrov avatar Mar 31 '24 08:03 Tigrov

Agree with @Tigrov. For rest configuration better use PHP syntax.

The only doubt is, is there a case when the rest configuration passed as array? (I think, that no...)

vjik avatar Mar 31 '24 09:03 vjik

It's not convenient to mix array- and callable- like configurations and use it together. As Factory can make necessary calls it must do it.

xepozz avatar Mar 31 '24 12:03 xepozz

If you want to pass rest configuration, you can use as it is now

$factory->create([
    'class' => EngineInterface::class,
    '__construct()' => [
        'power' => 146,
    ],
    'setUserId()' => [5],
]);

Or

$factory->create([
    'class' => EngineInterface::class,
    'setUserId()' => [5],
], power: 146);

Tigrov avatar Mar 31 '24 13:03 Tigrov

For sure. But the issue is about to make factory flexible for creating objects by instructions.

I don't like various parameters for constructors at all. It would just make the method unavailable for further modifications, as we have now: create($config) -> create($config, $constructor) -> create($config, $constructor, $rest) -> create($config, $constructor, $rest, $flags) and so on. Let's stop propagate this way?

xepozz avatar Mar 31 '24 14:03 xepozz

$factory->create([
    'class' => EngineInterface::class,
    'setUserId()' => [5],
], power: 146);

I don't like this way, because it requires merge constructor arguments when config also contain them.

vjik avatar Mar 31 '24 14:03 vjik

May be create separate method with suggested syntax?

vjik avatar Mar 31 '24 14:03 vjik

it requires merge constructor arguments when config also contain them.

I don't see anything wrong with this.

May be create separate method with suggested syntax?

Maybe

Tigrov avatar Apr 01 '24 03:04 Tigrov

May be create separate method with suggested syntax?

Yes. That's better. When designing the syntax, we've tried mixing formats in the same call, but then dropped it completely. Merging these was creating hell.

samdark avatar Apr 02 '24 21:04 samdark