Skip to content
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

Cloning lazy instantiated objects #333

Closed
theofidry opened this issue Aug 29, 2016 · 4 comments
Closed

Cloning lazy instantiated objects #333

theofidry opened this issue Aug 29, 2016 · 4 comments
Assignees
Labels

Comments

@theofidry
Copy link

theofidry commented Aug 29, 2016

If you have a proxy used to lazy instantiated object, cloning it will result in the instantiation of the said object. Is there any way to prevent that? Because this makes it impossible to use lazy instantiation in an immutable system.

To give a more real world use case, in the case of https://github.com/nelmio/alice, sometimes generating a fixture object may result in resolving other objects. For example if you have:

Dummy:
  dummy1:
    relatedDummy: '@dummy*'
  dummy0: {}

When generating dummy1, @dummy* will match dummy0 and so dummy0 will be generated before dummy1. In certain cases however, for example:

Dummy:
  dummy{1..10}:
    relatedDummies: '3x @dummy*' # means will construct and array where each element will be @dummy*

This strategy fails because you may have cyclic dependencies. Those cyclic dependences are actually perfectly valid and is not something that should be avoided, but it will fail is because for example dummy1 needs dummy2 to be generated first, and dummy2 needs dummy3, but dummy3 needs dummy1, which cannot be generated yet...

There is two ways to fix that:

  1. Instantiate all objects first, but this problem persist if you have those dependencies at the instantiation level, i.e. for example:
Dummy:
  dummy{1..10}:
    __construct: ['3x @dummy*']
  1. lazy instantiate the objects. So when dummy1 needs dummy2, you stop at that and you don't care yet how dummy2 is generated.

The issue is that the library enforces immutability almost everywhere, for example
here, making use of https://github.com/myclabs/DeepCopy. The resulting issue is that some cloning are done too early for the usage of a proxy to be of any use.

@theofidry
Copy link
Author

@Ocramius sorry I pressed the enter key too soon.

@Ocramius Ocramius self-assigned this Aug 29, 2016
@theofidry
Copy link
Author

Also guess kind of related to myclabs/DeepCopy#18

@Ocramius
Copy link
Owner

  1. Instantiate all objects first, but this problem persist if you have those dependencies at the instantiation level, i.e. for example

A cyclic graph can only be built like that in PHP, since there is no construct that allows instantiation and bi-directional reference of objects at the same time. This is normal for imperative languages, so I' don't see a way around it.

  1. lazy instantiate the objects. So when dummy1 needs dummy2, you stop at that and you don't care yet how dummy2 is generated.

This is a workaround, but it still isn't an "immutable cyclic graph". It just looks immutable from the outside.

Even if you disabled lazy instantiation in a specific method of your proxies (__clone, in this case), you'd still end up with a mess later on, once you try to restore the graph to a valid state, post-initialization.

I don't want to support different __clone semantics, as they have only caused issues for doctrine (in doctrine/common) in the past, and generally just add up to the confusion (this scenario).

In addition to that, ProxyManager is probably the wrong tool here, as it is not really designed to break cyclic graphs like this one. It can be used for that, but it's not its primary purpose. It seems to me that nelmio/alice expects the entire graph to be provided as "complete" in one shot. This can be done by skipping its configuration DSL and by giving it a fully instantiated/complete graph instead (manually).

@theofidry
Copy link
Author

A cyclic graph can only be built like that in PHP, since there is no construct that allows instantiation and bi-directional reference of objects at the same time. This is normal for imperative languages, so I' don't see a way around it.

Makes sense, so the problem comes from the way I'm solving those 2x @dummy* in the first place. Thanks for the help :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants