Skip to content

Commit 4aff76f

Browse files
committed
Implement CallWithDeprecatedIniOptionRule
1 parent 81833b5 commit 4aff76f

File tree

4 files changed

+178
-0
lines changed

4 files changed

+178
-0
lines changed

rules.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ rules:
2222
- PHPStan\Rules\Deprecations\CallToDeprecatedFunctionRule
2323
- PHPStan\Rules\Deprecations\CallToDeprecatedMethodRule
2424
- PHPStan\Rules\Deprecations\CallToDeprecatedStaticMethodRule
25+
- PHPStan\Rules\Deprecations\CallWithDeprecatedIniOptionRule
2526
- PHPStan\Rules\Deprecations\FetchingClassConstOfDeprecatedClassRule
2627
- PHPStan\Rules\Deprecations\FetchingDeprecatedConstRule
2728
- PHPStan\Rules\Deprecations\ImplementationOfDeprecatedInterfaceRule
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Deprecations;
4+
5+
use PhpParser\Node;
6+
use PhpParser\Node\Expr\FuncCall;
7+
use PhpParser\Node\Name;
8+
use PHPStan\Analyser\Scope;
9+
use PHPStan\Broker\FunctionNotFoundException;
10+
use PHPStan\Php\PhpVersion;
11+
use PHPStan\Reflection\ReflectionProvider;
12+
use PHPStan\Rules\Rule;
13+
use PHPStan\Rules\RuleErrorBuilder;
14+
use function count;
15+
use function in_array;
16+
use function sprintf;
17+
use function strtolower;
18+
19+
/**
20+
* @implements Rule<FuncCall>
21+
*/
22+
class CallWithDeprecatedIniOptionRule implements Rule
23+
{
24+
25+
private const INI_FUNCTIONS = [
26+
'ini_get',
27+
'ini_set',
28+
'ini_alter',
29+
'ini_restore',
30+
];
31+
32+
private const DEPRECATED_OPTIONS = [
33+
'8.3' => [
34+
'assert.active',
35+
'assert.exception',
36+
'assert.bail',
37+
'assert.warning',
38+
],
39+
];
40+
41+
private ReflectionProvider $reflectionProvider;
42+
43+
private DeprecatedScopeHelper $deprecatedScopeHelper;
44+
45+
private PhpVersion $phpVersion;
46+
47+
public function __construct(
48+
ReflectionProvider $reflectionProvider,
49+
DeprecatedScopeHelper $deprecatedScopeHelper,
50+
PhpVersion $phpVersion
51+
)
52+
{
53+
$this->reflectionProvider = $reflectionProvider;
54+
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
55+
$this->phpVersion = $phpVersion;
56+
}
57+
58+
public function getNodeType(): string
59+
{
60+
return FuncCall::class;
61+
}
62+
63+
public function processNode(Node $node, Scope $scope): array
64+
{
65+
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
66+
return [];
67+
}
68+
69+
if (!($node->name instanceof Name)) {
70+
return [];
71+
}
72+
73+
if (count($node->getArgs()) < 1) {
74+
return [];
75+
}
76+
77+
try {
78+
$function = $this->reflectionProvider->getFunction($node->name, $scope);
79+
} catch (FunctionNotFoundException $e) {
80+
// Other rules will notify if the function is not found
81+
return [];
82+
}
83+
84+
if (!in_array(strtolower($function->getName()), self::INI_FUNCTIONS, true)) {
85+
return [];
86+
}
87+
88+
$phpVersion = $this->phpVersion->getMajorVersionId() . '.' . $this->phpVersion->getMinorVersionId();
89+
if (!isset(self::DEPRECATED_OPTIONS[$phpVersion])) {
90+
return [];
91+
}
92+
93+
$iniType = $scope->getType($node->getArgs()[0]->value);
94+
foreach ($iniType->getConstantStrings() as $string) {
95+
if (!in_array($string->getValue(), self::DEPRECATED_OPTIONS[$phpVersion], true)) {
96+
continue;
97+
}
98+
99+
return [
100+
RuleErrorBuilder::message(sprintf(
101+
"Call to function %s() with deprecated option '%s'.",
102+
$function->getName(),
103+
$string->getValue(),
104+
))->identifier('function.deprecated')->build(),
105+
];
106+
}
107+
108+
return [];
109+
}
110+
111+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Deprecations;
4+
5+
use PHPStan\Php\PhpVersion;
6+
use PHPStan\Rules\Rule;
7+
use PHPStan\Testing\RuleTestCase;
8+
use const PHP_VERSION_ID;
9+
10+
/**
11+
* @extends RuleTestCase<CallWithDeprecatedIniOptionRule>
12+
*/
13+
class CallWithDeprecatedIniOptionRuleTest extends RuleTestCase
14+
{
15+
16+
protected function getRule(): Rule
17+
{
18+
return new CallWithDeprecatedIniOptionRule(
19+
$this->createReflectionProvider(),
20+
new DeprecatedScopeHelper([new DefaultDeprecatedScopeResolver()]),
21+
self::getContainer()->getByType(PhpVersion::class),
22+
);
23+
}
24+
25+
public function testRule(): void
26+
{
27+
$expectedErrors = [];
28+
if (PHP_VERSION_ID >= 80300) {
29+
$expectedErrors = [
30+
[
31+
"Call to function ini_set() with deprecated option 'assert.active'.",
32+
11,
33+
],
34+
[
35+
"Call to function ini_get() with deprecated option 'assert.active'.",
36+
12,
37+
],
38+
];
39+
}
40+
41+
$this->analyse(
42+
[__DIR__ . '/data/call-with-deprecation-ini-option.php'],
43+
$expectedErrors,
44+
);
45+
}
46+
47+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace CallWithDeprecatedIniOption;
4+
5+
function doFooBar(): void {
6+
var_dump(ini_set('memory_limit', '2048M'));
7+
var_dump(ini_get('memory_limit'));
8+
}
9+
10+
function doFoo(): void {
11+
var_dump(ini_set('assert.active', false));
12+
var_dump(ini_get('assert.active'));
13+
}
14+
15+
/** @deprecated */
16+
function inDeprecatedFunction(): void {
17+
var_dump(ini_set('assert.active', false));
18+
var_dump(ini_get('assert.active'));
19+
}

0 commit comments

Comments
 (0)