Skip to content

Conversation

@TomasVotruba
Copy link
Member

@TomasVotruba TomasVotruba commented Oct 13, 2025

Closes rectorphp/rector#9152

final class Product {
-    private string $name;
+    public string $name {
+        get { return $this->name; }
+        set { $this->name = ucfirst($value); }
+    }
-
-    public function getName(): string {
-        return $this->name;
-    }
-
-    public function setName(string $name): void {
-        $this->name = ucfirst($name);
-    }
}

Changing getters/setters to property hooks may have alter behavior, if the class is extended and uses getter, see https://3v4l.org/HIHXs
That's why it runs safely on final classes only.


If you're confident there is close to zero of such cases, you can enable option to run on non-final classes too:

use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withTreatClassesAsFinal()

@TomasVotruba TomasVotruba force-pushed the tv-property-hooks branch 4 times, most recently from 02658a0 to aa9c9a6 Compare October 13, 2025 21:39
@TomasVotruba TomasVotruba changed the title tv property hooks [PHP 8.4] Add PropertyHookRector (optional) Oct 13, 2025
@TomasVotruba TomasVotruba force-pushed the tv-property-hooks branch 2 times, most recently from 703e077 to e34e37a Compare October 14, 2025 07:24
Copy link
Member

@samsonasik samsonasik left a comment

Choose a reason for hiding this comment

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

This need test for readonly property which should be skipped.

https://3v4l.org/2g4ZM

property hook seems remove readonly flag based on the transformation.

@TomasVotruba
Copy link
Member Author

property hook seems remove readonly flag based on the transformation.

👍

Copy link
Member

@samsonasik samsonasik left a comment

Choose a reason for hiding this comment

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

If class->isReadonly(), all properties become readonly, so seems should be skipped as well.

@TomasVotruba
Copy link
Member Author

@samsonasik What if there is only getter property hook?

@samsonasik
Copy link
Member

@TomasVotruba that will error, see https://3v4l.org/aQhYo#v8.4.12

@TomasVotruba
Copy link
Member Author

@samsonasik I see 👍

if ($node->getProperties() === []) {
return null;
}

Copy link
Member

Choose a reason for hiding this comment

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

this should check if there is promoted property that is readonly, eg:

$constructClassMethod = $node->getMethod('__construct');

if ($constructClassMethod instanceof ClassMethod) {
       foreach ($constructClassMethod->params as $param) {
            // readonly param must be promoted property already, and can't have property hook
            if ($param->isReadonly()) {
                  return null;
            }
      }
}

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'm not sure if promoted properties should be covered, as those are usually set in the constructor.

If we change it to property hook, it will start look rather messy. Property will become non-promoted and constructor full of assings. I want to skip these.


Before:

final class SomeClass
{
    public function __construct(
        private int $value,
    )
    {
    }

    public function getValue()
    {
        return $this->value;
    }
}

After:

final class SomeClass
{
    public int $value {
        get => $this->value;
    }

    public function __construct(int $value)
    {
        $this->value = $value;
    }
}

Copy link
Member

@samsonasik samsonasik Oct 14, 2025

Choose a reason for hiding this comment

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

What I mean if there is another readonly promoted property, it should be skipped as well, same behaviour with normal readonly property.

I will create PR to skip mixed existing property with readonly promoted property.

Copy link
Member

Choose a reason for hiding this comment

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

@TomasVotruba I created new PR to skip if class has:

@TomasVotruba
Copy link
Member Author

Let's kick of first version, to try and iterate 👍

@TomasVotruba TomasVotruba enabled auto-merge (squash) October 14, 2025 20:50
@TomasVotruba TomasVotruba merged commit 4945203 into main Oct 14, 2025
52 checks passed
@TomasVotruba TomasVotruba deleted the tv-property-hooks branch October 14, 2025 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[php 8.4] Add property hooks upgrade - optional rule

3 participants