1
0
Fork 0

Added PHPStan rule that checks we don't use $this in closures.

pull/8471/head
Adam Žurek 2019-12-10 22:31:07 +01:00
parent 406a28708f
commit e5b13b4c8f
6 changed files with 125 additions and 2 deletions

1
.gitattributes vendored
View File

@ -15,3 +15,4 @@
.travis.yml export-ignore .travis.yml export-ignore
appveyor.yml export-ignore appveyor.yml export-ignore
phpunit.xml.dist export-ignore phpunit.xml.dist export-ignore
/phpstan/ export-ignore

View File

@ -66,8 +66,13 @@
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
"Composer\\Test\\": "tests/Composer/Test" "Composer\\Test\\": "tests/Composer/Test",
} "Composer\\PHPStanRules\\": "phpstan/Rules/src",
"Composer\\PHPStanRulesTests\\": "phpstan/Rules/tests"
},
"classmap": [
"phpstan/Rules/tests/data"
]
}, },
"bin": [ "bin": [
"bin/composer" "bin/composer"

View File

@ -0,0 +1,46 @@
<?php declare(strict_types = 1);
namespace Composer\PHPStanRules;
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
/**
* @phpstan-implements Rule<\PhpParser\Node\Expr\Variable>
*/
final class AnonymousFunctionWithThisRule implements Rule
{
/**
* @inheritDoc
*/
public function getNodeType(): string
{
return \PhpParser\Node\Expr\Variable::class;
}
/**
* @inheritDoc
*/
public function processNode(Node $node, Scope $scope): array
{
if (!\is_string($node->name) || $node->name !== 'this') {
return [];
}
if ($scope->isInClosureBind()) {
return [];
}
if (!$scope->isInClass()) {
// reported in other standard rule on level 0
return [];
}
if ($scope->isInAnonymousFunction()) {
return ['Using $this inside anonymous function is prohibited because of PHP 5.3 support.'];
}
return [];
}
}

View File

@ -0,0 +1,28 @@
<?php declare(strict_types = 1);
namespace Composer\PHPStanRulesTests;
use Composer\PHPStanRules\AnonymousFunctionWithThisRule;
use PHPStan\Testing\RuleTestCase;
/**
* @phpstan-extends RuleTestCase<AnonymousFunctionWithThisRule>
*/
final class AnonymousFunctionWithThisRuleTest extends RuleTestCase
{
/**
* @inheritDoc
*/
protected function getRule(): \PHPStan\Rules\Rule
{
return new AnonymousFunctionWithThisRule();
}
public function testWithThis(): void
{
$this->analyse([__DIR__ . '/data/method-with-this.php'], [
['Using $this inside anonymous function is prohibited because of PHP 5.3 support.', 13],
['Using $this inside anonymous function is prohibited because of PHP 5.3 support.', 17],
]);
}
}

View File

@ -0,0 +1,34 @@
<?php
class FirstClass
{
/**
* @var int
*/
private $firstProp = 9;
public function funMethod()
{
function() {
$this->firstProp;
};
call_user_func(function() {
$this->funMethod();
}, $this);
$bind = 'bind';
function() use($bind) {
};
}
}
function global_ok() {
$_SERVER['REMOTE_ADDR'];
}
function global_this() {
// not checked by our rule, it is checked with standard phpstan rule on level 0
$this['REMOTE_ADDR'];
}

View File

@ -23,6 +23,15 @@ parameters:
# we don't have different constructors for parent/child # we don't have different constructors for parent/child
- '~^Unsafe usage of new static\(\)\.$~' - '~^Unsafe usage of new static\(\)\.$~'
# hhvm should have support for $this in closures
-
count: 1
message: '~^Using \$this inside anonymous function is prohibited because of PHP 5\.3 support\.$~'
path: '../tests/Composer/Test/Repository/PlatformRepositoryTest.php'
paths: paths:
- ../src - ../src
- ../tests - ../tests
rules:
- Composer\PHPStanRules\AnonymousFunctionWithThisRule