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

Remove dependency to doctrine/common #299

Draft
wants to merge 1 commit into
base: 3.4.x
Choose a base branch
from

Conversation

greg0ire
Copy link
Member

Two good reasons to do this move:

  • This was a circular dependency.
  • doctrine/common is being sunset.

@stof
Copy link
Member

stof commented Jun 17, 2022

The code does not properly handle cases where code implements the Proxy interface without the future methods

@greg0ire
Copy link
Member Author

greg0ire commented Jun 17, 2022

The code does not properly handle cases where code implements the Proxy interface without the future methods

I see several paths forward:

  1. deprecate the Proxy interface in favor of a more complete one, check it in addition to the one from common. Drawbacks: it will have a worse name, the best name being already taken (unless you can find something ?). Also, it won't allow us to drop the dependency to doctrine/common
  2. add a complementary interface with only the missing methods, extend it in doctrine/common, release doctrine/common, add a conflict on persistence with versions older than the latest doctrine/common, and throw unless both interfaces are implemented. Drawback: it's quite complicated
  3. add method_exists checks and throw in the appropriate case. Drawback: I'm not sure how performance-sensitive the code where the check happens is, or if having those checks could become an issue. Maybe check just for one method and assuming the rest is implemented would be sufficient. Anyway, even if all methods exist, that's not a guarantee that they have the required signature.

What would you recommend? I'm leaning towards 3.

@greg0ire greg0ire force-pushed the sever-ties-to-common branch 2 times, most recently from d0ea640 to 51ba295 Compare June 19, 2022 12:19
@greg0ire
Copy link
Member Author

I went ahead and implemented a check, but just for the methods that are called.

@malarzm
Copy link
Member

malarzm commented Jun 20, 2022

It's been a while since I had to touch proxied-public-properties-voodoo magic but here goes nothing: can't we outsource the optimization to doctrine/common and/or employ consumers (well, ORM) to do some check beforehand and remove code altogether? Given ORM is the only consumer, and it already relies on doctrine/common, it could even provide its own implementation for needed reflection.

@greg0ire
Copy link
Member Author

@malarzm no idea yet, but it sounds better indeed, I'll try to look into that 👍

@greg0ire
Copy link
Member Author

greg0ire commented Jun 22, 2022

@malarzm I've taken a look at ORM, and getValue() seems to be called in a lot of places. I'm not quite sure the check is useful in 100% of the call sites. Maybe somebody will know which one actually require the check.

I think one way to do this in a simple way would be to override AbstractClassMetadataFactory::getReflectionService() so that it returns a service implemented in the ORM with an overridden getAccessibleProperty method which would return 3 types inheriting the 3 ones from persistence, with an overridden method… this looks quite hairy.

@derrabus @beberlei what do you think about this?

It should be noted that if we decide to go that way, we will have to deprecate passing a proxy object to getValue(), and postpone the removal of the check to 4.0. Because of how this will slow things down, I think we should merge this PR regardless of whether we do what @malarzm suggests, that way we get rid of the (circular!) dependency now.

@beberlei
Copy link
Member

GetValue is Performance critical, i would like to avoid to increase the number of method calls there.

@beberlei
Copy link
Member

I need to look at this on a proper display, on mobile i cant fully review

@malarzm
Copy link
Member

malarzm commented Jun 29, 2022

Here goes nothing #2 to keep the changes minimal: instanceof works just fine with possibly-non-existing classes, how about keeping things as is reflection-wise and just moving doctrine/common to require-dev for the sake of tests? It's hacky a bit but will work :)

@greg0ire
Copy link
Member Author

@malarzm it's already in require-dev 😉 This PR is a step towards sunsetting doctrine/common.

@malarzm
Copy link
Member

malarzm commented Jun 30, 2022

it's already in require-dev

Oh, missed that. What's the point then? Once we get rid of old Proxies in ORM (and enough time passes) we'll be able to just get rid of it. What's the benefit now?

@greg0ire
Copy link
Member Author

greg0ire commented Jun 30, 2022

  1. I'm trying to migrate ORM to PHP 8 syntax: https://github.com/doctrine/orm/projects/6
  2. It's better to add type declarations to doctrine/common beforehand, that way I can add them as well on inheriting types, but @derrabus suggested we kill doctrine/common instead
  3. I'm trying to kill it

@malarzm
Copy link
Member

malarzm commented Jun 30, 2022

Shouldn't ORM switch to ProxyManager first and continue PHP 8 syntax afterwards? Then doctrine/common will be dropped from its requirements. We can't really kill doctrine/common before releasing ORM 3.0 and even after that we'll have to provide support for 2.x for quite some time

@greg0ire
Copy link
Member Author

Shouldn't ORM switch to ProxyManager first and continue PHP 8 syntax afterwards?

This comment says we shouldn't: doctrine/orm#8518 (comment)

We can't really kill doctrine/common before releasing ORM 3.0

Can't we? If we copy proxy classes to the ORM, maybe we can?

@malarzm
Copy link
Member

malarzm commented Jul 1, 2022

If we copy proxy classes to the ORM, maybe we can?

All right, had no idea it was the plan :)

Two good reasons to do this move:
- This was a circular dependency.
- doctrine/common is being sunset.
@greg0ire
Copy link
Member Author

greg0ire commented Aug 20, 2022

@beberlei after #299, the extra method calls are moved to setValue, is that better performance-wise? This method is called less than getValue I suppose.

@greg0ire greg0ire marked this pull request as draft August 21, 2022 21:06
@greg0ire
Copy link
Member Author

Converting to draft as determining how to replace doctrine/common proxy functionality might have some influence on this PR.

@nicolas-grekas
Copy link
Member

See follow up at #307

@@ -49,6 +53,13 @@ public function setValue($object, $value = null)
return;
}

if (! method_exists($object, '__getInitializer') || ! method_exists($object, '__setInitializer')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't we assume that $object is always an isntance of the class used for this property and move the check to ctor?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes that's probably safe to do 👍

@beberlei
Copy link
Member

beberlei commented Oct 9, 2022

@greg0ire Generally setValue is used in hydration, getValue in changeset computation. So setValue is probably called much more often as its for every read.

@derrabus derrabus changed the base branch from 3.1.x to 3.2.x December 19, 2022 12:43
@greg0ire greg0ire changed the base branch from 3.2.x to 3.4.x May 17, 2024 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants