Skip to content

Commit 0cbbfba

Browse files
committed
PHP 8 supports %h and %H in printf/sprintf
1 parent 82596f5 commit 0cbbfba

File tree

4 files changed

+44
-2
lines changed

4 files changed

+44
-2
lines changed

src/Php/PhpVersion.php

+5
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,9 @@ public function throwsTypeErrorForInternalFunctions(): bool
9696
return $this->versionId >= 80000;
9797
}
9898

99+
public function supportsHhPrintfSpecifier(): bool
100+
{
101+
return $this->versionId >= 80000;
102+
}
103+
99104
}

src/Rules/Functions/PrintfParametersRule.php

+16-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PhpParser\Node;
66
use PhpParser\Node\Expr\FuncCall;
77
use PHPStan\Analyser\Scope;
8+
use PHPStan\Php\PhpVersion;
89
use PHPStan\Rules\RuleErrorBuilder;
910
use PHPStan\Type\TypeUtils;
1011

@@ -14,6 +15,13 @@
1415
class PrintfParametersRule implements \PHPStan\Rules\Rule
1516
{
1617

18+
private PhpVersion $phpVersion;
19+
20+
public function __construct(PhpVersion $phpVersion)
21+
{
22+
$this->phpVersion = $phpVersion;
23+
}
24+
1725
public function getNodeType(): string
1826
{
1927
return FuncCall::class;
@@ -94,7 +102,14 @@ public function processNode(Node $node, Scope $scope): array
94102

95103
private function getPlaceholdersCount(string $functionName, string $format): int
96104
{
97-
$specifiers = in_array($functionName, ['sprintf', 'printf'], true) ? '[bcdeEfFgGosuxX]' : '(?:[cdDeEfinosuxX]|\[[^\]]+\])';
105+
$specifiers = in_array($functionName, ['sprintf', 'printf'], true) ? '[bcdeEfFgGosuxX%s]' : '(?:[cdDeEfinosuxX%s]|\[[^\]]+\])';
106+
$addSpecifier = '';
107+
if ($this->phpVersion->supportsHhPrintfSpecifier()) {
108+
$addSpecifier .= 'hH';
109+
}
110+
111+
$specifiers = sprintf($specifiers, $addSpecifier);
112+
98113
$pattern = '~(?<before>%*)%(?:(?<position>\d+)\$)?[-+]?(?:[ 0]|(?:\'[^%]))?-?\d*(?:\.\d*)?' . $specifiers . '~';
99114

100115
$matches = \Nette\Utils\Strings::matchAll($format, $pattern, PREG_SET_ORDER);

tests/PHPStan/Rules/Functions/PrintfParametersRuleTest.php

+18-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace PHPStan\Rules\Functions;
44

5+
use PHPStan\Php\PhpVersion;
6+
use const PHP_VERSION_ID;
7+
58
/**
69
* @extends \PHPStan\Testing\RuleTestCase<PrintfParametersRule>
710
*/
@@ -10,7 +13,7 @@ class PrintfParametersRuleTest extends \PHPStan\Testing\RuleTestCase
1013

1114
protected function getRule(): \PHPStan\Rules\Rule
1215
{
13-
return new PrintfParametersRule();
16+
return new PrintfParametersRule(new PhpVersion(PHP_VERSION_ID));
1417
}
1518

1619
public function testFile(): void
@@ -91,4 +94,18 @@ public function testFile(): void
9194
]);
9295
}
9396

97+
public function testBug4717(): void
98+
{
99+
$errors = [
100+
[
101+
'Call to sprintf contains 1 placeholder, 2 values given.',
102+
5,
103+
],
104+
];
105+
if (PHP_VERSION_ID >= 80000) {
106+
$errors = [];
107+
}
108+
$this->analyse([__DIR__ . '/data/bug-4717.php'], $errors);
109+
}
110+
94111
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
$f = 4.0/3;
4+
$s = 'Bug';
5+
echo sprintf('%s qty = %h', $s, $f);

0 commit comments

Comments
 (0)