Asymmetric visibility is a BC break

php.internals

Удальцов Валентин

1 year ago
Hi, internals! Since writing https://externals.io/message/125740 I've realized that the major problem with aviz is actually simple but fundamental. In PHP <=8.0 this code is valid for an object of any user class: ```php class User { public string $name = 'Bob'; } $object = new User(); foreach ($object as $property => $value) { $object->{$property} = 'Jack'; } ``` The same is true for Reflection API: once you check that `(new ReflectionProperty(Foo::class, 'property'))->isPublic()`, you can safely read property and write to it from any scope. Now let's jump to PHP 8.1+ with support for readonly properties. A readonly property is two functionalities in one: write-once and private set. This means that `public readonly $property` is actually `public(get) private(set) readonly $property`. Although it is marked as `public`, it is not public because it is not a symmetric public property! In PHP 8.1+, the following User class suddenly breaks the code above: ```php class User { public function __construct( public readonly string $name = 'Bob', ) {} } $object = new User(); foreach ($object as $property => $value) { // Fatal error: Uncaught Error: Cannot modify readonly property User::$name $object->{$property} = 'Jack'; } ``` In other words, the meaning of `public` has changed in PHP 8.1. Before, it used to mean "symmetric", now it means "symmetric unless readonly". While not explicitly stated in changelogs, this was a BC break, because a changed semantic of smth that existed before is a BC break. Did it break anything? Of course it did! See: - https://github.com/doctrine/orm/issues/10049 - https://github.com/symfony/symfony/pull/46840 - https://github.com/Ocramius/GeneratedHydrator/issues/656 - https://github.com/opis/closure/issues/129 I believe there are still many places where the concept of "public" needs to be adjusted to fully support readonly properties. Now in PHP 8.4 asymmetry will be made explicit and will allow users to specify visibility for setters. However, the core issue remains unresolved: ```php final class User { public function __construct( public private(set) string $name = 'Bob', ) {} } $object = new User(); foreach ($object as $property => $value) { // Fatal error: Uncaught Error: Cannot modify private(set) property User::$name from global scope $object->{$property} = 'Jack'; } ``` I'd like to draw your attention to the fact that aviz introduces a BC break, despite saying "Backward Incompatible Changes: None. This syntax would have been a parse error before." While the syntax is new, it allows one to alter the old concept of public by changing set visibility. What can we do about it: 1. Explicitly introduce the concept of getter and setter visibility, preserve `ReflectionProperty::isPublic()` behavior from PHP <=8.0 and add `ReflectionProperty::(get|set)Is(Public|Protected|Private)` methods. I have explained all these ideas in https://externals.io/message/125740 . If this option is chosen, aviz will likely need to be reverted and reintroduced in PHP 8.5, since we're already in the feature freeze period. 2. Proceed with the current approach, but clearly explain the BC break in the changelog, and merge this PR https://github.com/php/php-src/pull/16209 to mitigate reflection issues as outlined in https://externals.io/message/125740.
-- Best regards, Valentin

Hammed Ajao

1 year ago
On Wed, Oct 9, 2024, 9:02 a.m. Valentin Udaltsov < udaltsov.valentin@gmail.com> wrote:
> Hi, internals! > > Since writing https://externals.io/message/125740 I've realized that > the major problem with aviz is actually simple but fundamental. > > In PHP <=8.0 this code is valid for an object of any user class: > > ```php > class User > { > public string $name = 'Bob'; > } > > $object = new User(); > > foreach ($object as $property => $value) { > $object->{$property} = 'Jack'; > } > ``` > > The same is true for Reflection API: once you check that `(new > ReflectionProperty(Foo::class, 'property'))->isPublic()`, you can > safely read property and write to it from any scope. > > Now let's jump to PHP 8.1+ with support for readonly properties. > > A readonly property is two functionalities in one: write-once and > private set. This means that `public readonly $property` is actually > `public(get) private(set) readonly $property`. Although it is marked > as `public`, it is not public because it is not a symmetric public > property! > > In PHP 8.1+, the following User class suddenly breaks the code above: > > ```php > class User > { > public function __construct( > public readonly string $name = 'Bob', > ) {} > } > > $object = new User(); > > foreach ($object as $property => $value) { > // Fatal error: Uncaught Error: Cannot modify readonly property > User::$name > $object->{$property} = 'Jack'; > } > ``` > > In other words, the meaning of `public` has changed in PHP 8.1. > Before, it used to mean "symmetric", now it means "symmetric unless > readonly". > > While not explicitly stated in changelogs, this was a BC break, > because a changed semantic of smth that existed before is a BC break. > > Did it break anything? Of course it did! See: > - https://github.com/doctrine/orm/issues/10049 > - https://github.com/symfony/symfony/pull/46840 > - https://github.com/Ocramius/GeneratedHydrator/issues/656 > - https://github.com/opis/closure/issues/129 > > I believe there are still many places where the concept of "public" > needs to be adjusted to fully support readonly properties. > > Now in PHP 8.4 asymmetry will be made explicit and will allow users to > specify visibility for setters. However, the core issue remains > unresolved: > > ```php > final class User > { > public function __construct( > public private(set) string $name = 'Bob', > ) {} > } > > $object = new User(); > > foreach ($object as $property => $value) { > // Fatal error: Uncaught Error: Cannot modify private(set) > property User::$name from global scope > $object->{$property} = 'Jack'; > } > ``` > > I'd like to draw your attention to the fact that aviz introduces a BC > break, despite saying "Backward Incompatible Changes: None. This > syntax would have been a parse error before." While the syntax is new, > it allows one to alter the old concept of public by changing set > visibility. > > What can we do about it: > 1. Explicitly introduce the concept of getter and setter visibility, > preserve `ReflectionProperty::isPublic()` behavior from PHP <=8.0 and > add `ReflectionProperty::(get|set)Is(Public|Protected|Private)` > methods. I have explained all these ideas in > https://externals.io/message/125740 . If this option is chosen, aviz > will likely need to be reverted and reintroduced in PHP 8.5, since > we're already in the feature freeze period. > 2. Proceed with the current approach, but clearly explain the BC break > in the changelog, and merge this PR > https://github.com/php/php-src/pull/16209 to mitigate reflection > issues as outlined in https://externals.io/message/125740. > > -- > Best regards, > Valentin >
Tbh we should consider voting to get rid of it, the costs are starting to outweigh the benefits (which aren't super clear to me). Cheers.

Kamil Tekiela

1 year ago
I have to admit I understood nothing from your email, but I got curious about some of your words.
> A readonly property is two functionalities in one: write-once and
private set. What do you mean it is private set? Readonly only means the property is writable once. It does not affect its visibility.
> While the syntax is new,
it allows one to alter the old concept of public by changing set visibility. Isn't that the whole point of asymmetric visibility? If you use the new syntax, you can change what public means. Code that doesn't use it will function as it did before. What is the BC break then?

Удальцов Валентин

1 year ago
On 09.10.2024 19:08, Kamil Tekiela <tekiela246@gmail.com> wrote:
> > I have to admit I understood nothing from your email, but I got > curious about some of your words.
Hi, Kamil! I tried my best :) Thank you for your interest!
> > A readonly property is two functionalities in one: write-once and > private set. > > What do you mean it is private set? Readonly only means the property > is writable once. It does not affect its visibility.
It in fact does affect visibility. For instance, you cannot write uninitialized public property from global scope: https://3v4l.org/4Xf2R The same fact is mentioned in the aviz RFC: https://wiki.php.net/rfc/asymmetric-visibility-v2#:~:text=The%20readonly%20flag%2C%20introduced%20in%20PHP%208.1%2C%20is%20really%20two%20flags%20in%20one
-- Valentin

Claude Pache

1 year ago
> Le 9 oct. 2024 à 17:01, Valentin Udaltsov <udaltsov.valentin@gmail.com> a écrit : > > Hi, internals! > > Since writing https://externals.io/message/125740 I've realized that > the major problem with aviz is actually simple but fundamental. > > In PHP <=8.0 this code is valid for an object of any user class: > > ```php > class User > { > public string $name = 'Bob'; > } > > $object = new User(); > > foreach ($object as $property => $value) { > $object->{$property} = 'Jack'; > } > ``` > > The same is true for Reflection API: once you check that `(new > ReflectionProperty(Foo::class, 'property'))->isPublic()`, you can > safely read property and write to it from any scope. > > Now let's jump to PHP 8.1+ with support for readonly properties. > > A readonly property is two functionalities in one: write-once and > private set. This means that `public readonly $property` is actually > `public(get) private(set) readonly $property`. Although it is marked > as `public`, it is not public because it is not a symmetric public > property! > > In PHP 8.1+, the following User class suddenly breaks the code above: > > ```php > class User > { > public function __construct( > public readonly string $name = 'Bob', > ) {} > } > > $object = new User(); > > foreach ($object as $property => $value) { > // Fatal error: Uncaught Error: Cannot modify readonly property User::$name > $object->{$property} = 'Jack'; > } > ``` > > In other words, the meaning of `public` has changed in PHP 8.1. > Before, it used to mean "symmetric", now it means "symmetric unless > readonly". > > While not explicitly stated in changelogs, this was a BC break, > because a changed semantic of smth that existed before is a BC break. > > Did it break anything? Of course it did! See: > - https://github.com/doctrine/orm/issues/10049 > - https://github.com/symfony/symfony/pull/46840 > - https://github.com/Ocramius/GeneratedHydrator/issues/656 > - https://github.com/opis/closure/issues/129 > > I believe there are still many places where the concept of "public" > needs to be adjusted to fully support readonly properties. > > Now in PHP 8.4 asymmetry will be made explicit and will allow users to > specify visibility for setters. However, the core issue remains > unresolved: > > ```php > final class User > { > public function __construct( > public private(set) string $name = 'Bob', > ) {} > } > > $object = new User(); > > foreach ($object as $property => $value) { > // Fatal error: Uncaught Error: Cannot modify private(set) > property User::$name from global scope > $object->{$property} = 'Jack'; > } > ``` > > I'd like to draw your attention to the fact that aviz introduces a BC > break, despite saying "Backward Incompatible Changes: None. This > syntax would have been a parse error before." While the syntax is new, > it allows one to alter the old concept of public by changing set > visibility. > > What can we do about it: > 1. Explicitly introduce the concept of getter and setter visibility, > preserve `ReflectionProperty::isPublic()` behavior from PHP <=8.0 and > add `ReflectionProperty::(get|set)Is(Public|Protected|Private)` > methods. I have explained all these ideas in > https://externals.io/message/125740 . If this option is chosen, aviz > will likely need to be reverted and reintroduced in PHP 8.5, since > we're already in the feature freeze period. > 2. Proceed with the current approach, but clearly explain the BC break > in the changelog, and merge this PR > https://github.com/php/php-src/pull/16209 to mitigate reflection > issues as outlined in https://externals.io/message/125740. > > -- > Best regards, > Valentin
Hi Valentin, There is no BC break, in the sense that code that worked under PHP 8.3 (and therefore use PHP 8.3 features only) will not break when run under PHP 8.4. Of course, code that makes assumptions that are true when using PHP 8.3 features only, will need to be adapted as soon as PHP 8.4 features are used. This is unsurprising and expected. Yes, it means that libraries that make use of Reflection are not automatically compatible with PHP 8.4+ without amendment. By nature, such libraries cannot claim to be compatible with arbitrary future versions of PHP. That said, https://github.com/php/php-src/pull/16209 is interesting to have, but not mandatory. The current `ReflectionProperty::isPropertySet()` and `ReflectionProperty::isPrivateSet()` might be somewhat confusing at first, but they are sufficient in order to obtain the needed information. —Claude

Удальцов Валентин

1 year ago
On 09.102024 at 19:20 Claude Pache <claude.pache@gmail.com> wrote:
> There is no BC break, in the sense that code that worked under PHP 8.3 (and therefore use PHP 8.3 features only) will not break when run under PHP 8.4. > > Of course, code that makes assumptions that are true when using PHP 8.3 features only, will need to be adapted as soon as PHP 8.4 features are used. This is unsurprising and expected.
Hi, Claude! Thank you for the explanation. I now get why aviz does not break BC :) Until now, I was worried that we were missing something important.
> That said, https://github.com/php/php-src/pull/16209 is interesting to have, but not mandatory. The current `ReflectionProperty::isPropertySet()` and `ReflectionProperty::isPrivateSet()` might be somewhat confusing at first, but they are sufficient in order to obtain the needed information.
Yes, they are sufficient, but very difficult to work with. Just to check that property is writable from global scope, you have to do `isPublic() && !isReadonly() && !isPrivateSet() && !isProtectedSet() && (!isVirtual() || hasHook(PropertyHookType::Set))`. See our discussion with Ilija: https://github.com/php/php-src/issues/16175#issuecomment-2389966021
-- Valentin

Rob Landers

1 year ago
On Thu, Oct 10, 2024, at 15:32, Valentin Udaltsov wrote:
> On 09.102024 at 19:20 Claude Pache <claude.pache@gmail.com> wrote: > > There is no BC break, in the sense that code that worked under PHP 8.3 (and therefore use PHP 8.3 features only) will not break when run under PHP 8.4. > > > > Of course, code that makes assumptions that are true when using PHP 8.3 features only, will need to be adapted as soon as PHP 8.4 features are used. This is unsurprising and expected. > > Hi, Claude! > > Thank you for the explanation. I now get why aviz does not break BC :) > Until now, I was worried that we were missing something important. > > > That said, https://github.com/php/php-src/pull/16209 is interesting to have, but not mandatory. The current `ReflectionProperty::isPropertySet()` and `ReflectionProperty::isPrivateSet()` might be somewhat confusing at first, but they are sufficient in order to obtain the needed information. > > Yes, they are sufficient, but very difficult to work with. Just to > check that property is writable from global scope, you have to do > `isPublic() && !isReadonly() && !isPrivateSet() && !isProtectedSet() > && (!isVirtual() || hasHook(PropertyHookType::Set))`. > See our discussion with Ilija: > https://github.com/php/php-src/issues/16175#issuecomment-2389966021 > > -- > Valentin >
Hello all, I am still struggling to understand how this isn't a BC break when it most obviously is. Sure, code that worked on 8.3 will continue to work on 8.4. In that case, we could have argued that my function autoloading RFC didn't have a BC break, because proper implementations wouldn't have broken. To me, this is along the same lines. A "proper" implementation won't break, but there may be subtle ways that "improper" implementations will break and thus it should be considered a BC break. — Rob

Jonathan Vollebregt

1 year ago
> A "proper" implementation won't break, but there may be subtle ways that "improper" implementations will break and thus it should be considered a BC break.
This thread is fallaciously equating breaks in third-party libraries _when changing consumer code_, with breaks just by updating PHP. If I'm in PHP 8.1+ and I pass an object into a library and all goes well, then I change a property to readonly and get an error, that's not PHP making a breaking change by allowing me to use readonly. That's an outdated library (and me) breaking my code. I've had my reflection code break on backwards compatible changes loads of times, but every time it required the user to make a change to their code first. Valentin's list of examples proves this point. They worked fine on 8.1 _until_ people changed code to add readonly. That's not a BC break. Same deal for aviz.

Rob Landers

1 year ago
On Fri, Oct 11, 2024, at 12:20, Jonathan Vollebregt wrote:
> > A "proper" implementation won't break, but there may be subtle ways that "improper" implementations will break and thus it should be considered a BC break. > > This thread is fallaciously equating breaks in third-party libraries > _when changing consumer code_, with breaks just by updating PHP. > > If I'm in PHP 8.1+ and I pass an object into a library and all goes > well, then I change a property to readonly and get an error, that's not > PHP making a breaking change by allowing me to use readonly. That's an > outdated library (and me) breaking my code. > > I've had my reflection code break on backwards compatible changes loads > of times, but every time it required the user to make a change to their > code first. > > Valentin's list of examples proves this point. They worked fine on 8.1 > _until_ people changed code to add readonly. That's not a BC break. Same > deal for aviz. >
I guess what I am saying is that we probably need a proper definition of "BC break". IMHO, adding a php version check to do something is probably a BC break. Serializers will need a version check, thus it is a BC break. — Rob

Jordan LeDoux

1 year ago
On Fri, Oct 11, 2024 at 3:34 AM Rob Landers <rob@bottled.codes> wrote:
> On Fri, Oct 11, 2024, at 12:20, Jonathan Vollebregt wrote: > > > A "proper" implementation won't break, but there may be subtle ways that > "improper" implementations will break and thus it should be considered a BC > break. > > This thread is fallaciously equating breaks in third-party libraries > _when changing consumer code_, with breaks just by updating PHP. > > If I'm in PHP 8.1+ and I pass an object into a library and all goes > well, then I change a property to readonly and get an error, that's not > PHP making a breaking change by allowing me to use readonly. That's an > outdated library (and me) breaking my code. > > I've had my reflection code break on backwards compatible changes loads > of times, but every time it required the user to make a change to their > code first. > > Valentin's list of examples proves this point. They worked fine on 8.1 > _until_ people changed code to add readonly. That's not a BC break. Same > deal for aviz. > > > I guess what I am saying is that we probably need a proper definition of > "BC break". IMHO, adding a php version check to do something is probably a > BC break. Serializers will need a version check, thus it is a BC break. > > — Rob >
Is this not something than has a really standard and consistent definition? "Code which runs correctly on the previous version of the project, if it is not updated, will also run correctly and provide the same output on the next version." Backwards compatible has never, in any work I've done through my entire career, meant something like "if you take old code and then update it to the new version incorrectly, it doesn't work"... that seems... obvious? What exactly is the claim being made here? Because it sounds like the claim is very much that second "definition". Jordan

Удальцов Валентин

1 year ago
On Mon, 14 Oct 2024 at 01:28, Jordan LeDoux <jordan.ledoux@gmail.com>:
> Backwards compatible has never, in any work I've done through my entire career, meant something like "if you take old code and then update it to the new version incorrectly, it doesn't work"... that seems... obvious? > > What exactly is the claim being made here? Because it sounds like the claim is very much that second "definition". > > Jordan
Hi, Jordan! The problem is that in practice most of the PHP libraries consider themselves to be compatible with newer PHP versions. For instance, Symfony PropertyInfo uses `"php": ">=8.2"` constraint in its `composer.json`. However, it is not compatible with PHP 8.4, I've just created an issue: https://github.com/symfony/symfony/issues/58556 The end user will be the victim, because `composer require symfony/property-info` will happily install property-info v7.1.4 for PHP 8.4, but it's not gonna work.
-- Valentin

Bilge

1 year ago
On 14/10/2024 01:02, Valentin Udaltsov wrote:
> The problem is that in practice most of the PHP libraries consider > themselves to be compatible with newer PHP versions. > > For instance, Symfony PropertyInfo uses `"php": ">=8.2"` constraint in > its `composer.json`.
That seems like a problem they have created for themselves. It seems an error to me to declare software forward-compatible with PHP versions that do not yet exist and thus have clearly not been tested against. Being as it is an error, we shouldn't consider it impinges on PHP's definition of a BC break. Cheers, Bilge

Удальцов Валентин

1 year ago
On Mon, 14/10/2024 04:07, Bilge <bilge@scriptfusion.com> wrote:
> > On 14/10/2024 01:02, Valentin Udaltsov wrote: > > The problem is that in practice most of the PHP libraries consider > > themselves to be compatible with newer PHP versions. > > > > For instance, Symfony PropertyInfo uses `"php": ">=8.2"` constraint in > > its `composer.json`. > > That seems like a problem they have created for themselves. It seems an > error to me to declare software forward-compatible with PHP versions > that do not yet exist and thus have clearly not been tested against. > Being as it is an error, we shouldn't consider it impinges on PHP's > definition of a BC break. > > Cheers, > Bilge
Hi, Bilge! I think that PHP should then clearly explain what is a BC break and what isn't on a separate php.net page. And even explain what php version constraints are safe for Composer libraries. Some languages have such a document: - https://go.dev/doc/go1compat - https://peps.python.org/pep-0387/
-- Valentin

Pierre Joye

1 year ago
Hello, On Mon, Oct 14, 2024, 8:07 AM Bilge <bilge@scriptfusion.com> wrote:
> On 14/10/2024 01:02, Valentin Udaltsov wrote: > > The problem is that in practice most of the PHP libraries consider > > themselves to be compatible with newer PHP versions. > > > > For instance, Symfony PropertyInfo uses `"php": ">=8.2"` constraint in > > its `composer.json`. > > That seems like a problem they have created for themselves. It seems an > error to me to declare software forward-compatible with PHP versions > that do not yet exist and thus have clearly not been tested against. > Being as it is an error, we shouldn't consider it impinges on PHP's > definition of a BC break. >
As much as I like this new feature and I am more than thankful for the work behind it, if a test in codes using a x.y version of php works but fails in x.y+1, it is a BC break, no matter how we look at it. A php dependency targeting x.* is very common. While it tends to be used less frequently as the amount of issues increase, that's not necessarly a good thing. In some cases it is a necessary evil (extension deprecated adding warnings, security fix requiring a bc break, f.e.). However, I am very doubtful here. And I do not know if it can be avoided while keeping the new behaviors. All in all, it would be great to at least agree that there is a BC break issue, so it can be addressed according, whatever the final decision is. best, Pierre

Jordan LeDoux

1 year ago
On Sun, Oct 13, 2024 at 5:03 PM Valentin Udaltsov < udaltsov.valentin@gmail.com> wrote:
> On Mon, 14 Oct 2024 at 01:28, Jordan LeDoux <jordan.ledoux@gmail.com>: > > Backwards compatible has never, in any work I've done through my entire > career, meant something like "if you take old code and then update it to > the new version incorrectly, it doesn't work"... that seems... obvious? > > > > What exactly is the claim being made here? Because it sounds like the > claim is very much that second "definition". > > > > Jordan > > Hi, Jordan! > > The problem is that in practice most of the PHP libraries consider > themselves to be compatible with newer PHP versions. > > For instance, Symfony PropertyInfo uses `"php": ">=8.2"` constraint in > its `composer.json`. However, it is not compatible with PHP 8.4, I've > just created an issue: https://github.com/symfony/symfony/issues/58556 > > The end user will be the victim, because `composer require > symfony/property-info` will happily install property-info v7.1.4 for > PHP 8.4, but it's not gonna work. > > -- > Valentin >
How does a library that uses code that will not even compile (like `readonly` or `private(set)`), but claims to not require a PHP version that uses the syntax, suddenly make a BC problem for the language? Composer allows libraries to set minimum PHP versions for releases. Any time you update your libraries, you may have to update your code which uses it. That's just part of how libraries work. Jordan

Удальцов Валентин

1 year ago
On Mon, 14/10/2024 05:01, Jordan LeDoux <jordan.ledoux@gmail.com>:
> > > > On Sun, Oct 13, 2024 at 5:03 PM Valentin Udaltsov <udaltsov.valentin@gmail.com> wrote: >> >> On Mon, 14 Oct 2024 at 01:28, Jordan LeDoux <jordan.ledoux@gmail.com>: >> > Backwards compatible has never, in any work I've done through my entire career, meant something like "if you take old code and then update it to the new version incorrectly, it doesn't work"... that seems... obvious? >> > >> > What exactly is the claim being made here? Because it sounds like the claim is very much that second "definition". >> > >> > Jordan >> >> Hi, Jordan! >> >> The problem is that in practice most of the PHP libraries consider >> themselves to be compatible with newer PHP versions. >> >> For instance, Symfony PropertyInfo uses `"php": ">=8.2"` constraint in >> its `composer.json`. However, it is not compatible with PHP 8.4, I've >> just created an issue: https://github.com/symfony/symfony/issues/58556 >> >> The end user will be the victim, because `composer require >> symfony/property-info` will happily install property-info v7.1.4 for >> PHP 8.4, but it's not gonna work. >> >> -- >> Valentin > > > How does a library that uses code that will not even compile (like `readonly` or `private(set)`), but claims to not require a PHP version that uses the syntax, suddenly make a BC problem for the language? Composer allows libraries to set minimum PHP versions for releases. Any time you update your libraries, you may have to update your code which uses it. That's just part of how libraries work. > > Jordan
First of all, I have already agreed above that PHP does not have a BC break here. Now we are discussing the potential problems in the PHP ecosystem and how they could be mitigated.
> Composer allows libraries to set minimum PHP versions for releases.
I think you've got the problem wrong. The problem is about the maximum version, not the minimum one. Consider the Symfony issue I've just reported: https://github.com/symfony/symfony/issues/58556 Symfony PropertyInfo requires `php >= 8.2`. And it is written in PHP 8.2 syntax. So it can be safely installed and used in PHP 8.2 and 8.3. In other words it's forward compatible. However, the `php >= 8.2` constraint also allows installing it in PHP 8.4. And as it turned out, PropertyInfo is not ready for 8.4 syntax (see my reproducer https://github.com/vudaltsov/symfony-property-access-php84). In my opinion, this is a problem, because a PHP 8.4 user can install the library without any obstacles and only later find out that `private (set)` properties do not work as expected there. Ideally `symfony/property-info` should not be installable until it ensures to be compatible with all the PHP 8.4 features. So, its PHP constraint should be `>=8.2 && <8.4`. And then `>=8.2 && <8.5`, once the tests pass for PHP 8.4 features.
-- Best regards, Valentin

Jonathan Vollebregt

1 year ago
On 10/9/24 5:01 PM, Valentin Udaltsov wrote:
> While not explicitly stated in changelogs, this was a BC break, > because a changed semantic of smth that existed before is a BC break.
Since readonly was only introduced in 8.1 this wasn't a BC break. You couldn't have a readonly property before so no pre-existing code would break.
> Did it break anything? Of course it did! See:
Again, none of these would break if using 8.0 code. They broke because someone added a PHP 8.1 readonly property to existing code and then tried reflecting/hydrating/serializing it with code that was only tested on 8.0. Now what _could_ be a BC break is when they made a load of internal PHP properties readonly but afaik that only happened on virtual properties that behaved that way already (Think DOMNode stuff) While I agree that `is(Public|Protected|Private)(Get|Set)` is a clearer solution, nothing about the current implementation breaks BC. - Jonathan