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

[VarExporter] Fix exporting default values involving global constants #56488

Merged

Conversation

kylekatarnls
Copy link
Contributor

@kylekatarnls kylekatarnls commented May 19, 2024

Q A
Branch? 6.4
Bug fix? yes
New feature? no
Deprecations? no
License MIT

Hello, we hit a case when a service works fine when injected normally but stop working when injected lazily. The reason was that the default value of a parameter was a global constant that was used without explicitly specifying \ nor importing it. It ends up being incorrectly transformer in the proxy class as \MyNamespace\GLOBAL_CONSTANT instead of \GLOBAL_CONSTANT.

We worked around that by adding the \ in this service which is anyway rather a good move to be explicit. However I believe the ReflectionCaster should support this case because:

  • You might want to use a class from a third-party you don't control the code as a lazy service in Symfony and they might be legit not to use the FQCN since it's a feature provided by PHP to work.
  • So you can be confident that passing an injection from non-lazy to lazy is not going to cause problem.
  • It minimize surprises. We were confident that mocking this service in our tests was fine and so we didn't catch it early, it would be relatively tedious if we start to assume the proxy class can be incompatible where the normal class is and so that we would have to test all non-mocked of them in all possible situations.

@carsonbot carsonbot added this to the 5.4 milestone May 19, 2024
@kylekatarnls kylekatarnls force-pushed the fix/local-namespace-constant-name branch from 2cad659 to fbaed3b Compare May 19, 2024 09:58
@kylekatarnls kylekatarnls marked this pull request as draft May 19, 2024 09:59
@kylekatarnls kylekatarnls force-pushed the fix/local-namespace-constant-name branch 3 times, most recently from ddf9e3b to 4060c04 Compare May 19, 2024 15:30
@kylekatarnls kylekatarnls force-pushed the fix/local-namespace-constant-name branch 2 times, most recently from e98b45a to ab96ab0 Compare May 19, 2024 18:00
@kylekatarnls
Copy link
Contributor Author

AFAIU looking at the current state of tests https://github.com/symfony/symfony/tree/5.4 it sounds like failures here are not related to the current change.

@kylekatarnls kylekatarnls changed the title Allow to work with global constant without FQCN [VarDumper] Allow to work with global constant without FQCN May 19, 2024
@kylekatarnls kylekatarnls marked this pull request as ready for review May 19, 2024 18:05
@nicolas-grekas
Copy link
Member

nicolas-grekas commented May 19, 2024

Hi thanks for the PR. I'm surprised this change is in VarDumper and not in VarExporter. Does this really fix the issue you have?
Can you please share a small reproducing app just to be sure I get what we're talking about?

@kylekatarnls
Copy link
Contributor Author

kylekatarnls commented May 19, 2024

I guess both should be consistent and support what PHP natively support. For my use case, I'm looking for what is generating proxy-classes.php.

@kylekatarnls
Copy link
Contributor Author

Basically, I think Symfony may need to use this logic anywhere it's calling getDefaultValueConstantName because the actual behavior of PHP is to try both local namesapce and global namespace but this reflection method will always only return the local namespace.

@kylekatarnls
Copy link
Contributor Author

@nicolas-grekas You're right. It's not only applying to getDefaultValueConstantName() it also happens when doing (string) $param of a \ReflectionParameter, this precise case we hit is there in ProxyHelper::exportDefault:
https://github.com/symfony/symfony/blob/7.1/src/Symfony/Component/VarExporter/ProxyHelper.php#L338

When having in the constructor of a service:

__construct(
  #[Autowire(lazy: true)]
  private Foo $foo,
)

And Foo definition being:

namespace Bar;

class Foo
{
  public function byPi(float $number, float $pi = M_PI): float
  {
    return $number * $pi;
  }
}

Then casting to string the ReflectionParameter for float $pi = M_PI will give:

Parameter #1 [ <optional> int $pi = Bar\M_PI]

And then using this string, Symfony will assume Bar\M_PI is the correct and only way to export this default value.

Is it enough so you see what issue we face or still want me to provide a mini-repo?

I will try to make a PR to handle consistently both getDefaultValueConstantName() and (string) casts in various places I can find where it's used, but I'm open to any suggestion.

@kylekatarnls kylekatarnls force-pushed the fix/local-namespace-constant-name branch from ab96ab0 to 4ac2ccb Compare May 20, 2024 11:10
@kylekatarnls kylekatarnls changed the base branch from 5.4 to 6.4 May 20, 2024 11:11
@kylekatarnls kylekatarnls force-pushed the fix/local-namespace-constant-name branch from 4ac2ccb to 4420c35 Compare May 20, 2024 11:28
@kylekatarnls kylekatarnls changed the title [VarDumper] Allow to work with global constant without FQCN [VarExporter] Allow to work with global constant without FQCN May 20, 2024
@kylekatarnls kylekatarnls force-pushed the fix/local-namespace-constant-name branch from 4420c35 to 3294b80 Compare May 20, 2024 11:29
@nicolas-grekas nicolas-grekas modified the milestones: 5.4, 6.4 May 20, 2024
@kylekatarnls
Copy link
Contributor Author

Updated the PR to handle only the case of ProxyHelper in VarExporter (6.4 fix)

A next (but independent) step could be #56824 so global constants can be resolved without the \ the same way in the other places.

@nicolas-grekas nicolas-grekas changed the title [VarExporter] Allow to work with global constant without FQCN [VarExporter] Fix exporting default values involving global constants May 20, 2024
@nicolas-grekas nicolas-grekas force-pushed the fix/local-namespace-constant-name branch 2 times, most recently from cf25382 to 7800cf6 Compare May 20, 2024 13:49
@nicolas-grekas nicolas-grekas force-pushed the fix/local-namespace-constant-name branch from 7800cf6 to 5d33407 Compare May 20, 2024 13:52
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

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

I have updated the implementation to handle more cases (eg. when consts are nested in an array)

@nicolas-grekas
Copy link
Member

Thank you @kylekatarnls.

@nicolas-grekas nicolas-grekas merged commit 3e67099 into symfony:6.4 May 20, 2024
3 of 10 checks passed
@kylekatarnls
Copy link
Contributor Author

Thank to you for the quick review and improvements here 🙏

xabbuh added a commit that referenced this pull request May 22, 2024
This PR was merged into the 6.4 branch.

Discussion
----------

[VarExporter] Fix test expectation

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | -
| License       | MIT

Fixes a wrong expectation introduced in #56488

Commits
-------

19d573a [VarExporter] Fix test expectation
This was referenced May 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants