Skip to content
Advertisement

How to infer type of a dynamically instantiated class without using annotations?

I have a dynamic config where I’ve defined supported classes for usage:

'registeredRequestParameters' => [
    SearchParameter::class,
    ReturnsParameter::class,
    OrderByParameter::class,
    RelationsParameter::class
],

All of those classes extend an abstract class AbstractParameter.

Now when I am registering those in the package I’m developing, I am doing this:

foreach ($this->requestParameters as $parameter) {
    /**
     * @var AbstractParameter $instance
     */
    $instance = new $parameter($this->request, $this->builder, $this->configModel);
    $instance->appendQuery();
}

And this is working fine, however I need to say that $instance is actually an AbstractParameter because otherwise my IDE won’t pick up that the method is from that class.

Is there a way to do this without annotations?

Advertisement

Answer

There is absolutely nothing wrong with using type annotations. That’s what they are there for.

But I agree that proper type hinting is better and more robust.

But for that you cannot use not use dynamic instantiation. Use an abstract factory instead. This will make the code clearer, more flexible, and more explicit.

abstract class ParameterFactory {
    
    public static parameter($type, $request, $builder, $configModel) : AbstractParameter
    {
        
        switch ($type) {
            case SearchParameter::class:
                return new SearchParameter($request, $builder, $configModel);
            case ReturnsParameter::class:
                return new ReturnsParameter($request, $builder, $configModel);
            case OrderByParameter::class:
                return new OrderByParameter($request, $builder, $configModel);
            case RelationsParameter::class:
                return new OrderByParameter($request, $builder, $configModel);
        }

        throw new InvalidArgumentException("Class $type not supported by factory");
            
    }
}

Then you would do:

foreach ($this->requestParameters as $parameter) {  
    $instance = ParameterFactory::parameter(parameter, $this->request, $this->builder, $this->configModel);
    $instance->appendQuery();
}

As an aside, I would create a ParameterInterface and type-hint for that instead of an abstract class.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement