Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ Because PHPStan is a widely used static analysis tool in the PHP community. It a

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.

## What if I need to ignore a Rule in a certain Place?

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.

### Alternative Tools

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:
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
},
"autoload-dev": {
"psr-4": {
"Phauthentic\\PHPStanRules\\Tests\\": "tests/"
"Phauthentic\\PHPStanRules\\Tests\\": "tests/",
"App\\": "data/"
}
},
"authors": [
Expand Down
49 changes: 49 additions & 0 deletions data/DependencyConstraintsRuleFqcn/ExtendsAndImplements.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace App\Capability;

// This should be caught when checkFqcn is enabled with 'extends' reference type
class CustomDateTime extends \DateTime
{
}

// This should be caught when checkFqcn is enabled with 'implements' reference type
class CustomDateTimeInterface implements \DateTimeInterface
{
public function format(string $format): string
{
return '';
}

public function getTimezone(): \DateTimeZone|false
{
return false;
}

public function getOffset(): int
{
return 0;
}

public function getTimestamp(): int
{
return 0;
}

public function diff(\DateTimeInterface $targetObject, bool $absolute = false): \DateInterval
{
return new \DateInterval('P0D');
}

public function __wakeup(): void
{
}
}

// This should not be caught (allowed class)
class CustomException extends \Exception
{
}

41 changes: 41 additions & 0 deletions data/DependencyConstraintsRuleFqcn/InstanceofAndCatch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace App\Capability;

class InstanceofAndCatch
{
public function checkInstanceof($value): bool
{
// This should be caught when checkFqcn is enabled with 'instanceof' reference type
return $value instanceof \DateTime;
}

public function checkImmutableInstanceof($value): bool
{
// This should be caught when checkFqcn is enabled with 'instanceof' reference type
return $value instanceof \DateTimeImmutable;
}

public function handleException(): void
{
try {
throw new \Exception('test');
// This should be caught when checkFqcn is enabled with 'catch' reference type
} catch (\Exception $e) {
// Handle exception
}
}

public function handleMultipleExceptions(): void
{
try {
throw new \Exception('test');
// Both should be caught when checkFqcn is enabled with 'catch' reference type
} catch (\RuntimeException | \LogicException $e) {
// Handle exceptions
}
}
}

36 changes: 36 additions & 0 deletions data/DependencyConstraintsRuleFqcn/MixedUsageAllowed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace App\Capability;

// This file uses allowed classes both with use statements and FQCN
// None of these should trigger errors

use Exception;
use stdClass;

class MixedUsageAllowed
{
private stdClass $obj;

public function useStatement(): Exception
{
return new Exception('test');
}

public function fqcn(): \stdClass
{
return new \stdClass();
}

public function catchException(): void
{
try {
throw new \Exception('test');
} catch (\Exception $e) {
// Handle
}
}
}

39 changes: 39 additions & 0 deletions data/DependencyConstraintsRuleFqcn/MixedUsageForbidden.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace App\Capability;

// This file mixes use statements with FQCN for forbidden classes
// Both should be caught when enabled

use DateTime;
use DateTimeImmutable;

class MixedUsageForbidden
{
// Caught with use statement checking
public function useStatement(): DateTime
{
return new DateTime('now');
}

// Caught with FQCN checking when enabled
public function fqcnInstantiation()
{
return new \DateTime('now');
}

// Caught with use statement checking
public function useStatementImmutable(): DateTimeImmutable
{
return new DateTimeImmutable('now');
}

// Caught with FQCN checking when enabled
public function fqcnImmutable(): \DateTimeImmutable
{
return new \DateTimeImmutable('now');
}
}

27 changes: 27 additions & 0 deletions data/DependencyConstraintsRuleFqcn/NewInstantiation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace App\Capability;

class NewInstantiation
{
public function createDate()
{
// This should be caught when checkFqcn is enabled with 'new' reference type
return new \DateTime('now');
}

public function createImmutableDate()
{
// This should be caught when checkFqcn is enabled with 'new' reference type
return new \DateTimeImmutable('now');
}

public function createAllowedClass()
{
// This should not be caught
return new \stdClass();
}
}

48 changes: 48 additions & 0 deletions data/DependencyConstraintsRuleFqcn/SelectiveReferenceTypes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace App\Capability;

class SelectiveReferenceTypes
{
// Property type hint
private \DateTime $property;

// Constructor with param type hint
public function __construct(\DateTime $param)
{
$this->property = $param;
}

// Return type hint
public function getDate(): \DateTime
{
return $this->property;
}

// New instantiation
public function createNew()
{
return new \DateTime('now');
}

// Static call
public function createFromFormat()
{
return \DateTime::createFromFormat('Y-m-d', '2023-01-01');
}

// Class constant
public function getClassName()
{
return \DateTime::class;
}

// instanceof
public function checkType($value): bool
{
return $value instanceof \DateTime;
}
}

45 changes: 45 additions & 0 deletions data/DependencyConstraintsRuleFqcn/StaticCalls.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace App\Capability;

class StaticCalls
{
public function createFromFormat()
{
// This should be caught when checkFqcn is enabled with 'static_call' reference type
return \DateTime::createFromFormat('Y-m-d', '2023-01-01');
}

public function createImmutableFromFormat()
{
// This should be caught when checkFqcn is enabled with 'static_call' reference type
return \DateTimeImmutable::createFromFormat('Y-m-d', '2023-01-01');
}

public function getAtomConstant()
{
// This should be caught when checkFqcn is enabled with 'static_property' reference type
return \DateTime::ATOM;
}

public function getClassConstant()
{
// This should be caught when checkFqcn is enabled with 'class_const' reference type
return \DateTime::class;
}

public function getImmutableClassConstant()
{
// This should be caught when checkFqcn is enabled with 'class_const' reference type
return \DateTimeImmutable::class;
}

public function getAllowedClassConstant()
{
// This should not be caught
return \stdClass::class;
}
}

57 changes: 57 additions & 0 deletions data/DependencyConstraintsRuleFqcn/TypeHints.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace App\Capability;

class TypeHints
{
// This should be caught when checkFqcn is enabled with 'property' reference type
private \DateTime $dateTime;

private \DateTimeImmutable $immutableDateTime;

private \stdClass $allowed;

// This should be caught when checkFqcn is enabled with 'param' reference type
public function setDateTime(\DateTime $date): void
{
$this->dateTime = $date;
}

// This should be caught when checkFqcn is enabled with 'param' reference type
public function setImmutableDateTime(\DateTimeImmutable $date): void
{
$this->immutableDateTime = $date;
}

// This should be caught when checkFqcn is enabled with 'return' reference type
public function getDateTime(): \DateTime
{
return $this->dateTime;
}

// This should be caught when checkFqcn is enabled with 'return' reference type
public function getImmutableDateTime(): \DateTimeImmutable
{
return $this->immutableDateTime;
}

public function getAllowed(): \stdClass
{
return $this->allowed;
}

// Test nullable types
public function getNullableDateTime(): ?\DateTime
{
return null;
}

// Test union types (PHP 8.0+)
public function getUnionType(): \DateTime|\DateTimeImmutable
{
return $this->dateTime;
}
}

Loading