Skip to content

Commit 3f9f695

Browse files
committed
Merge remote-tracking branch 'origin/2.1.x' into 2.2.x
2 parents b15face + 77a3244 commit 3f9f695

File tree

6 files changed

+338
-5
lines changed

6 files changed

+338
-5
lines changed

bin/functionMetadata_original.php

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,118 @@
9494
'link' => ['hasSideEffects' => true],
9595
'mkdir' => ['hasSideEffects' => true],
9696
'move_uploaded_file' => ['hasSideEffects' => true],
97+
'mysqli_affected_rows' => ['hasSideEffects' => true],
98+
'mysqli_autocommit' => ['hasSideEffects' => true],
99+
'mysqli_begin_transaction' => ['hasSideEffects' => true],
100+
'mysqli_bind_param' => ['hasSideEffects' => true],
101+
'mysqli_bind_result' => ['hasSideEffects' => true],
102+
'mysqli_change_user' => ['hasSideEffects' => true],
103+
'mysqli_character_set_name' => ['hasSideEffects' => true],
104+
'mysqli_client_encoding' => ['hasSideEffects' => true],
105+
'mysqli_close' => ['hasSideEffects' => true],
106+
'mysqli_commit' => ['hasSideEffects' => true],
107+
'mysqli_connect' => ['hasSideEffects' => true],
108+
'mysqli_connect_errno' => ['hasSideEffects' => true],
109+
'mysqli_connect_error' => ['hasSideEffects' => true],
110+
'mysqli_data_seek' => ['hasSideEffects' => true],
111+
'mysqli_debug' => ['hasSideEffects' => true],
112+
'mysqli_dump_debug_info' => ['hasSideEffects' => true],
113+
'mysqli_errno' => ['hasSideEffects' => true],
114+
'mysqli_error' => ['hasSideEffects' => true],
115+
'mysqli_error_list' => ['hasSideEffects' => true],
116+
'mysqli_escape_string' => ['hasSideEffects' => true],
117+
'mysqli_execute' => ['hasSideEffects' => true],
118+
'mysqli_execute_query' => ['hasSideEffects' => true],
119+
'mysqli_fetch' => ['hasSideEffects' => true],
120+
'mysqli_fetch_all' => ['hasSideEffects' => true],
121+
'mysqli_fetch_array' => ['hasSideEffects' => true],
122+
'mysqli_fetch_assoc' => ['hasSideEffects' => true],
123+
'mysqli_fetch_column' => ['hasSideEffects' => true],
124+
'mysqli_fetch_field' => ['hasSideEffects' => true],
125+
'mysqli_fetch_lengths' => ['hasSideEffects' => true],
126+
'mysqli_fetch_object' => ['hasSideEffects' => true],
127+
'mysqli_fetch_row' => ['hasSideEffects' => true],
128+
'mysqli_field_count' => ['hasSideEffects' => true],
129+
'mysqli_field_seek' => ['hasSideEffects' => true],
130+
'mysqli_field_tell' => ['hasSideEffects' => true],
131+
'mysqli_free_result' => ['hasSideEffects' => true],
132+
'mysqli_get_cache_stats' => ['hasSideEffects' => true],
133+
'mysqli_get_charset' => ['hasSideEffects' => true],
134+
'mysqli_get_client_info' => ['hasSideEffects' => true],
135+
'mysqli_get_client_stats' => ['hasSideEffects' => true],
136+
'mysqli_get_client_version' => ['hasSideEffects' => true],
137+
'mysqli_get_connection_stats' => ['hasSideEffects' => true],
138+
'mysqli_get_host_info' => ['hasSideEffects' => true],
139+
'mysqli_get_links_stats' => ['hasSideEffects' => true],
140+
'mysqli_get_metadata' => ['hasSideEffects' => true],
141+
'mysqli_get_proto_info' => ['hasSideEffects' => true],
142+
'mysqli_get_server_info' => ['hasSideEffects' => true],
143+
'mysqli_get_server_version' => ['hasSideEffects' => true],
144+
'mysqli_get_warnings' => ['hasSideEffects' => true],
145+
'mysqli_info' => ['hasSideEffects' => true],
146+
'mysqli_init' => ['hasSideEffects' => true],
147+
'mysqli_insert_id' => ['hasSideEffects' => true],
148+
'mysqli_kill' => ['hasSideEffects' => true],
149+
'mysqli_more_results' => ['hasSideEffects' => true],
150+
'mysqli_multi_query' => ['hasSideEffects' => true],
151+
'mysqli_next_result' => ['hasSideEffects' => true],
152+
'mysqli_options' => ['hasSideEffects' => true],
153+
'mysqli_param_count' => ['hasSideEffects' => true],
154+
'mysqli_ping' => ['hasSideEffects' => true],
155+
'mysqli_poll' => ['hasSideEffects' => true],
156+
'mysqli_prepare' => ['hasSideEffects' => true],
157+
'mysqli_query' => ['hasSideEffects' => true],
158+
'mysqli_real_connect' => ['hasSideEffects' => true],
159+
'mysqli_real_escape_string' => ['hasSideEffects' => true],
160+
'mysqli_real_query' => ['hasSideEffects' => true],
161+
'mysqli_reap_async_query' => ['hasSideEffects' => true],
162+
'mysqli_refresh' => ['hasSideEffects' => true],
163+
'mysqli_release_savepoint' => ['hasSideEffects' => true],
164+
'mysqli_report' => ['hasSideEffects' => true],
165+
'mysqli_rollback' => ['hasSideEffects' => true],
166+
'mysqli_savepoint' => ['hasSideEffects' => true],
167+
'mysqli_select_db' => ['hasSideEffects' => true],
168+
'mysqli_send_long_data' => ['hasSideEffects' => true],
169+
'mysqli_set_charset' => ['hasSideEffects' => true],
170+
'mysqli_set_local_infile_default' => ['hasSideEffects' => true],
171+
'mysqli_set_local_infile_handler' => ['hasSideEffects' => true],
172+
'mysqli_set_opt' => ['hasSideEffects' => true],
173+
'mysqli_sqlstate' => ['hasSideEffects' => true],
174+
'mysqli_ssl_set' => ['hasSideEffects' => true],
175+
'mysqli_stat' => ['hasSideEffects' => true],
176+
'mysqli_stmt_affected_rows' => ['hasSideEffects' => true],
177+
'mysqli_stmt_attr_get' => ['hasSideEffects' => true],
178+
'mysqli_stmt_attr_set' => ['hasSideEffects' => true],
179+
'mysqli_stmt_bind_param' => ['hasSideEffects' => true],
180+
'mysqli_stmt_bind_result' => ['hasSideEffects' => true],
181+
'mysqli_stmt_close' => ['hasSideEffects' => true],
182+
'mysqli_stmt_data_seek' => ['hasSideEffects' => true],
183+
'mysqli_stmt_errno' => ['hasSideEffects' => true],
184+
'mysqli_stmt_error' => ['hasSideEffects' => true],
185+
'mysqli_stmt_error_list' => ['hasSideEffects' => true],
186+
'mysqli_stmt_execute' => ['hasSideEffects' => true],
187+
'mysqli_stmt_fetch' => ['hasSideEffects' => true],
188+
'mysqli_stmt_field_count' => ['hasSideEffects' => true],
189+
'mysqli_stmt_free_result' => ['hasSideEffects' => true],
190+
'mysqli_stmt_get_result' => ['hasSideEffects' => true],
191+
'mysqli_stmt_get_warnings' => ['hasSideEffects' => true],
192+
'mysqli_stmt_init' => ['hasSideEffects' => true],
193+
'mysqli_stmt_insert_id' => ['hasSideEffects' => true],
194+
'mysqli_stmt_more_results' => ['hasSideEffects' => true],
195+
'mysqli_stmt_next_result' => ['hasSideEffects' => true],
196+
'mysqli_stmt_num_rows' => ['hasSideEffects' => true],
197+
'mysqli_stmt_param_count' => ['hasSideEffects' => true],
198+
'mysqli_stmt_prepare' => ['hasSideEffects' => true],
199+
'mysqli_stmt_reset' => ['hasSideEffects' => true],
200+
'mysqli_stmt_result_metadata' => ['hasSideEffects' => true],
201+
'mysqli_stmt_send_long_data' => ['hasSideEffects' => true],
202+
'mysqli_stmt_sqlstate' => ['hasSideEffects' => true],
203+
'mysqli_stmt_store_result' => ['hasSideEffects' => true],
204+
'mysqli_store_result' => ['hasSideEffects' => true],
205+
'mysqli_thread_id' => ['hasSideEffects' => true],
206+
'mysqli_thread_safe' => ['hasSideEffects' => true],
207+
'mysqli_use_result' => ['hasSideEffects' => true],
208+
'mysqli_warning_count' => ['hasSideEffects' => true],
97209
'ob_clean' => ['hasSideEffects' => true],
98210
'ob_end_clean' => ['hasSideEffects' => true],
99211
'ob_end_flush' => ['hasSideEffects' => true],

resources/functionMetadata.php

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,6 +1392,118 @@
13921392
'msgfmt_parse_message' => ['hasSideEffects' => false],
13931393
'mt_getrandmax' => ['hasSideEffects' => false],
13941394
'mt_rand' => ['hasSideEffects' => true],
1395+
'mysqli_affected_rows' => ['hasSideEffects' => true],
1396+
'mysqli_autocommit' => ['hasSideEffects' => true],
1397+
'mysqli_begin_transaction' => ['hasSideEffects' => true],
1398+
'mysqli_bind_param' => ['hasSideEffects' => true],
1399+
'mysqli_bind_result' => ['hasSideEffects' => true],
1400+
'mysqli_change_user' => ['hasSideEffects' => true],
1401+
'mysqli_character_set_name' => ['hasSideEffects' => true],
1402+
'mysqli_client_encoding' => ['hasSideEffects' => true],
1403+
'mysqli_close' => ['hasSideEffects' => true],
1404+
'mysqli_commit' => ['hasSideEffects' => true],
1405+
'mysqli_connect' => ['hasSideEffects' => true],
1406+
'mysqli_connect_errno' => ['hasSideEffects' => true],
1407+
'mysqli_connect_error' => ['hasSideEffects' => true],
1408+
'mysqli_data_seek' => ['hasSideEffects' => true],
1409+
'mysqli_debug' => ['hasSideEffects' => true],
1410+
'mysqli_dump_debug_info' => ['hasSideEffects' => true],
1411+
'mysqli_errno' => ['hasSideEffects' => true],
1412+
'mysqli_error' => ['hasSideEffects' => true],
1413+
'mysqli_error_list' => ['hasSideEffects' => true],
1414+
'mysqli_escape_string' => ['hasSideEffects' => true],
1415+
'mysqli_execute' => ['hasSideEffects' => true],
1416+
'mysqli_execute_query' => ['hasSideEffects' => true],
1417+
'mysqli_fetch' => ['hasSideEffects' => true],
1418+
'mysqli_fetch_all' => ['hasSideEffects' => true],
1419+
'mysqli_fetch_array' => ['hasSideEffects' => true],
1420+
'mysqli_fetch_assoc' => ['hasSideEffects' => true],
1421+
'mysqli_fetch_column' => ['hasSideEffects' => true],
1422+
'mysqli_fetch_field' => ['hasSideEffects' => true],
1423+
'mysqli_fetch_lengths' => ['hasSideEffects' => true],
1424+
'mysqli_fetch_object' => ['hasSideEffects' => true],
1425+
'mysqli_fetch_row' => ['hasSideEffects' => true],
1426+
'mysqli_field_count' => ['hasSideEffects' => true],
1427+
'mysqli_field_seek' => ['hasSideEffects' => true],
1428+
'mysqli_field_tell' => ['hasSideEffects' => true],
1429+
'mysqli_free_result' => ['hasSideEffects' => true],
1430+
'mysqli_get_cache_stats' => ['hasSideEffects' => true],
1431+
'mysqli_get_charset' => ['hasSideEffects' => true],
1432+
'mysqli_get_client_info' => ['hasSideEffects' => true],
1433+
'mysqli_get_client_stats' => ['hasSideEffects' => true],
1434+
'mysqli_get_client_version' => ['hasSideEffects' => true],
1435+
'mysqli_get_connection_stats' => ['hasSideEffects' => true],
1436+
'mysqli_get_host_info' => ['hasSideEffects' => true],
1437+
'mysqli_get_links_stats' => ['hasSideEffects' => true],
1438+
'mysqli_get_metadata' => ['hasSideEffects' => true],
1439+
'mysqli_get_proto_info' => ['hasSideEffects' => true],
1440+
'mysqli_get_server_info' => ['hasSideEffects' => true],
1441+
'mysqli_get_server_version' => ['hasSideEffects' => true],
1442+
'mysqli_get_warnings' => ['hasSideEffects' => true],
1443+
'mysqli_info' => ['hasSideEffects' => true],
1444+
'mysqli_init' => ['hasSideEffects' => true],
1445+
'mysqli_insert_id' => ['hasSideEffects' => true],
1446+
'mysqli_kill' => ['hasSideEffects' => true],
1447+
'mysqli_more_results' => ['hasSideEffects' => true],
1448+
'mysqli_multi_query' => ['hasSideEffects' => true],
1449+
'mysqli_next_result' => ['hasSideEffects' => true],
1450+
'mysqli_options' => ['hasSideEffects' => true],
1451+
'mysqli_param_count' => ['hasSideEffects' => true],
1452+
'mysqli_ping' => ['hasSideEffects' => true],
1453+
'mysqli_poll' => ['hasSideEffects' => true],
1454+
'mysqli_prepare' => ['hasSideEffects' => true],
1455+
'mysqli_query' => ['hasSideEffects' => true],
1456+
'mysqli_real_connect' => ['hasSideEffects' => true],
1457+
'mysqli_real_escape_string' => ['hasSideEffects' => true],
1458+
'mysqli_real_query' => ['hasSideEffects' => true],
1459+
'mysqli_reap_async_query' => ['hasSideEffects' => true],
1460+
'mysqli_refresh' => ['hasSideEffects' => true],
1461+
'mysqli_release_savepoint' => ['hasSideEffects' => true],
1462+
'mysqli_report' => ['hasSideEffects' => true],
1463+
'mysqli_rollback' => ['hasSideEffects' => true],
1464+
'mysqli_savepoint' => ['hasSideEffects' => true],
1465+
'mysqli_select_db' => ['hasSideEffects' => true],
1466+
'mysqli_send_long_data' => ['hasSideEffects' => true],
1467+
'mysqli_set_charset' => ['hasSideEffects' => true],
1468+
'mysqli_set_local_infile_default' => ['hasSideEffects' => true],
1469+
'mysqli_set_local_infile_handler' => ['hasSideEffects' => true],
1470+
'mysqli_set_opt' => ['hasSideEffects' => true],
1471+
'mysqli_sqlstate' => ['hasSideEffects' => true],
1472+
'mysqli_ssl_set' => ['hasSideEffects' => true],
1473+
'mysqli_stat' => ['hasSideEffects' => true],
1474+
'mysqli_stmt_affected_rows' => ['hasSideEffects' => true],
1475+
'mysqli_stmt_attr_get' => ['hasSideEffects' => true],
1476+
'mysqli_stmt_attr_set' => ['hasSideEffects' => true],
1477+
'mysqli_stmt_bind_param' => ['hasSideEffects' => true],
1478+
'mysqli_stmt_bind_result' => ['hasSideEffects' => true],
1479+
'mysqli_stmt_close' => ['hasSideEffects' => true],
1480+
'mysqli_stmt_data_seek' => ['hasSideEffects' => true],
1481+
'mysqli_stmt_errno' => ['hasSideEffects' => true],
1482+
'mysqli_stmt_error' => ['hasSideEffects' => true],
1483+
'mysqli_stmt_error_list' => ['hasSideEffects' => true],
1484+
'mysqli_stmt_execute' => ['hasSideEffects' => true],
1485+
'mysqli_stmt_fetch' => ['hasSideEffects' => true],
1486+
'mysqli_stmt_field_count' => ['hasSideEffects' => true],
1487+
'mysqli_stmt_free_result' => ['hasSideEffects' => true],
1488+
'mysqli_stmt_get_result' => ['hasSideEffects' => true],
1489+
'mysqli_stmt_get_warnings' => ['hasSideEffects' => true],
1490+
'mysqli_stmt_init' => ['hasSideEffects' => true],
1491+
'mysqli_stmt_insert_id' => ['hasSideEffects' => true],
1492+
'mysqli_stmt_more_results' => ['hasSideEffects' => true],
1493+
'mysqli_stmt_next_result' => ['hasSideEffects' => true],
1494+
'mysqli_stmt_num_rows' => ['hasSideEffects' => true],
1495+
'mysqli_stmt_param_count' => ['hasSideEffects' => true],
1496+
'mysqli_stmt_prepare' => ['hasSideEffects' => true],
1497+
'mysqli_stmt_reset' => ['hasSideEffects' => true],
1498+
'mysqli_stmt_result_metadata' => ['hasSideEffects' => true],
1499+
'mysqli_stmt_send_long_data' => ['hasSideEffects' => true],
1500+
'mysqli_stmt_sqlstate' => ['hasSideEffects' => true],
1501+
'mysqli_stmt_store_result' => ['hasSideEffects' => true],
1502+
'mysqli_store_result' => ['hasSideEffects' => true],
1503+
'mysqli_thread_id' => ['hasSideEffects' => true],
1504+
'mysqli_thread_safe' => ['hasSideEffects' => true],
1505+
'mysqli_use_result' => ['hasSideEffects' => true],
1506+
'mysqli_warning_count' => ['hasSideEffects' => true],
13951507
'net_get_interfaces' => ['hasSideEffects' => false],
13961508
'ngettext' => ['hasSideEffects' => false],
13971509
'nl2br' => ['hasSideEffects' => false],

src/Analyser/MutatingScope.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3078,9 +3078,9 @@ private function setExpressionCertainty(Expr $expr, TrinaryLogic $certainty): se
30783078
}
30793079

30803080
/**
3081-
* Returns true when the type is a large union with non-trivial
3082-
* (IntersectionType) members — a sign of HasOffsetValueType
3083-
* combinatorial growth from array|object offset access patterns.
3081+
* Returns true when the type is a large union with intersection
3082+
* members that carry HasOffsetValueType — a sign of combinatorial
3083+
* growth from successive array|object offset access patterns.
30843084
* Operating on such types is expensive and should be skipped.
30853085
*/
30863086
private function isComplexUnionType(Type $type): bool
@@ -3093,8 +3093,13 @@ private function isComplexUnionType(Type $type): bool
30933093
return false;
30943094
}
30953095
foreach ($types as $member) {
3096-
if ($member instanceof IntersectionType) {
3097-
return true;
3096+
if (!$member instanceof IntersectionType) {
3097+
continue;
3098+
}
3099+
foreach ($member->getTypes() as $innerType) {
3100+
if ($innerType instanceof HasOffsetValueType) {
3101+
return true;
3102+
}
30983103
}
30993104
}
31003105
return false;
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
namespace Bug14484;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class A {}
8+
class B {}
9+
class C {}
10+
class D {}
11+
12+
class Bug
13+
{
14+
/**
15+
* @return int|bool|string|A|B|C|D|list<A>|null
16+
*/
17+
public function getValue(): mixed
18+
{
19+
return null;
20+
}
21+
22+
public function test(): void
23+
{
24+
$value = $this->getValue();
25+
if (!is_string($value)) {
26+
return;
27+
}
28+
assertType('string', $value);
29+
}
30+
31+
}
32+
33+
class Bug2
34+
{
35+
/**
36+
* @return int|bool|string|A|B|C|D|list<A>|null
37+
*/
38+
public function getValue(): mixed
39+
{
40+
return null;
41+
}
42+
43+
public function testInstanceof(): void
44+
{
45+
$value = $this->getValue();
46+
if (!($value instanceof A)) {
47+
return;
48+
}
49+
// Expected: narrowed to A
50+
// Actual in 2.1.49: entire union reported (narrowing lost)
51+
assertType(A::class, $value);
52+
}
53+
54+
public function testIfElseifInstanceof(): void
55+
{
56+
$value = $this->getValue();
57+
if ($value === null) {
58+
return;
59+
}
60+
if ($value instanceof A) {
61+
assertType(A::class, $value);
62+
} elseif ($value instanceof B) {
63+
assertType(B::class, $value);
64+
} elseif (is_array($value)) {
65+
assertType('list<Bug14484\\A>', $value);
66+
} elseif (is_string($value)) {
67+
assertType('string', $value);
68+
}
69+
}
70+
}

tests/PHPStan/Rules/Comparison/BooleanOrConstantConditionRuleTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,4 +402,11 @@ public function testInTrait(): void
402402
]);
403403
}
404404

405+
public function testBug14473(): void
406+
{
407+
$this->treatPhpDocTypesAsCertain = true;
408+
409+
$this->analyse([__DIR__ . '/data/bug-14473.php'], []);
410+
}
411+
405412
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug14473;
4+
5+
$link = mysqli_connect('host', 'user', 'pass', 'database') or die('Could not connect: ' . mysqli_connect_error());
6+
7+
// (assume long-running code that can cause the connection to time out)
8+
9+
$link = mysqli_connect('host', 'user', 'pass', 'database') or die('Could not reconnect: ' . mysqli_connect_error());
10+
11+
// okay, so let's make certain that the connection is closed
12+
mysqli_close($link);
13+
14+
$link = mysqli_connect('host', 'user', 'pass', 'database') or die('Could not reconnect: ' . mysqli_connect_error());
15+
16+
// close it and destroy the variable
17+
mysqli_close($link);
18+
unset($link);
19+
20+
$link = mysqli_connect('host', 'user', 'pass', 'database') or die('Could not reconnect: ' . mysqli_connect_error());
21+
22+
// close, destroy ...
23+
mysqli_close($link);
24+
unset($link);
25+
26+
// ... and assign to a different variable
27+
$newLink = mysqli_connect('host', 'user', 'pass', 'database') or die('Could not reconnect: ' . mysqli_connect_error());

0 commit comments

Comments
 (0)