Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[PropertyAccess] Fix handling property names with a . #58110

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

Merged
merged 1 commit into from
Aug 30, 2024

Conversation

alexandre-daubois
Copy link
Member

@alexandre-daubois alexandre-daubois commented Aug 28, 2024

Q A
Branch? 5.4
Bug fix? yes
New feature? no
Deprecations? no
Issues Fix #58100
License MIT

If the property path contains a dot, it is considered to be an access to an underlying property. However, some edge cases allow to have dots in property names, especially with stdClass.

Minimal reproducer:

$stdclass = (object) ['bankAccount.iban' => 'NL16TEST0436169118', 'bankSummary' => ''];
$accessor = PropertyAccess::createPropertyAccessor();

dump($accessor->getValue($stdclass, 'bankAccount.iban')); // returns "NL16TEST0436169118"

$accessor->setValue($stdclass, 'bankAccount.iban', 'value');
dump($accessor->getValue($stdclass, 'bankAccount.iban')); // returns "value"

@xabbuh
Copy link
Member

xabbuh commented Aug 28, 2024

Shouldn't the dot be escaped in the property path instead?

@alexandre-daubois
Copy link
Member Author

alexandre-daubois commented Aug 28, 2024

For the minimal reproducer, yes, but it doesn't help with the original issue where the author uses Serializer and doesn't have the hand on the underlying property paths.

Inevitably, this is closely linked to stdClass, hence the hard check in the code to make sure you're dealing with stdClass.

@xabbuh
Copy link
Member

xabbuh commented Aug 28, 2024

Can this not be fixed inside the Serializer component?

@alexandre-daubois
Copy link
Member Author

Actually, escaping the dot seems only to work with array accesses. The following code breaks:

$stdclass = (object) ['bankAccount.iban' => 'NL16TEST0436169118', 'bankSummary' => ''];
$accessor = PropertyAccess::createPropertyAccessor();

dump($accessor->getValue($stdclass, 'bankAccount\.iban')); // throws NoSuchPropertyException

Or maybe I'm using the wrong syntax?

@@ -150,7 +150,7 @@ public function getValue($objectOrArray, $propertyPath)
self::VALUE => $objectOrArray,
];

if (\is_object($objectOrArray) && false === strpbrk((string) $propertyPath, '.[')) {
if (\is_object($objectOrArray) && (false === strpbrk((string) $propertyPath, '.[') || property_exists($objectOrArray, $propertyPath))) {
Copy link
Member

Choose a reason for hiding this comment

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

let's make this specific to stdClass?
this can be true for any object with dynamic properties but I don't think we need to support that, esp. if that costs too much, CPU-wise. Can you check this aspect.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've made it specific to stdClass. Here a quick benchmark, testing both accessing stdClass and other objects:

<?php

use Symfony\Component\PropertyAccess\PropertyAccess;

require 'vendor/autoload.php';

class Foo
{
    public $iban = 'NL16TEST0436169118';
    public $bankSummary = '';
}

$stdclass = (object) ['iban' => 'NL16TEST0436169118', 'bankSummary' => ''];
$accessor = PropertyAccess::createPropertyAccessor();

dump("Testing with stdClass");
foreach (range(1, 5) as $i) {
    $start = microtime(true);

    for ($j = 0; $j < 100000; $j++) {
        $accessor->setValue($stdclass, 'iban', 'value');
        $accessor->getValue($stdclass, 'iban');
    }

    $end = microtime(true);

    dump('Elapsed time: ' . ($end - $start) . ' seconds');
}

dump("\nTesting with Foo");
$foo = new Foo();
foreach (range(1, 5) as $i) {
    $start = microtime(true);

    for ($j = 0; $j < 100000; $j++) {
        $accessor->setValue($foo, 'iban', 'value');
        $accessor->getValue($foo, 'iban');
    }

    $end = microtime(true);

    dump('Elapsed time: ' . ($end - $start) . ' seconds');
}

Above is with the patch, below it 5.4 as is:

image

The difference is low for 100 000 iterations. After running the script several times, the time differences are explained more by external tasks that take up some CPU during execution.

Copy link
Member

@xabbuh xabbuh left a comment

Choose a reason for hiding this comment

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

LGTM

@nicolas-grekas
Copy link
Member

Thank you @alexandre-daubois.

@nicolas-grekas nicolas-grekas merged commit c210fab into symfony:5.4 Aug 30, 2024
8 of 12 checks passed
This was referenced Aug 30, 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.

4 participants