Skip to content

Commit 20054a8

Browse files
Introduce __stringnotstringable
1 parent b05cb5e commit 20054a8

File tree

5 files changed

+164
-3
lines changed

5 files changed

+164
-3
lines changed

resources/functionMap.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,7 +1650,7 @@
16501650
'DomXsltStylesheet::result_dump_mem' => ['string', 'xmldoc'=>'DOMDocument'],
16511651
'DOTNET::__construct' => ['void', 'assembly_name'=>'string', 'class_name'=>'string', 'codepage='=>'int'],
16521652
'dotnet_load' => ['int', 'assembly_name'=>'string', 'datatype_name='=>'string', 'codepage='=>'int'],
1653-
'doubleval' => ['float', 'var'=>'scalar|array|resource|null'],
1653+
'doubleval' => ['float', 'var'=>'int|float|__stringnotstringable|bool|array|resource|null'],
16541654
'Ds\Deque::__construct' => ['void', 'values='=>'mixed'],
16551655
'Ds\Deque::count' => ['0|positive-int'],
16561656
'Ds\Deque::jsonSerialize' => ['array'],
@@ -2448,7 +2448,7 @@
24482448
'finfo_file' => ['string|false', 'finfo'=>'resource', 'file_name'=>'string', 'options='=>'int', 'context='=>'resource'],
24492449
'finfo_open' => ['resource|false', 'options='=>'int', 'arg='=>'string'],
24502450
'finfo_set_flags' => ['bool', 'finfo'=>'resource', 'options'=>'int'],
2451-
'floatval' => ['float', 'var'=>'scalar|array|resource|null'],
2451+
'floatval' => ['float', 'var'=>'int|float|__stringnotstringable|bool|array|resource|null'],
24522452
'flock' => ['bool', 'fp'=>'resource', 'operation'=>'int-mask<LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB>', '&w_wouldblock='=>'0|1'],
24532453
'floor' => ['__benevolent<float|false>', 'number'=>'float'],
24542454
'flush' => ['void'],
@@ -5075,7 +5075,7 @@
50755075
'intltz_to_date_time_zone' => ['DateTimeZone|false', 'obj'=>''],
50765076
'intltz_use_daylight_time' => ['bool', 'obj'=>''],
50775077
'intlz_create_default' => ['IntlTimeZone'],
5078-
'intval' => ['int', 'var'=>'scalar|array|resource|null', 'base='=>'int'],
5078+
'intval' => ['int', 'var'=>'int|float|__stringnotstringable|bool|array|resource|null', 'base='=>'int'],
50795079
'InvalidArgumentException::__clone' => ['void'],
50805080
'InvalidArgumentException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'(?Throwable)|(?InvalidArgumentException)'],
50815081
'InvalidArgumentException::__toString' => ['string'],

src/PhpDoc/TypeNodeResolver.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
use PHPStan\Type\StaticType;
9999
use PHPStan\Type\StaticTypeFactory;
100100
use PHPStan\Type\StringAlwaysAcceptingObjectWithToStringType;
101+
use PHPStan\Type\StringNeverAcceptingObjectWithToStringType;
101102
use PHPStan\Type\StringType;
102103
use PHPStan\Type\ThisType;
103104
use PHPStan\Type\Type;
@@ -462,6 +463,8 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco
462463
return StaticTypeFactory::falsey();
463464
case '__stringandstringable':
464465
return new StringAlwaysAcceptingObjectWithToStringType();
466+
case '__stringnotstringable':
467+
return new StringNeverAcceptingObjectWithToStringType();
465468
}
466469

467470
if ($nameScope->getClassName() !== null) {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type;
4+
5+
class StringNeverAcceptingObjectWithToStringType extends StringType
6+
{
7+
8+
public function accepts(Type $type, bool $strictTypes): AcceptsResult
9+
{
10+
return parent::accepts($type, true);
11+
}
12+
13+
}

tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2397,6 +2397,53 @@ public function testArrayRand(): void
23972397
]);
23982398
}
23992399

2400+
public function testBug6560(): void
2401+
{
2402+
$this->checkExplicitMixed = true;
2403+
$this->checkImplicitMixed = true;
2404+
2405+
$varName = PHP_VERSION_ID < 80000 ? '$var' : '$value';
2406+
2407+
$this->analyse([__DIR__ . '/data/bug-6560.php'], [
2408+
[
2409+
sprintf('Parameter #1 %s of function strval expects bool|float|int|resource|string|null, array given.', $varName),
2410+
20,
2411+
],
2412+
[
2413+
sprintf('Parameter #1 %s of function strval expects bool|float|int|resource|string|null, stdClass given.', $varName),
2414+
74,
2415+
],
2416+
[
2417+
sprintf('Parameter #1 %s of function intval expects array|bool|float|int|resource|string|null, stdClass given.', $varName),
2418+
77,
2419+
],
2420+
[
2421+
sprintf('Parameter #1 %s of function floatval expects array|bool|float|int|resource|string|null, stdClass given.', $varName),
2422+
80,
2423+
],
2424+
[
2425+
sprintf('Parameter #1 %s of function intval expects array|bool|float|int|resource|string|null, Stringable@anonymous/tests/PHPStan/Rules/Functions/data/bug-6560.php:10 given.', $varName),
2426+
86,
2427+
],
2428+
[
2429+
sprintf('Parameter #1 %s of function floatval expects array|bool|float|int|resource|string|null, Stringable@anonymous/tests/PHPStan/Rules/Functions/data/bug-6560.php:10 given.', $varName),
2430+
89,
2431+
],
2432+
[
2433+
sprintf('Parameter #1 %s of function strval expects bool|float|int|resource|string|null, mixed given.', $varName),
2434+
92,
2435+
],
2436+
[
2437+
sprintf('Parameter #1 %s of function intval expects array|bool|float|int|resource|string|null, mixed given.', $varName),
2438+
95,
2439+
],
2440+
[
2441+
sprintf('Parameter #1 %s of function floatval expects array|bool|float|int|resource|string|null, mixed given.', $varName),
2442+
98,
2443+
],
2444+
]);
2445+
}
2446+
24002447
#[RequiresPhp('< 8.0')]
24012448
public function testArrayRandPhp7(): void
24022449
{
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
$array = [];
3+
$string = '';
4+
$int = 1;
5+
$float = .1;
6+
$resource = fopen('./.env', 'r'); // Cannot cast resource to float. But works
7+
\assert(false !== $resource);
8+
$bool = true;
9+
$object = new stdClass();
10+
$stringable = new class() {
11+
public function __toString(): string {
12+
return '';
13+
}
14+
};
15+
$null = null;
16+
/** @var mixed $mixed */
17+
$mixed = null;
18+
19+
echo (string) $array . PHP_EOL;
20+
echo strval($array) . PHP_EOL;
21+
22+
echo (int) $array . PHP_EOL;
23+
echo intval($array) . PHP_EOL;
24+
25+
echo (float) $array . PHP_EOL;
26+
echo floatval($array) . PHP_EOL;
27+
28+
echo (string) $string . PHP_EOL;
29+
echo strval($string) . PHP_EOL;
30+
31+
echo (int) $string . PHP_EOL;
32+
echo intval($string) . PHP_EOL;
33+
34+
echo (float) $string . PHP_EOL;
35+
echo floatval($string) . PHP_EOL;
36+
37+
echo (string) $int . PHP_EOL;
38+
echo strval($int) . PHP_EOL;
39+
40+
echo (int) $int . PHP_EOL;
41+
echo intval($int) . PHP_EOL;
42+
43+
echo (float) $int . PHP_EOL;
44+
echo floatval($int) . PHP_EOL;
45+
46+
echo (string) $float . PHP_EOL;
47+
echo strval($float) . PHP_EOL;
48+
49+
echo (int) $float . PHP_EOL;
50+
echo intval($float) . PHP_EOL;
51+
52+
echo (float) $float . PHP_EOL;
53+
echo floatval($float) . PHP_EOL;
54+
55+
echo (string) $resource . PHP_EOL;
56+
echo strval($resource) . PHP_EOL;
57+
58+
echo (int) $resource . PHP_EOL;
59+
echo intval($resource) . PHP_EOL;
60+
61+
echo (float) $resource . PHP_EOL;
62+
echo floatval($resource) . PHP_EOL;
63+
64+
echo (string) $bool . PHP_EOL;
65+
echo strval($bool) . PHP_EOL;
66+
67+
echo (int) $bool . PHP_EOL;
68+
echo intval($bool) . PHP_EOL;
69+
70+
echo (float) $bool . PHP_EOL;
71+
echo floatval($bool) . PHP_EOL;
72+
73+
echo (string) $object . PHP_EOL;
74+
echo strval($object) . PHP_EOL;
75+
76+
echo (int) $object . PHP_EOL;
77+
echo intval($object) . PHP_EOL;
78+
79+
echo (float) $object . PHP_EOL;
80+
echo floatval($object) . PHP_EOL;
81+
82+
echo (string) $stringable . PHP_EOL;
83+
echo strval($stringable) . PHP_EOL;
84+
85+
echo (int) $stringable . PHP_EOL;
86+
echo intval($stringable) . PHP_EOL;
87+
88+
echo (float) $stringable . PHP_EOL;
89+
echo floatval($stringable) . PHP_EOL;
90+
91+
echo (string) $mixed . PHP_EOL;
92+
echo strval($mixed) . PHP_EOL;
93+
94+
echo (int) $mixed . PHP_EOL;
95+
echo intval($mixed) . PHP_EOL;
96+
97+
echo (float) $mixed . PHP_EOL;
98+
echo floatval($mixed) . PHP_EOL;

0 commit comments

Comments
 (0)