Skip to content

Commit 964bf1f

Browse files
pan93412nicolas-grekas
authored andcommitted
[PropertyInfo] Fix write visibility for Asymmetric Visibility and Virtual Properties
1 parent 294a39f commit 964bf1f

File tree

3 files changed

+108
-5
lines changed

3 files changed

+108
-5
lines changed

src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -617,12 +617,18 @@ private function isAllowedProperty(string $class, string $property, bool $writeA
617617
try {
618618
$reflectionProperty = new \ReflectionProperty($class, $property);
619619

620-
if (\PHP_VERSION_ID >= 80100 && $writeAccessRequired && $reflectionProperty->isReadOnly()) {
621-
return false;
622-
}
620+
if ($writeAccessRequired) {
621+
if (\PHP_VERSION_ID >= 80100 && $reflectionProperty->isReadOnly()) {
622+
return false;
623+
}
624+
625+
if (\PHP_VERSION_ID >= 80400 && ($reflectionProperty->isProtectedSet() || $reflectionProperty->isPrivateSet())) {
626+
return false;
627+
}
623628

624-
if (\PHP_VERSION_ID >= 80400 && $writeAccessRequired && ($reflectionProperty->isProtectedSet() || $reflectionProperty->isPrivateSet())) {
625-
return false;
629+
if (\PHP_VERSION_ID >= 80400 &&$reflectionProperty->isVirtual() && !$reflectionProperty->hasHook(\PropertyHookType::Set)) {
630+
return false;
631+
}
626632
}
627633

628634
return (bool) ($reflectionProperty->getModifiers() & $this->propertyReflectionFlags);
@@ -863,6 +869,20 @@ private function getReadVisiblityForMethod(\ReflectionMethod $reflectionMethod):
863869

864870
private function getWriteVisiblityForProperty(\ReflectionProperty $reflectionProperty): string
865871
{
872+
if (\PHP_VERSION_ID >= 80400) {
873+
if ($reflectionProperty->isVirtual() && !$reflectionProperty->hasHook(\PropertyHookType::Set)) {
874+
return PropertyWriteInfo::VISIBILITY_PRIVATE;
875+
}
876+
877+
if ($reflectionProperty->isPrivateSet()) {
878+
return PropertyWriteInfo::VISIBILITY_PRIVATE;
879+
}
880+
881+
if ($reflectionProperty->isProtectedSet()) {
882+
return PropertyWriteInfo::VISIBILITY_PROTECTED;
883+
}
884+
}
885+
866886
if ($reflectionProperty->isPrivate()) {
867887
return PropertyWriteInfo::VISIBILITY_PRIVATE;
868888
}

src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php7Dummy;
2929
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php7ParentDummy;
3030
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php81Dummy;
31+
use Symfony\Component\PropertyInfo\Tests\Fixtures\VirtualProperties;
3132
use Symfony\Component\PropertyInfo\Type;
3233

3334
/**
@@ -699,4 +700,67 @@ public function testAsymmetricVisibility()
699700
$this->assertFalse($this->extractor->isWritable(AsymmetricVisibility::class, 'publicProtected'));
700701
$this->assertFalse($this->extractor->isWritable(AsymmetricVisibility::class, 'protectedPrivate'));
701702
}
703+
704+
/**
705+
* @requires PHP 8.4
706+
*/
707+
public function testVirtualProperties()
708+
{
709+
$this->assertTrue($this->extractor->isReadable(VirtualProperties::class, 'virtualNoSetHook'));
710+
$this->assertTrue($this->extractor->isReadable(VirtualProperties::class, 'virtualSetHookOnly'));
711+
$this->assertTrue($this->extractor->isReadable(VirtualProperties::class, 'virtualHook'));
712+
$this->assertFalse($this->extractor->isWritable(VirtualProperties::class, 'virtualNoSetHook'));
713+
$this->assertTrue($this->extractor->isWritable(VirtualProperties::class, 'virtualSetHookOnly'));
714+
$this->assertTrue($this->extractor->isWritable(VirtualProperties::class, 'virtualHook'));
715+
}
716+
717+
/**
718+
* @dataProvider provideAsymmetricVisibilityMutator
719+
* @requires PHP 8.4
720+
*/
721+
public function testAsymmetricVisibilityMutator(string $property, string $readVisibility, string $writeVisibility)
722+
{
723+
$extractor = new ReflectionExtractor(null, null, null, true, ReflectionExtractor::ALLOW_PUBLIC | ReflectionExtractor::ALLOW_PROTECTED | ReflectionExtractor::ALLOW_PRIVATE);
724+
$readMutator = $extractor->getReadInfo(AsymmetricVisibility::class, $property);
725+
$writeMutator = $extractor->getWriteInfo(AsymmetricVisibility::class, $property, [
726+
'enable_getter_setter_extraction' => true,
727+
]);
728+
729+
$this->assertSame(PropertyReadInfo::TYPE_PROPERTY, $readMutator->getType());
730+
$this->assertSame(PropertyWriteInfo::TYPE_PROPERTY, $writeMutator->getType());
731+
$this->assertSame($readVisibility, $readMutator->getVisibility());
732+
$this->assertSame($writeVisibility, $writeMutator->getVisibility());
733+
}
734+
735+
public static function provideAsymmetricVisibilityMutator(): iterable
736+
{
737+
yield ['publicPrivate', PropertyReadInfo::VISIBILITY_PUBLIC, PropertyWriteInfo::VISIBILITY_PRIVATE];
738+
yield ['publicProtected', PropertyReadInfo::VISIBILITY_PUBLIC, PropertyWriteInfo::VISIBILITY_PROTECTED];
739+
yield ['protectedPrivate', PropertyReadInfo::VISIBILITY_PROTECTED, PropertyWriteInfo::VISIBILITY_PRIVATE];
740+
}
741+
742+
/**
743+
* @dataProvider provideVirtualPropertiesMutator
744+
* @requires PHP 8.4
745+
*/
746+
public function testVirtualPropertiesMutator(string $property, string $readVisibility, string $writeVisibility)
747+
{
748+
$extractor = new ReflectionExtractor(null, null, null, true, ReflectionExtractor::ALLOW_PUBLIC | ReflectionExtractor::ALLOW_PROTECTED | ReflectionExtractor::ALLOW_PRIVATE);
749+
$readMutator = $extractor->getReadInfo(VirtualProperties::class, $property);
750+
$writeMutator = $extractor->getWriteInfo(VirtualProperties::class, $property, [
751+
'enable_getter_setter_extraction' => true,
752+
]);
753+
754+
$this->assertSame(PropertyReadInfo::TYPE_PROPERTY, $readMutator->getType());
755+
$this->assertSame(PropertyWriteInfo::TYPE_PROPERTY, $writeMutator->getType());
756+
$this->assertSame($readVisibility, $readMutator->getVisibility());
757+
$this->assertSame($writeVisibility, $writeMutator->getVisibility());
758+
}
759+
760+
public static function provideVirtualPropertiesMutator(): iterable
761+
{
762+
yield ['virtualNoSetHook', PropertyReadInfo::VISIBILITY_PUBLIC, PropertyWriteInfo::VISIBILITY_PRIVATE];
763+
yield ['virtualSetHookOnly', PropertyReadInfo::VISIBILITY_PUBLIC, PropertyWriteInfo::VISIBILITY_PUBLIC];
764+
yield ['virtualHook', PropertyReadInfo::VISIBILITY_PUBLIC, PropertyWriteInfo::VISIBILITY_PUBLIC];
765+
}
702766
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\PropertyInfo\Tests\Fixtures;
13+
14+
class VirtualProperties
15+
{
16+
public bool $virtualNoSetHook { get => true; }
17+
public bool $virtualSetHookOnly { set => $value; }
18+
public bool $virtualHook { get => true; set => $value; }
19+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy