2

I am actually trying to instanciate a class dynamically with these arguments.
Here is the code I use in class A:

/** @var string $source */
$source = '\Foo\Bar\My\Class'; // Dynamic value that I am not aware because it is from other extensions

/** @var bool $isClassLoadable */
$isClassLoadable = $this->definedClasses->isClassLoadable($source);
if (!$isClassLoadable) {
    return false;
}

/** @var Model $model */
$model = $this->getModel(); // loaded model with data

/** @var \Magento\Framework\Simplexml\Config $config */
$config = $this->getConfig(); // loaded configuration with data

/** @var ProcessorInterface $processorInstance */
$processorInstance = $this->objectManager->create(
    $source,
    [
        $model,
        $config,
    ]
);

The \Foo\Bar\My\Class class code:

public function __construct(
    Model $model,
    Config $config
) {
    $this->model = $model;
    $this->config = $config;

    \Zend_Debug::dump($this->model->debug());
    \Zend_Debug::dump($this->config);
}

Here my two parameters are an empty model and an empty configuration.

Questions
- Is it a good practice to use ObjectManager to create class from a "string" ?
- If it is a "good practice" what is the way to keep my data between my class A and the \Foo\Bar\My\Class instanciation ?


EDIT
I am aware that using ObjectManager is a bad practice and Factory are here to avoid that but the $source is from a configuration and maybe third part extensions, I don't know his value. I hardcoded it for the purpose of my example.

1 Answer 1

4

No, it's not a good practice to use the object manager.
Use a factory instead.
To get an instance of \Foo\Bar\My\Class you will need to use an instance of \Foo\Bar\My\ClassFactory that will be automatically generated.

I assume that the code you listed in the question is part of a class.
you should have in your class this:

protected $fooBarFactory;
public function __construct(
    ....
    \Foo\Bar\My\ClassFactory $fooBarFactory,
    ....
) {
   .... 
   $this->fooBarFactory = $fooBarFactory;
    ....
}

Then you can instantiate your \Foo\Bar\My\Class like this:

$processorInstance = $this->fooBarFactory->create([
    'model' => $model,
    'config' => $config,
]);

The createmethod takes as parameter an array, and the keys in this array must match the constructor argument names in the class you are instantiating.
Your class accepts 2 parameters in the constructor called $model and $config hence the array keys model and config.
[EDIT]
In case your class acts as a factory you can use ObjectManager.
I think you should move the code that actually instantiates $source in a separate factory (that's not autogenerated) and you are allowed there to use the OM.
And you can inject that general factory in your class and have something like this

$processorInstance = $this->customProcessorFactory->create(
    $source, 
    [
        'model' => $model,
        'config' => $config,
    ]
);
8
  • Hi, the thing I forgot to say that is the $source is from configuration and maybe third part extensions. I write it hardcoded here for the example. I am aware of the factory method but I can not use it here, I think. Or maybe do I have to manually add Factory to my $source string and mix the two methods ? Nov 24, 2016 at 13:39
  • If I am right I can not inject my $source class to my class A depending on my edit informations Nov 24, 2016 at 13:53
  • See my update to the answer. I hope it makes sense.
    – Marius
    Nov 24, 2016 at 14:00
  • If I understand I create a class CustomProcessorFactory that I inject in my Class A. In that class I use the OM to create the source. So in my Class A I call customProcessorFactory as in you example which it is using the OM right ? If that is it I did not see what will change, that will just move my ObjectManager initial issue. Did I misunderstood your reasoning or maybe my example is not that clear ? Nov 24, 2016 at 14:10
  • The idea was to use object manager only in classes that act as factories and do nothing else. If you move your $source instantiation to a separate class that just only instantiates it and does nothing else, you are off the hook. You are allowed to use OM. The effect will be the same but your code will be best practice compliant.
    – Marius
    Nov 24, 2016 at 14:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.