Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

orest's avatar
Level 13

factory that depends on request parameters

Given that I have a factory class that create fruits based on a request parameter.

Should the client know the exact parameter that needs to be passed to the factory ( First Approach)

Or it is better to pass a generic parameter to the Factory ( in other words hide the specifics from the client ) and let the Factory know which exact parameter it needs to create an object. ( Second Approach )

First Approach

class FruitFactory
{

    public function create($type)
    {
        if($type == 'Apple')
        {
            return new Apple();
        }
    }
}

$fruitFactory = new FruitFactory();
$type = request('type');
$fruit = $fruitFactory->create($type);

Second Approach

class FruitFactory
{

    public function create(Request $request)
    {
	$type = request('type');

        if($type == 'Apple')
        {
            return new Apple();
        }
    }
}

$fruitFactory = new FruitFactory();
$fruit = $fruitFactory->create();

Updated Question

If the FruitFactory is a factory of factories, does it need to know about all the exact parameters that its children factories need to create an object ?

Or maybe in this case the second approach is better ( Just passing the general $request parameter and let the factory find out which parameter it needs to create an object )

class FruitFactory
{

    public function create($type, $color)
    {
        if($type == 'Apple')
        {
		return app(Apple::class)->create($color);
        }
    }
}


class Apple
{
	public function create($color)
        {
		if($color == 'green') 
		{
			return new GreenApple();
		}
	}

}


$fruitFactory = new FruitFactory();
$type = request('type');
$color = request('color');

$fruitFactory->create($type, $color);

0 likes
8 replies
rodrigo.pedra's avatar

I prefer the "first approach" you described. Besides being more decoupled from your app's specific architecture, one reason is that you can reuse that code in Console Commands and Queued Jobs where you might not have access to the request object.

1 like
automica's avatar

@orest i think your first approach is best. Using the request object adds another layer of complexity which isn't needed here. Your Factory shouldn't need to know about the Request object.

passing in an type argument makes more sense when you creating 'Apple' objects in your tests.

You have a little error in your code at the top which i have corrected to:

$type= request('type');

$fruitFactory = new FruitFactory();
$result = $fruitFactory->create($type);
1 like
orest's avatar
Level 13

i have updated the question ( basically is a question on top of the initial question ).

To make sure that i'm not on the wrong way

automica's avatar

@orest is this hypothetical question to understand factories are you genuinely looking to make a factory that makes GreenApple's?

1 like
orest's avatar
Level 13

@automica hahaha oh no. is just a simple example to illustrate the question

rodrigo.pedra's avatar
Level 56

Well, as I said before, the first approach would be my personal preference, but that doesn't mean the second approach is a bad idea.

If you have a complex "factory of factories" (or a resolver maybe), maybe passing the request object can do it.

Note that it will make it harder to use that "factory of factories" in other places where a request object might not be available (Console Commands, Queues Jobs, Tests, ...)

I would go for a DTO (Data Transfer Object) that knows to build itself from a request Object, and pass that to the "Factory of Factories" object.

That way I can manually construct the DTO in places where I don't have a request Object.

Something like this:

class MyDTO {
    public $type;
    public $color;

    public function __construct($type, $color) {
        $this->type = $type;
        $this->color = $color;
    }

    public static function fromRequest($request) {
        return new self($request->input('type'), $request->input('color'));
    }
}

Then your "Factory of factories" can receive this DTO:

class FruitFactory
{

    public function create($dto)
    {
        if($dto->type == 'Apple')
        {
		return app(Apple::class)->create($dto->color);
        }
    }
}

And you would call it like this:

$dto = MyDTO::fromRequest(request());

$fruitFactory = new FruitFactory();
$fruit = $fruitFactory->create($dto);

Notice that although we have a new class, the usage didn't get more complex.

The advantage is that if you need to use it outside a request context you can buid your DTO and use it:

$type = // from a file, for example
$color = // from an API response, for example

$dto = new MyDTO($type, $color);

$fruitFactory = new FruitFactory();
$fruit = $fruitFactory->create($dto);

Hope it helps somehow.

1 like

Please or to participate in this conversation.