Skip to content

Commit 4507adf

Browse files
arshidkv12Arshid
andauthored
Add rector to migrate __sleep() to __serialize() (#7212)
* Add rector to migrate __sleep() to __serialize() * Add rector to migrate __sleep() to __serialize() * Sleep method * Add rector to migrate __sleep() to __serialize() * Add rector to migrate __sleep() to __serialize() * SleepToSerializeRector * SleepToSerializeRector_Class * SleepToSerializeRector_Class * SleepToSerializeRector_Class * SleepToSerializeRector_Class --------- Co-authored-by: Arshid <[email protected]>
1 parent e00f52f commit 4507adf

8 files changed

Lines changed: 243 additions & 0 deletions

File tree

config/set/php85.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Rector\Config\RectorConfig;
1010
use Rector\Php85\Rector\ArrayDimFetch\ArrayFirstLastRector;
1111
use Rector\Php85\Rector\ClassMethod\NullDebugInfoReturnRector;
12+
use Rector\Php85\Rector\Class_\SleepToSerializeRector;
1213
use Rector\Php85\Rector\Const_\DeprecatedAnnotationToDeprecatedAttributeRector;
1314
use Rector\Php85\Rector\FuncCall\ArrayKeyExistsNullToEmptyStringRector;
1415
use Rector\Php85\Rector\FuncCall\ChrArgModuloRector;
@@ -38,6 +39,7 @@
3839
ColonAfterSwitchCaseRector::class,
3940
ArrayKeyExistsNullToEmptyStringRector::class,
4041
ChrArgModuloRector::class,
42+
SleepToSerializeRector::class,
4143
OrdSingleByteRector::class,
4244
]
4345
);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Rector\Tests\Php85\Rector\Class_\SleepToSerializeRector\Fixture;
5+
6+
class SkipSleepEmpty {
7+
private $id;
8+
private $name;
9+
10+
public function __sleep(): array {
11+
return [];
12+
}
13+
}
14+
?>
15+
?>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Rector\Tests\Php85\Rector\Class_\SleepToSerializeRector\Fixture;
5+
6+
class SkipSleepNull {
7+
private $id;
8+
private $name;
9+
10+
public function __sleep() {
11+
return null;
12+
}
13+
}
14+
?>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Rector\Tests\Php85\Rector\Class_\SleepToSerializeRector\Fixture;
5+
6+
class User {
7+
private $id;
8+
private $name;
9+
10+
public function __sleep() {
11+
return ['id', 'name'];
12+
}
13+
}
14+
?>
15+
-----
16+
<?php
17+
declare(strict_types=1);
18+
19+
namespace Rector\Tests\Php85\Rector\Class_\SleepToSerializeRector\Fixture;
20+
21+
class User {
22+
private $id;
23+
private $name;
24+
25+
public function __serialize(): array {
26+
return ['id' => $this->id, 'name' => $this->name];
27+
}
28+
}
29+
?>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Php85\Rector\Class_\SleepToSerializeRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class SleepToSerializeRectorTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/configured_rule.php';
27+
}
28+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\Php85\Rector\Class_\SleepToSerializeRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->rule(SleepToSerializeRector::class);
10+
};
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Php85\Rector\Class_;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\Array_;
9+
use PhpParser\Node\Expr\ArrayItem;
10+
use PhpParser\Node\Expr\PropertyFetch;
11+
use PhpParser\Node\Identifier;
12+
use PhpParser\Node\Stmt\Class_;
13+
use PhpParser\Node\Stmt\ClassMethod;
14+
use Rector\PhpParser\Node\BetterNodeFinder;
15+
use Rector\Rector\AbstractRector;
16+
use Rector\TypeDeclaration\NodeAnalyzer\ReturnAnalyzer;
17+
use Rector\ValueObject\PhpVersionFeature;
18+
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
19+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
20+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
21+
22+
/**
23+
* @see https://3v4l.org/51uu0
24+
* @see https://3v4l.org/ktJnk
25+
* @see https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_the_sleep_and_wakeup_magic_methods
26+
* @see \Rector\Tests\Php85\Rector\Class_\SleepToSerializeRector\SleepToSerializeRectorTest
27+
*/
28+
final class SleepToSerializeRector extends AbstractRector implements MinPhpVersionInterface
29+
{
30+
public function __construct(
31+
private BetterNodeFinder $betterNodeFinder,
32+
private ReturnAnalyzer $returnAnalyzer
33+
) {
34+
}
35+
36+
public function provideMinPhpVersion(): int
37+
{
38+
return PhpVersionFeature::DEPRECATED_METHOD_SLEEP;
39+
}
40+
41+
public function getRuleDefinition(): RuleDefinition
42+
{
43+
return new RuleDefinition(
44+
'Change __sleep() to __serialize() with correct return values',
45+
[
46+
new CodeSample(
47+
<<<'CODE_SAMPLE'
48+
class User {
49+
private $id;
50+
private $name;
51+
52+
public function __sleep() {
53+
return ['id', 'name'];
54+
}
55+
}
56+
CODE_SAMPLE
57+
,
58+
<<<'CODE_SAMPLE'
59+
class User {
60+
private $id;
61+
private $name;
62+
63+
public function __serialize(): array {
64+
return [
65+
'id' => $this->id,
66+
'name' => $this->name,
67+
];
68+
}
69+
}
70+
CODE_SAMPLE
71+
),
72+
]
73+
);
74+
}
75+
76+
/**
77+
* @return array<class-string<Node>>
78+
*/
79+
public function getNodeTypes(): array
80+
{
81+
return [Class_::class];
82+
}
83+
84+
/**
85+
* @param Class_ $node
86+
*/
87+
public function refactor(Node $node): ?Node
88+
{
89+
if ($node->getMethod('__serialize') instanceof ClassMethod) {
90+
return null;
91+
}
92+
93+
$classMethod = $node->getMethod('__sleep');
94+
if (! $classMethod instanceof ClassMethod) {
95+
return null;
96+
}
97+
98+
if ($classMethod->returnType instanceof Identifier && $this->isName($classMethod->returnType, 'array')) {
99+
return null;
100+
}
101+
102+
$returns = $this->betterNodeFinder->findReturnsScoped($classMethod);
103+
if (! $this->returnAnalyzer->hasOnlyReturnWithExpr($classMethod, $returns)) {
104+
return null;
105+
}
106+
107+
$hasChanged = false;
108+
foreach ($returns as $return) {
109+
if (! $return->expr instanceof Array_) {
110+
return null;
111+
}
112+
113+
if (count($return->expr->items) > 0) {
114+
$newItems = [];
115+
foreach ($return->expr->items as $item) {
116+
if ($item !== null && $item->value instanceof Node\Scalar\String_) {
117+
$propName = $item->value->value;
118+
$newItems[] = new ArrayItem(
119+
new PropertyFetch(new Node\Expr\Variable('this'), $propName),
120+
$item->value
121+
);
122+
}
123+
}
124+
if (count($newItems) > 0) {
125+
$hasChanged = true;
126+
$return->expr->items = $newItems;
127+
}
128+
}
129+
}
130+
131+
if ($hasChanged) {
132+
$classMethod->name = new Identifier('__serialize');
133+
$classMethod->returnType = new Identifier('array');
134+
return $node;
135+
}
136+
137+
return null;
138+
}
139+
}

src/ValueObject/PhpVersionFeature.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,12 @@ final class PhpVersionFeature
811811
*/
812812
public const DEPRECATE_OUTSIDE_INTERVEL_VAL_IN_CHR_FUNCTION = PhpVersion::PHP_85;
813813

814+
/**
815+
* @see https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_the_sleep_and_wakeup_magic_methods
816+
* @var int
817+
*/
818+
public const DEPRECATED_METHOD_SLEEP = PhpVersion::PHP_85;
819+
814820
/**
815821
* @see https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_passing_string_which_are_not_one_byte_long_to_ord
816822
* @var int

0 commit comments

Comments
 (0)