Let me give you another example for the case when an arbitrary number of arguments must be passed to the constructor of a factory product, and different products may have different designer signatures. For example, if a class appears like car_Sedan_With_Custom_Engine , with a constructor:
class car_Sedan_With_Custom_Engine extends car_Sedan { /** * @var EngineInterface */ private $engine; public function __construct(array $options = [], EngineInterface $engine = null) { parent::__construct($options); if ($engine) { $this->engine = $engine; } } //...методы классы }
Where the object that implements the EngineInterface is also passed to the constructor (for example, to apply the Strategy pattern). Then you can use the Reflection API reflection mechanism (this approach cannot be recommended for all occasions, it has certain drawbacks, but it works for a number of applications) and use the ReflectionClass::newInstanceArgs method. Then you can rewrite the factory method, thus:
public static function build ($type = '', $args = []) { if($type == '') { throw new Exception('Invalid Car Type.'); } else { $className = 'car_'.ucfirst($type); if(class_exists($className)) { $reflect = new ReflectionClass($class); $object = $reflect->newInstanceArgs($args); return $object; } else { throw new Exception('Car type not found.'); } } }
Then the client code to create an instance of car_Sedan will look like this:
$sedan = carFactory::build('car_Sedan', [$options]);
And to create car_Sedan_With_Custom_Engine :
$customizedSedan = carFactory::build( 'car_Sedan_With_Custom_Engine', [$options, new CustomEngine()] );