Skip to content

Commit a9a24da

Browse files
committed
Implement CallWithDeprecatedIniOptionRule
1 parent 81833b5 commit a9a24da

File tree

4 files changed

+177
-0
lines changed

4 files changed

+177
-0
lines changed

rules.neon

+1
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
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
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 array_key_exists;
15+
use function count;
16+
use function in_array;
17+
use function sprintf;
18+
use function strtolower;
19+
20+
/**
21+
* @implements Rule<FuncCall>
22+
*/
23+
class CallWithDeprecatedIniOptionRule implements Rule
24+
{
25+
26+
private const INI_FUNCTIONS = [
27+
'ini_get',
28+
'ini_set',
29+
'ini_alter',
30+
'ini_restore',
31+
];
32+
33+
private const DEPRECATED_OPTIONS = [
34+
'assert.active' => 80300,
35+
'assert.exception' => 80300,
36+
'assert.bail' => 80300,
37+
'assert.warning' => 80300,
38+
];
39+
40+
private ReflectionProvider $reflectionProvider;
41+
42+
private DeprecatedScopeHelper $deprecatedScopeHelper;
43+
44+
private PhpVersion $phpVersion;
45+
46+
public function __construct(
47+
ReflectionProvider $reflectionProvider,
48+
DeprecatedScopeHelper $deprecatedScopeHelper,
49+
PhpVersion $phpVersion
50+
)
51+
{
52+
$this->reflectionProvider = $reflectionProvider;
53+
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
54+
$this->phpVersion = $phpVersion;
55+
}
56+
57+
public function getNodeType(): string
58+
{
59+
return FuncCall::class;
60+
}
61+
62+
public function processNode(Node $node, Scope $scope): array
63+
{
64+
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
65+
return [];
66+
}
67+
68+
if (!($node->name instanceof Name)) {
69+
return [];
70+
}
71+
72+
if (count($node->getArgs()) < 1) {
73+
return [];
74+
}
75+
76+
try {
77+
$function = $this->reflectionProvider->getFunction($node->name, $scope);
78+
} catch (FunctionNotFoundException $e) {
79+
// Other rules will notify if the function is not found
80+
return [];
81+
}
82+
83+
if (!in_array(strtolower($function->getName()), self::INI_FUNCTIONS, true)) {
84+
return [];
85+
}
86+
87+
$phpVersionId = $this->phpVersion->getVersionId();
88+
$iniType = $scope->getType($node->getArgs()[0]->value);
89+
foreach ($iniType->getConstantStrings() as $string) {
90+
if (!array_key_exists($string->getValue(), self::DEPRECATED_OPTIONS)) {
91+
continue;
92+
}
93+
94+
if ($phpVersionId < self::DEPRECATED_OPTIONS[$string->getValue()]) {
95+
continue;
96+
}
97+
98+
return [
99+
RuleErrorBuilder::message(sprintf(
100+
"Call to function %s() with deprecated option '%s'.",
101+
$function->getName(),
102+
$string->getValue(),
103+
))->identifier('function.deprecated')->build(),
104+
];
105+
}
106+
107+
return [];
108+
}
109+
110+
}
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+
}
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)