Skip to content

Commit 610061d

Browse files
committed
Add ResourceOperationFuncCallRule
1 parent 2027cc2 commit 610061d

File tree

6 files changed

+112
-2
lines changed

6 files changed

+112
-2
lines changed

example/example.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
<?php
22
namespace SfpExample\PHPStan\DontOperationInsideConstructor;
33

4+
use function fopen;
5+
46
class Example
57
{
68
public function __construct()
79
{
810
$fileInfo = new \SplFileInfo('test');
911
$fileInfo->openFile('r');
12+
13+
fopen('test', 'r');
1014
}
1115

1216
public static function factory() : self

rules.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
rules:
22
- Sfp\PHPStan\DontOperationInsideConstructor\Rules\ResourceOperationMethodCallRule
3+
- Sfp\PHPStan\DontOperationInsideConstructor\Rules\ResourceOperationFuncCallRule
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sfp\PHPStan\DontOperationInsideConstructor\Rules;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Name;
9+
use PHPStan\Analyser\Scope;
10+
use PHPStan\Rules\Rule;
11+
use PHPStan\Rules\RuleError;
12+
use PHPStan\Rules\RuleErrorBuilder;
13+
use PHPStan\ShouldNotHappenException;
14+
use Sfp\ResourceOperations\ResourceOperations;
15+
16+
use function in_array;
17+
use function sprintf;
18+
19+
/**
20+
* @implements Rule<Node\Expr\FuncCall>
21+
*/
22+
final class ResourceOperationFuncCallRule implements Rule
23+
{
24+
public function getNodeType(): string
25+
{
26+
return Node\Expr\FuncCall::class;
27+
}
28+
29+
/**
30+
* @param Node\Expr\FuncCall $node
31+
* @return array|RuleError[]|string[]
32+
* @throws ShouldNotHappenException
33+
*/
34+
public function processNode(Node $node, Scope $scope): array
35+
{
36+
if ($scope->getFunctionName() !== '__construct') {
37+
return [];
38+
}
39+
40+
if (! $node->name instanceof Name) {
41+
return [];
42+
}
43+
44+
$errors = [];
45+
if (in_array($node->name->toString(), ResourceOperations::getFunctions(), true)) {
46+
$errors[] = RuleErrorBuilder::message(
47+
sprintf("Don't resource operation inside constructor. function %s() is called.", $node->name->toString())
48+
)->identifier('sfp-dont-operation.resourceOperationFuncCall')->build();
49+
}
50+
51+
return $errors;
52+
}
53+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SfpTest\PHPStan\DontOperationInsideConstructor\Rules;
6+
7+
use PHPStan\Rules\Rule;
8+
use PHPStan\Testing\RuleTestCase;
9+
use Sfp\PHPStan\DontOperationInsideConstructor\Rules\ResourceOperationFuncCallRule;
10+
11+
/**
12+
* @extends RuleTestCase<ResourceOperationFuncCallRule>
13+
* @covers \Sfp\PHPStan\DontOperationInsideConstructor\Rules\ResourceOperationFuncCallRule
14+
*/
15+
class ResourceOperationFuncCallRuleTest extends RuleTestCase
16+
{
17+
public function getRule(): Rule
18+
{
19+
return new ResourceOperationFuncCallRule();
20+
}
21+
22+
public function testProcess(): void
23+
{
24+
$this->analyse([__DIR__ . '/data/ResourceOperationFuncCall.php'], [
25+
[
26+
"Don't resource operation inside constructor. function fopen() is called.",
27+
13,
28+
],
29+
]);
30+
}
31+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SfpTest\PHPStan\DontOperationInsideConstructor\Rules\data;
6+
7+
use function fopen;
8+
9+
class ResourceOperationFuncCall
10+
{
11+
public function __construct()
12+
{
13+
$fp = fopen('test', 'r');
14+
15+
(function () {
16+
})();
17+
}
18+
}

test/example.output

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<testsuite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" failures="1" name="phpstan" tests="1" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/junit-team/junit5/r5.5.1/platform-tests/src/test/resources/jenkins-junit.xsd">
3-
<testcase name="example/example.php:9">
2+
<testsuite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" failures="2" name="phpstan" tests="2" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/junit-team/junit5/r5.5.1/platform-tests/src/test/resources/jenkins-junit.xsd">
3+
<testcase name="example/example.php:11">
44
<failure type="ERROR" message="Don't resource operation inside constructor. Method SplFileInfo::openfile() is called."/>
55
</testcase>
6+
<testcase name="example/example.php:13">
7+
<failure type="ERROR" message="Don't resource operation inside constructor. function fopen() is called."/>
8+
</testcase>
69
</testsuite>

0 commit comments

Comments
 (0)