Skip to content

[Serializer] Improve ObjectNormalizer performance #16547

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

Closed
wants to merge 2 commits into from

Conversation

dunglas
Copy link
Member

@dunglas dunglas commented Nov 14, 2015

Q A
Bug fix? no
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #16179
License MIT
Doc PR n/a

Cache attributes detection in a similar way than in #16294 for PropertyAccess.

As for the PropertyAccess Component, I'll open another PR (in 2.8 or 3.1) allowing to cache these attributes between requests using Doctrine Cache.

@Tobion, can you try this PR with your benchmark to estimate the gain?

} elseif (strpos($name, 'is') === 0) {
// issers
$attributes[lcfirst(substr($name, 2))] = true;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't the constructor checks redundant here? They would never get through the has/is/get checks, or is it done simply because of performance reasons?

Personally I would like to see a guard clause here for readability:

if ($reflMethod->getNumberOfRequiredParameters() > 0) {
    continue;
}
// also prevents a lot of is checks as destructor is hardly ever implemented and constructor only ever once

Another option would be to omit the number of required attributes at this point and only check it when needed.

$attributes[lcfirst(substr($name, 3))] = 0 === $reflMethod->getNumberOfRequiredParameters();

This would limit the checks even more, but I'm not sure if calling the reflection method is slower or relying on getName() and strpos()

If it comes down to preferences, feel free to ignore if you disagree

@fabpot
Copy link
Member

fabpot commented Nov 23, 2015

Can you rebase? Thanks.

@dunglas dunglas force-pushed the obj_norm_perf branch 3 times, most recently from da10798 to 6f02eb1 Compare November 25, 2015 13:25
@dunglas
Copy link
Member Author

dunglas commented Nov 25, 2015

Rebased.

I've also refactored the code to add a guard clause according to @iltar comment but I left the constructor/destructor for now as we don't know the impact on performance such check can have.

return self::$attributesCache[$key];
}

if (self::$attributesCache[$key] = $this->getAllowedAttributes($object, $context, true)) {
Copy link
Member

Choose a reason for hiding this comment

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

you should not assign false here. It could corrupt the cache in case an exception is thrown in the following logic, is catched, and the method is called again: as you assign false in the cache array, the cache is set and used on future calls (and breaks the contracts of the method). Use a local variable and assign the cache only on next line when using the value.

and the logic is also altered here: an empty array should be returned here. Only false triggers the fallback logic. So you need to use a strict comparison

Copy link
Member

Choose a reason for hiding this comment

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

btw, this means we are missing a test covering the case where the object does not have any property serialized in the groups being used (your PR switches it to serialize the whole object, which is a regression)

@dunglas
Copy link
Member Author

dunglas commented Nov 25, 2015

@stof bug fixed and test added. Thanks for the review.

@dunglas dunglas changed the title [Serializer] Improve ObjectNormalizer performances [Serializer] Improve ObjectNormalizer performance Nov 25, 2015
@fabpot
Copy link
Member

fabpot commented Nov 28, 2015

Thank you @dunglas.

@fabpot fabpot closed this in 2659c8e Nov 28, 2015
@dunglas dunglas deleted the obj_norm_perf branch December 1, 2015 21:55
fabpot added a commit that referenced this pull request Jan 4, 2016
…ct class (dunglas)

This PR was squashed before being merged into the 3.1-dev branch (closes #17191).

Discussion
----------

[Serializer] Move the normalization logic in an abstract class

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | n/a
| License       | MIT
| Doc PR        | n/a

As suggested by @xabbuh, move all the normalization logic for objects in an abstract class.
It will ease the maintenance as well as adding new features such as #17113 and #16143.

I've introduced a new abstract class to avoid BC breaks in `AbstractNormalizer`. As a (good) side effect, all normalizers now benefits from the caching system introduced in #16547.

Commits
-------

3bec813 [Serializer] Move the normalization logic in an abstract class
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.

5 participants