Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ lint:
--exclude tests/PHPStan/Rules/Properties/data/hooked-properties-without-bodies-in-class.php \
--exclude tests/PHPStan/Rules/Properties/data/readonly-property-hooks.php \
--exclude tests/PHPStan/Rules/Properties/data/readonly-property-hooks-in-interface.php \
--exclude tests/PHPStan/Rules/Properties/data/static-hooked-properties.php \
--exclude tests/PHPStan/Rules/Properties/data/static-hooked-property-in-interface.php \
--exclude tests/PHPStan/Rules/Properties/data/virtual-hooked-properties.php \
--exclude tests/PHPStan/Rules/Classes/data/bug-12281.php \
--exclude tests/PHPStan/Rules/Traits/data/bug-12281.php \
Expand Down
9 changes: 9 additions & 0 deletions src/Rules/Properties/PropertiesInInterfaceRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ public function processNode(Node $node, Scope $scope): array
];
}

if ($node->isStatic()) {
return [
RuleErrorBuilder::message('Hooked properties cannot be static.')
->nonIgnorable()
->identifier('property.hookedStaticInInterface')
->build(),
];
}

if ($this->hasAnyHookBody($node)) {
return [
RuleErrorBuilder::message('Interfaces cannot include property hooks with bodies.')
Expand Down
11 changes: 11 additions & 0 deletions src/Rules/Properties/PropertyInClassRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ public function processNode(Node $node, Scope $scope): array
}
}

if ($node->isStatic()) {
if ($node->hasHooks()) {
return [
RuleErrorBuilder::message('Hooked properties cannot be static.')
->nonIgnorable()
->identifier('property.hookedStatic')
->build(),
];
}
}

if ($node->isVirtual()) {
if ($node->getDefault() !== null) {
return [
Expand Down
22 changes: 22 additions & 0 deletions tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,26 @@ public function testPhp84AndReadonlyPropertyHooksInInterface(): void
]);
}

public function testPhp84AndStaticHookedPropertyInInterface(): void
{
if (PHP_VERSION_ID < 80400) {
$this->markTestSkipped('Test requires PHP 8.4 or later.');
}

$this->analyse([__DIR__ . '/data/static-hooked-property-in-interface.php'], [
[
'Hooked properties cannot be static.',
7,
],
[
'Hooked properties cannot be static.',
9,
],
[
'Hooked properties cannot be static.',
11,
],
]);
}

}
18 changes: 18 additions & 0 deletions tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,22 @@ public function testPhp84AndVirtualHookedProperties(): void
]);
}

public function testPhp84AndStaticHookedProperties(): void
{
if (PHP_VERSION_ID < 80400) {
$this->markTestSkipped('Test requires PHP 8.4 or later.');
}

$this->analyse([__DIR__ . '/data/static-hooked-properties.php'], [
[
'Hooked properties cannot be static.',
7,
],
[
'Hooked properties cannot be static.',
15,
],
]);
}

}
18 changes: 18 additions & 0 deletions tests/PHPStan/Rules/Properties/data/static-hooked-properties.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php declare(strict_types=1);

namespace StaticHookedProperties;

class HelloWorld
{
public static string $foo {
get => $this->foo;
set => $this->foo = $value;
}
}

abstract class HiWorld
{
public static string $foo {
get => 'dummy';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php declare(strict_types=1);

namespace StaticHookedPropertyInInterface;

interface HelloWorld
{
public static string $firstName { get; set; }

public static string $middleName { get; }

public static string $lastName { set; }
}
Loading