-
Notifications
You must be signed in to change notification settings - Fork 153
Dependencies injected to properties #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Allows backward compatible introduction of new dependencies to classes without having to use ObjectManager directly. Allows circular dependencies.
Would this make dependency properties that need such a thing public properties? |
Those properties would remain private/protected, if that's what you mean |
@@ -0,0 +1,34 @@ | |||
## Introduce the possibility to inject dependencies directly to properties | |||
### Reasons | |||
* Allowing backward compatible introduction of new dependencies to classes without having to use ObjectManager directly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you describe the issue with adding optional arguments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I've stated - because of having to use ObjectManager::getInstance(). Do you want me to describe why is it a bad thing to use object manager's static instance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I mean that if the problem in static dependency on OB, better to propose to ask for OM in the constructor explicitly and it definitely makes sense for me
* Allowing backward compatible introduction of new dependencies to classes without having to use ObjectManager directly | ||
Currently we have to add optional arguments to classes and invoke ObjectManager::getInstance() to get a dependency | ||
for cases when the constructor is invoked from a child class. Declaring such dependencies for properties will allow us to avoid this. | ||
* Allowing circular dependencies |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This contradicts with Magento Technical Guidelines
3.1. There SHOULD be no circular dependencies between object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll remove this part
after requested object instances are created we can make circular dependecies possible. | ||
### Details | ||
#### XML | ||
We'd have to add *properties*/*property* elements for *type* elements in di.xml's. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can I ask you to provide an example of XML declaration?
*property* element would have *type* and *shared* attributes just as *argument* does. | ||
#### Injection | ||
Key points: | ||
* Dependencies list for properties will be collected and injected after |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This contradicts with Magento Technical Guidelines
2.2. Object MUST be ready for use after instantiation. No additional public initialization methods are allowed.
2.14. Temporal coupling MUST be avoided
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No it doesn't. Classes requesting objects from object manager won't get them before they initiated. This is just details regarding implementation of injecting dependencies to properties.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be clear - I'm not suggesting we create setters for these properties or make them public. Objects will be fully initiated after the object manager returns them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You cannot create such an object with the "new" operator and use it without additional initialization and we don't have the requirement to create all objects using DI. Actually, we have opposite requirement: ObjectManager MUST NOT be used in unit tests.
Key points: | ||
* Dependencies list for properties will be collected and injected after | ||
the requested object's instance is created and added to the shared map (if it's a singleton) to allow circular dependencies | ||
* A dependency will __NOT__ be inject into a property if it's not equal to *null* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it unexpected behavior. When I pass arguments to constructor I will expect there will be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is it contradicting with what I've written?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I don't get what you are proposed here.
For me it looks like:
if I will write code like:
$om->create('MyClass', ['MyClass::property_a' => 123]);
and class object has already initialised in same constriuctor, the value "123" will not be used
* In order to preserve backward compatibility we can't add an argument to ObjectManagerInterface::create(), | ||
so to distinguish values passed in $arguments as property dependencies I propose we name them as *ClassName*::*property* | ||
#### Using ObjectManager::getInstance() | ||
* Mark it as deprecated because the only sensible use-case was introduction of new dependencies to classes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are other use cases. Better to discuss this separately
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, if I'm missing some use cases it would be good to know
ObjectManager is critical for performance point of view. So, we need also consider the impact on performance |
From my point of view the introduction of more reflection "magic" is worse than the use of the static I believe it's a common misconception that the use of all static method calls should be considered bad. Lets discuss the case of The first downside of using the The second downside of using the To summarize, I think the proposal is trying to solve a non-problem and accepting it would be harmful as it would introduce unneeded complexity. |
I also think it is better to have a single place of reference - we have to allow setting up dependencies via XML for 3rd party devs to extend, and without having to write a constructor (which can be generated by object manager if we choose to accept this PR) the di.xml's would be the single point of reference. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Agree with @Vinai, need stronger reasoning to introduce a feature which will complicate the framework
- Not clear how the configuration would look like
- Please provide analysis of dev experience changes with the new approach for core and extension developers
Reasons to introduce this:
|
How di.xml would look like:
|
Dev experience: Magento dev adding a new dependency to a classInstead of adding a new optional (not really) parameter to the constructor
you just add a property element to the class' di config (di.xml):
Magento dev creating a new classInstead of defining all the properties and then writing a redundant constructor you just add a type element to the module's di.xml:
di.xml:
3rd party dev looking up a class' dependenciesJust find the module's di.xml and type element with attr name=TheClass |
The ObjectManager should not touch the constructor behavior of a class. It shouldn't even know how the class works. His ONLY job is to pass values to the constructor on instanciation. Nothing else. |
Needing to use a different DIC is in my estimate a fringe case that probably would only effect < 1% of all instances. All others would suffer the introduced complexity, too.
That is false. Because the "optional" dependencies are part of the constructor signature, too, even though they default to
The constructor is the only source to get the full picture. In fact, the whole point of constructor injection is type safety. With this proposal any type could be injected via di.xml. This is no better than using arrays to pass in options, but without the nice things arrays. |
Writing a daemon may require multiple object managers for isolation because our code is designed to be called from a script that dies, but by employing an object manager per message we can write daemon safely without putting additional requirements for our code |
The problem with inability to specify a specific preference for an optional argument added to a class: |
Currently the constructor is not the only source of dependencies config - more specific types can be stated in di.xml and scalar values can only be passed with di.xml (including arrays of objects for Composite classes) |
Because of backward compatibility and lack of resources for refactoring we will not be able to migrate to property injection completely. It will become yet another way of doing the same thing and developers will have to look in one more place when trying to understand what instance is actually injected. It may work for green field projects, but for Magento does not look like a good idea. I believe the benefits of the proposal do not justify increased complexity and deterioration of dev experience. |
I agree with previous responders on
I think dependency on the object manager is not a big problem because it is used only when you don't pass dependency and should be eliminated in the future anyway. I agree that there is a problem that class can't be configured via di with different dependency. Maybe we should just create another method for this? |
Allows backward compatible introduction of new dependencies to classes without having to use ObjectManager directly.
Allows circular dependencies.