diff --git a/config/set/order/order.yaml b/config/set/order/order.yaml
index f6d2c242ae1..543a0be162b 100644
--- a/config/set/order/order.yaml
+++ b/config/set/order/order.yaml
@@ -1,3 +1,4 @@
services:
Rector\Order\Rector\Class_\OrderPrivateMethodsByUseRector: null
Rector\Order\Rector\Class_\OrderPublicInterfaceMethodRector: null
+ Rector\Order\Rector\Class_\OrderPropertyByComplexityRector: null
diff --git a/docs/rector_rules_overview.md b/docs/rector_rules_overview.md
index 414053743a1..eefb9a2054a 100644
--- a/docs/rector_rules_overview.md
+++ b/docs/rector_rules_overview.md
@@ -1,4 +1,4 @@
-# All 500 Rectors Overview
+# All 501 Rectors Overview
- [Projects](#projects)
- [General](#general)
@@ -4873,6 +4873,40 @@ Order private methods in order of their use
+### `OrderPropertyByComplexityRector`
+
+- class: [`Rector\Order\Rector\Class_\OrderPropertyByComplexityRector`](/../master/rules/order/src/Rector/Class_/OrderPropertyByComplexityRector.php)
+- [test fixtures](/../master/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Fixture)
+
+Order properties by complexity, from the simplest like scalars to the most complex, like union or collections
+
+```diff
+-class SomeClass
++class SomeClass implements FoodRecipeInterface
+ {
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+- * @var Type
++ * @var int
+ */
+- private $service;
++ private $price;
+
+ /**
+- * @var int
++ * @var Type
+ */
+- private $price;
++ private $service;
+ }
+```
+
+
+
### `OrderPublicInterfaceMethodRector`
- class: [`Rector\Order\Rector\Class_\OrderPublicInterfaceMethodRector`](/../master/rules/order/src/Rector/Class_/OrderPublicInterfaceMethodRector.php)
diff --git a/rules/order/src/PropertyRanker.php b/rules/order/src/PropertyRanker.php
new file mode 100644
index 00000000000..3facbf5cf47
--- /dev/null
+++ b/rules/order/src/PropertyRanker.php
@@ -0,0 +1,54 @@
+getAttribute(AttributeKey::PHP_DOC_INFO);
+ if ($phpDocInfo === null) {
+ return 1;
+ }
+
+ $varType = $phpDocInfo->getVarType();
+ if ($varType instanceof StringType || $varType instanceof IntegerType || $varType instanceof BooleanType || $varType instanceof FloatType) {
+ return 5;
+ }
+
+ if ($varType instanceof ArrayType || $varType instanceof IterableType) {
+ return 10;
+ }
+
+ if ($varType instanceof TypeWithClassName) {
+ return 15;
+ }
+
+ if ($varType instanceof IntersectionType) {
+ return 20;
+ }
+
+ if ($varType instanceof UnionType) {
+ return 25;
+ }
+
+ throw new NotImplementedException(get_class($varType));
+ }
+}
diff --git a/rules/order/src/Rector/Class_/OrderPropertyByComplexityRector.php b/rules/order/src/Rector/Class_/OrderPropertyByComplexityRector.php
new file mode 100644
index 00000000000..6cf7f818145
--- /dev/null
+++ b/rules/order/src/Rector/Class_/OrderPropertyByComplexityRector.php
@@ -0,0 +1,156 @@
+stmtOrder = $stmtOrder;
+ $this->propertyRanker = $propertyRanker;
+ }
+
+ public function getDefinition(): RectorDefinition
+ {
+ return new RectorDefinition(
+ 'Order properties by complexity, from the simplest like scalars to the most complex, like union or collections',
+ [
+ new CodeSample(
+ <<<'PHP'
+class SomeClass
+{
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var Type
+ */
+ private $service;
+
+ /**
+ * @var int
+ */
+ private $price;
+}
+PHP
+,
+ <<<'PHP'
+class SomeClass implements FoodRecipeInterface
+{
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var int
+ */
+ private $price;
+
+ /**
+ * @var Type
+ */
+ private $service;
+}
+PHP
+
+ ),
+ ]
+ );
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getNodeTypes(): array
+ {
+ return [Class_::class];
+ }
+
+ /**
+ * @param Class_ $node
+ */
+ public function refactor(Node $node): ?Node
+ {
+ $propertyByVisibilityByPosition = $this->resolvePropertyByVisibilityByPosition($node);
+
+ foreach ($propertyByVisibilityByPosition as $propertyByPosition) {
+ $propertyNameToRank = [];
+ $propertyPositionByName = [];
+
+ foreach ($propertyByPosition as $position => $property) {
+ /** @var string $propertyName */
+ $propertyName = $this->getName($property);
+
+ $propertyPositionByName[$position] = $propertyName;
+ $propertyNameToRank[$propertyName] = $this->propertyRanker->rank($property);
+ }
+
+ asort($propertyNameToRank);
+ $sortedPropertyByRank = array_keys($propertyNameToRank);
+
+ $oldToNewKeys = $this->stmtOrder->createOldToNewKeys($propertyPositionByName, $sortedPropertyByRank);
+
+ $this->stmtOrder->reorderClassStmtsByOldToNewKeys($node, $oldToNewKeys);
+ }
+
+ return $node;
+ }
+
+ private function getVisibilityAsString(Property $property): string
+ {
+ if ($property->isPrivate()) {
+ return 'private';
+ }
+
+ if ($property->isProtected()) {
+ return 'protected';
+ }
+
+ return 'public';
+ }
+
+ /**
+ * @return Property[][]
+ */
+ private function resolvePropertyByVisibilityByPosition(Class_ $class): array
+ {
+ $propertyByVisibilityByPosition = [];
+ foreach ($class->stmts as $position => $classStmt) {
+ if (! $classStmt instanceof Property) {
+ continue;
+ }
+
+ $visibility = $this->getVisibilityAsString($classStmt);
+ $propertyByVisibilityByPosition[$visibility][$position] = $classStmt;
+ }
+
+ return $propertyByVisibilityByPosition;
+ }
+}
diff --git a/rules/order/src/StmtOrder.php b/rules/order/src/StmtOrder.php
index b937a9c2807..3afe19ed0f8 100644
--- a/rules/order/src/StmtOrder.php
+++ b/rules/order/src/StmtOrder.php
@@ -31,14 +31,28 @@ final class StmtOrder
public function reorderClassStmtsByOldToNewKeys(Class_ $node, array $oldToNewKeys): Class_
{
+ $reorderedStmts = [];
+
+ $stmtCount = count($node->stmts);
+
foreach ($node->stmts as $key => $stmt) {
- if (! isset($oldToNewKeys[$key])) {
+ if (! array_key_exists($key, $oldToNewKeys)) {
+ $reorderedStmts[$key] = $stmt;
continue;
}
// reorder here
$newKey = $oldToNewKeys[$key];
- $node->stmts[$newKey] = $stmt;
+
+ $reorderedStmts[$newKey] = $stmt;
+ }
+
+ for ($i = 0; $i < $stmtCount; ++$i) {
+ if (! array_key_exists($i, $reorderedStmts)) {
+ continue;
+ }
+
+ $node->stmts[$i] = $reorderedStmts[$i];
}
return $node;
diff --git a/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Fixture/complex_types.php.inc b/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Fixture/complex_types.php.inc
new file mode 100644
index 00000000000..dfd1d07d59b
--- /dev/null
+++ b/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Fixture/complex_types.php.inc
@@ -0,0 +1,102 @@
+ array (6)
+ * | start => 18
+ * | visibility => "public" (6)
+ * | static => FALSE
+ * | type => "method" (6)
+ * | name => "secondMethod" (12)
+ * | end => 29
+ */
+ private $arrayOfMixedPlusContent = [];
+}
+
+?>
+-----
+ array (6)
+ * | start => 18
+ * | visibility => "public" (6)
+ * | static => FALSE
+ * | type => "method" (6)
+ * | name => "secondMethod" (12)
+ * | end => 29
+ */
+ private $arrayOfMixedPlusContent = [];
+ /**
+ * @var ComplexType
+ */
+ private $anotherObject;
+ /**
+ * @var AnotherSimpleType
+ */
+ private $someObject;
+}
+
+?>
diff --git a/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Fixture/fixture.php.inc b/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Fixture/fixture.php.inc
new file mode 100644
index 00000000000..b0d728da641
--- /dev/null
+++ b/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Fixture/fixture.php.inc
@@ -0,0 +1,50 @@
+
+-----
+
diff --git a/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Fixture/skip_correct.php.inc b/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Fixture/skip_correct.php.inc
new file mode 100644
index 00000000000..092e2098ee5
--- /dev/null
+++ b/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Fixture/skip_correct.php.inc
@@ -0,0 +1,18 @@
+doTestFile($file);
+ }
+
+ public function provideData(): Iterator
+ {
+ return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
+ }
+
+ protected function getRectorClass(): string
+ {
+ return OrderPropertyByComplexityRector::class;
+ }
+}
diff --git a/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Source/AnotherSimpleType.php b/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Source/AnotherSimpleType.php
new file mode 100644
index 00000000000..4aaa686d189
--- /dev/null
+++ b/rules/order/tests/Rector/Class_/OrderPropertyByComplexityRector/Source/AnotherSimpleType.php
@@ -0,0 +1,10 @@
+