Skip to content

Commit 6dc223b

Browse files
author
Florian Krämer
committed
Extending the dependency constraints rule
1 parent bcff346 commit 6dc223b

File tree

37 files changed

+1204
-65
lines changed

37 files changed

+1204
-65
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ Because PHPStan is a widely used static analysis tool in the PHP community. It a
4949

5050
It is also more or less easy to write your own rules if you need to enforce something specific that is not covered by the existing rules.
5151

52+
## What if I need to ignore a Rule in a certain Place?
53+
54+
Use the inline annotations PHPStan provides and add a comment explaining *why* in this case the rule is allowed to be broken. An inline annotation is the best because you should keep the information close to where it happens, visible right at the root of the problem.
55+
5256
### Alternative Tools
5357

5458
If you don't like this library, you can also check out other tools. Some of them provide a fluent interface instead of a Regex. If this feels more comfortable for you, you might want to check them out:

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
},
1414
"autoload-dev": {
1515
"psr-4": {
16-
"Phauthentic\\PHPStanRules\\Tests\\": "tests/"
16+
"Phauthentic\\PHPStanRules\\Tests\\": "tests/",
17+
"App\\": "data/"
1718
}
1819
},
1920
"authors": [
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Capability;
6+
7+
// This should be caught when checkFqcn is enabled with 'extends' reference type
8+
class CustomDateTime extends \DateTime
9+
{
10+
}
11+
12+
// This should be caught when checkFqcn is enabled with 'implements' reference type
13+
class CustomDateTimeInterface implements \DateTimeInterface
14+
{
15+
public function format(string $format): string
16+
{
17+
return '';
18+
}
19+
20+
public function getTimezone(): \DateTimeZone|false
21+
{
22+
return false;
23+
}
24+
25+
public function getOffset(): int
26+
{
27+
return 0;
28+
}
29+
30+
public function getTimestamp(): int
31+
{
32+
return 0;
33+
}
34+
35+
public function diff(\DateTimeInterface $targetObject, bool $absolute = false): \DateInterval
36+
{
37+
return new \DateInterval('P0D');
38+
}
39+
40+
public function __wakeup(): void
41+
{
42+
}
43+
}
44+
45+
// This should not be caught (allowed class)
46+
class CustomException extends \Exception
47+
{
48+
}
49+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Capability;
6+
7+
class InstanceofAndCatch
8+
{
9+
public function checkInstanceof($value): bool
10+
{
11+
// This should be caught when checkFqcn is enabled with 'instanceof' reference type
12+
return $value instanceof \DateTime;
13+
}
14+
15+
public function checkImmutableInstanceof($value): bool
16+
{
17+
// This should be caught when checkFqcn is enabled with 'instanceof' reference type
18+
return $value instanceof \DateTimeImmutable;
19+
}
20+
21+
public function handleException(): void
22+
{
23+
try {
24+
throw new \Exception('test');
25+
// This should be caught when checkFqcn is enabled with 'catch' reference type
26+
} catch (\Exception $e) {
27+
// Handle exception
28+
}
29+
}
30+
31+
public function handleMultipleExceptions(): void
32+
{
33+
try {
34+
throw new \Exception('test');
35+
// Both should be caught when checkFqcn is enabled with 'catch' reference type
36+
} catch (\RuntimeException | \LogicException $e) {
37+
// Handle exceptions
38+
}
39+
}
40+
}
41+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Capability;
6+
7+
// This file uses allowed classes both with use statements and FQCN
8+
// None of these should trigger errors
9+
10+
use Exception;
11+
use stdClass;
12+
13+
class MixedUsageAllowed
14+
{
15+
private stdClass $obj;
16+
17+
public function useStatement(): Exception
18+
{
19+
return new Exception('test');
20+
}
21+
22+
public function fqcn(): \stdClass
23+
{
24+
return new \stdClass();
25+
}
26+
27+
public function catchException(): void
28+
{
29+
try {
30+
throw new \Exception('test');
31+
} catch (\Exception $e) {
32+
// Handle
33+
}
34+
}
35+
}
36+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Capability;
6+
7+
// This file mixes use statements with FQCN for forbidden classes
8+
// Both should be caught when enabled
9+
10+
use DateTime;
11+
use DateTimeImmutable;
12+
13+
class MixedUsageForbidden
14+
{
15+
// Caught with use statement checking
16+
public function useStatement(): DateTime
17+
{
18+
return new DateTime('now');
19+
}
20+
21+
// Caught with FQCN checking when enabled
22+
public function fqcnInstantiation()
23+
{
24+
return new \DateTime('now');
25+
}
26+
27+
// Caught with use statement checking
28+
public function useStatementImmutable(): DateTimeImmutable
29+
{
30+
return new DateTimeImmutable('now');
31+
}
32+
33+
// Caught with FQCN checking when enabled
34+
public function fqcnImmutable(): \DateTimeImmutable
35+
{
36+
return new \DateTimeImmutable('now');
37+
}
38+
}
39+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Capability;
6+
7+
class NewInstantiation
8+
{
9+
public function createDate()
10+
{
11+
// This should be caught when checkFqcn is enabled with 'new' reference type
12+
return new \DateTime('now');
13+
}
14+
15+
public function createImmutableDate()
16+
{
17+
// This should be caught when checkFqcn is enabled with 'new' reference type
18+
return new \DateTimeImmutable('now');
19+
}
20+
21+
public function createAllowedClass()
22+
{
23+
// This should not be caught
24+
return new \stdClass();
25+
}
26+
}
27+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Capability;
6+
7+
class SelectiveReferenceTypes
8+
{
9+
// Property type hint
10+
private \DateTime $property;
11+
12+
// Constructor with param type hint
13+
public function __construct(\DateTime $param)
14+
{
15+
$this->property = $param;
16+
}
17+
18+
// Return type hint
19+
public function getDate(): \DateTime
20+
{
21+
return $this->property;
22+
}
23+
24+
// New instantiation
25+
public function createNew()
26+
{
27+
return new \DateTime('now');
28+
}
29+
30+
// Static call
31+
public function createFromFormat()
32+
{
33+
return \DateTime::createFromFormat('Y-m-d', '2023-01-01');
34+
}
35+
36+
// Class constant
37+
public function getClassName()
38+
{
39+
return \DateTime::class;
40+
}
41+
42+
// instanceof
43+
public function checkType($value): bool
44+
{
45+
return $value instanceof \DateTime;
46+
}
47+
}
48+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Capability;
6+
7+
class StaticCalls
8+
{
9+
public function createFromFormat()
10+
{
11+
// This should be caught when checkFqcn is enabled with 'static_call' reference type
12+
return \DateTime::createFromFormat('Y-m-d', '2023-01-01');
13+
}
14+
15+
public function createImmutableFromFormat()
16+
{
17+
// This should be caught when checkFqcn is enabled with 'static_call' reference type
18+
return \DateTimeImmutable::createFromFormat('Y-m-d', '2023-01-01');
19+
}
20+
21+
public function getAtomConstant()
22+
{
23+
// This should be caught when checkFqcn is enabled with 'static_property' reference type
24+
return \DateTime::ATOM;
25+
}
26+
27+
public function getClassConstant()
28+
{
29+
// This should be caught when checkFqcn is enabled with 'class_const' reference type
30+
return \DateTime::class;
31+
}
32+
33+
public function getImmutableClassConstant()
34+
{
35+
// This should be caught when checkFqcn is enabled with 'class_const' reference type
36+
return \DateTimeImmutable::class;
37+
}
38+
39+
public function getAllowedClassConstant()
40+
{
41+
// This should not be caught
42+
return \stdClass::class;
43+
}
44+
}
45+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Capability;
6+
7+
class TypeHints
8+
{
9+
// This should be caught when checkFqcn is enabled with 'property' reference type
10+
private \DateTime $dateTime;
11+
12+
private \DateTimeImmutable $immutableDateTime;
13+
14+
private \stdClass $allowed;
15+
16+
// This should be caught when checkFqcn is enabled with 'param' reference type
17+
public function setDateTime(\DateTime $date): void
18+
{
19+
$this->dateTime = $date;
20+
}
21+
22+
// This should be caught when checkFqcn is enabled with 'param' reference type
23+
public function setImmutableDateTime(\DateTimeImmutable $date): void
24+
{
25+
$this->immutableDateTime = $date;
26+
}
27+
28+
// This should be caught when checkFqcn is enabled with 'return' reference type
29+
public function getDateTime(): \DateTime
30+
{
31+
return $this->dateTime;
32+
}
33+
34+
// This should be caught when checkFqcn is enabled with 'return' reference type
35+
public function getImmutableDateTime(): \DateTimeImmutable
36+
{
37+
return $this->immutableDateTime;
38+
}
39+
40+
public function getAllowed(): \stdClass
41+
{
42+
return $this->allowed;
43+
}
44+
45+
// Test nullable types
46+
public function getNullableDateTime(): ?\DateTime
47+
{
48+
return null;
49+
}
50+
51+
// Test union types (PHP 8.0+)
52+
public function getUnionType(): \DateTime|\DateTimeImmutable
53+
{
54+
return $this->dateTime;
55+
}
56+
}
57+

0 commit comments

Comments
 (0)