Skip to content

Commit 96a90cc

Browse files
jlherrenondrejmirtes
authored andcommitted
Mark file resource functions as having side effects
Fixes phpstan/phpstan#5461
1 parent 2427b83 commit 96a90cc

File tree

4 files changed

+146
-0
lines changed

4 files changed

+146
-0
lines changed

bin/functionMetadata_original.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,46 @@
6161
'bcmod' => ['hasSideEffects' => false],
6262
'bcmul' => ['hasSideEffects' => false],
6363
// continue functionMap.php, line 424
64+
'chgrp' => ['hasSideEffects' => true],
65+
'chmod' => ['hasSideEffects' => true],
66+
'chown' => ['hasSideEffects' => true],
67+
'copy' => ['hasSideEffects' => true],
6468
'count' => ['hasSideEffects' => false],
69+
'fclose' => ['hasSideEffects' => true],
70+
'fflush' => ['hasSideEffects' => true],
71+
'fgetc' => ['hasSideEffects' => true],
72+
'fgetcsv' => ['hasSideEffects' => true],
73+
'fgets' => ['hasSideEffects' => true],
74+
'fgetss' => ['hasSideEffects' => true],
75+
'file_put_contents' => ['hasSideEffects' => true],
76+
'flock' => ['hasSideEffects' => true],
77+
'fopen' => ['hasSideEffects' => true],
78+
'fpassthru' => ['hasSideEffects' => true],
79+
'fputcsv' => ['hasSideEffects' => true],
80+
'fputs' => ['hasSideEffects' => true],
81+
'fread' => ['hasSideEffects' => true],
82+
'fscanf' => ['hasSideEffects' => true],
83+
'fseek' => ['hasSideEffects' => true],
84+
'ftruncate' => ['hasSideEffects' => true],
85+
'fwrite' => ['hasSideEffects' => true],
86+
'lchgrp' => ['hasSideEffects' => true],
87+
'lchown' => ['hasSideEffects' => true],
88+
'link' => ['hasSideEffects' => true],
89+
'mkdir' => ['hasSideEffects' => true],
90+
'move_uploaded_file' => ['hasSideEffects' => true],
91+
'pclose' => ['hasSideEffects' => true],
92+
'popen' => ['hasSideEffects' => true],
93+
'readfile' => ['hasSideEffects' => true],
94+
'rename' => ['hasSideEffects' => true],
95+
'rewind' => ['hasSideEffects' => true],
96+
'rmdir' => ['hasSideEffects' => true],
6597
'sprintf' => ['hasSideEffects' => false],
98+
'symlink' => ['hasSideEffects' => true],
99+
'tempnam' => ['hasSideEffects' => true],
100+
'tmpfile' => ['hasSideEffects' => true],
101+
'touch' => ['hasSideEffects' => true],
102+
'umask' => ['hasSideEffects' => true],
103+
'unlink' => ['hasSideEffects' => true],
66104

67105
// random functions, do not have side effects but are not deterministic
68106
'mt_rand' => ['hasSideEffects' => true],

resources/functionMetadata.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,10 @@
717717
'ceil' => ['hasSideEffects' => false],
718718
'checkdate' => ['hasSideEffects' => false],
719719
'checkdnsrr' => ['hasSideEffects' => false],
720+
'chgrp' => ['hasSideEffects' => true],
721+
'chmod' => ['hasSideEffects' => true],
720722
'chop' => ['hasSideEffects' => false],
723+
'chown' => ['hasSideEffects' => true],
721724
'chr' => ['hasSideEffects' => false],
722725
'chunk_split' => ['hasSideEffects' => false],
723726
'class_implements' => ['hasSideEffects' => false],
@@ -738,6 +741,7 @@
738741
'convert_cyr_string' => ['hasSideEffects' => false],
739742
'convert_uudecode' => ['hasSideEffects' => false],
740743
'convert_uuencode' => ['hasSideEffects' => false],
744+
'copy' => ['hasSideEffects' => true],
741745
'cos' => ['hasSideEffects' => false],
742746
'cosh' => ['hasSideEffects' => false],
743747
'count' => ['hasSideEffects' => false],
@@ -823,11 +827,18 @@
823827
'explode' => ['hasSideEffects' => false],
824828
'expm1' => ['hasSideEffects' => false],
825829
'extension_loaded' => ['hasSideEffects' => false],
830+
'fclose' => ['hasSideEffects' => true],
826831
'fdiv' => ['hasSideEffects' => false],
827832
'feof' => ['hasSideEffects' => false],
833+
'fflush' => ['hasSideEffects' => true],
834+
'fgetc' => ['hasSideEffects' => true],
835+
'fgetcsv' => ['hasSideEffects' => true],
836+
'fgets' => ['hasSideEffects' => true],
837+
'fgetss' => ['hasSideEffects' => true],
828838
'file' => ['hasSideEffects' => false],
829839
'file_exists' => ['hasSideEffects' => false],
830840
'file_get_contents' => ['hasSideEffects' => false],
841+
'file_put_contents' => ['hasSideEffects' => true],
831842
'fileatime' => ['hasSideEffects' => false],
832843
'filectime' => ['hasSideEffects' => false],
833844
'filegroup' => ['hasSideEffects' => false],
@@ -847,16 +858,26 @@
847858
'finfo::buffer' => ['hasSideEffects' => false],
848859
'finfo::file' => ['hasSideEffects' => false],
849860
'floatval' => ['hasSideEffects' => false],
861+
'flock' => ['hasSideEffects' => true],
850862
'floor' => ['hasSideEffects' => false],
851863
'fmod' => ['hasSideEffects' => false],
852864
'fnmatch' => ['hasSideEffects' => false],
865+
'fopen' => ['hasSideEffects' => true],
866+
'fpassthru' => ['hasSideEffects' => true],
867+
'fputcsv' => ['hasSideEffects' => true],
868+
'fputs' => ['hasSideEffects' => true],
869+
'fread' => ['hasSideEffects' => true],
870+
'fscanf' => ['hasSideEffects' => true],
871+
'fseek' => ['hasSideEffects' => true],
853872
'fstat' => ['hasSideEffects' => false],
854873
'ftell' => ['hasSideEffects' => false],
855874
'ftok' => ['hasSideEffects' => false],
875+
'ftruncate' => ['hasSideEffects' => true],
856876
'func_get_arg' => ['hasSideEffects' => false],
857877
'func_get_args' => ['hasSideEffects' => false],
858878
'func_num_args' => ['hasSideEffects' => false],
859879
'function_exists' => ['hasSideEffects' => false],
880+
'fwrite' => ['hasSideEffects' => true],
860881
'gc_enabled' => ['hasSideEffects' => false],
861882
'gc_status' => ['hasSideEffects' => false],
862883
'gd_info' => ['hasSideEffects' => false],
@@ -1182,8 +1203,11 @@
11821203
'key' => ['hasSideEffects' => false],
11831204
'key_exists' => ['hasSideEffects' => false],
11841205
'lcfirst' => ['hasSideEffects' => false],
1206+
'lchgrp' => ['hasSideEffects' => true],
1207+
'lchown' => ['hasSideEffects' => true],
11851208
'libxml_get_errors' => ['hasSideEffects' => false],
11861209
'libxml_get_last_error' => ['hasSideEffects' => false],
1210+
'link' => ['hasSideEffects' => true],
11871211
'linkinfo' => ['hasSideEffects' => false],
11881212
'locale_accept_from_http' => ['hasSideEffects' => false],
11891213
'locale_canonicalize' => ['hasSideEffects' => false],
@@ -1270,7 +1294,9 @@
12701294
'mhash_keygen_s2k' => ['hasSideEffects' => false],
12711295
'microtime' => ['hasSideEffects' => false],
12721296
'min' => ['hasSideEffects' => false],
1297+
'mkdir' => ['hasSideEffects' => true],
12731298
'mktime' => ['hasSideEffects' => false],
1299+
'move_uploaded_file' => ['hasSideEffects' => true],
12741300
'msgfmt_create' => ['hasSideEffects' => false],
12751301
'msgfmt_format' => ['hasSideEffects' => false],
12761302
'msgfmt_format_message' => ['hasSideEffects' => false],
@@ -1311,6 +1337,7 @@
13111337
'parse_ini_string' => ['hasSideEffects' => false],
13121338
'parse_url' => ['hasSideEffects' => false],
13131339
'pathinfo' => ['hasSideEffects' => false],
1340+
'pclose' => ['hasSideEffects' => true],
13141341
'pcntl_errno' => ['hasSideEffects' => false],
13151342
'pcntl_get_last_error' => ['hasSideEffects' => false],
13161343
'pcntl_getpriority' => ['hasSideEffects' => false],
@@ -1331,6 +1358,7 @@
13311358
'php_uname' => ['hasSideEffects' => false],
13321359
'phpversion' => ['hasSideEffects' => false],
13331360
'pi' => ['hasSideEffects' => false],
1361+
'popen' => ['hasSideEffects' => true],
13341362
'pos' => ['hasSideEffects' => false],
13351363
'posix_ctermid' => ['hasSideEffects' => false],
13361364
'posix_errno' => ['hasSideEffects' => false],
@@ -1375,16 +1403,20 @@
13751403
'range' => ['hasSideEffects' => false],
13761404
'rawurldecode' => ['hasSideEffects' => false],
13771405
'rawurlencode' => ['hasSideEffects' => false],
1406+
'readfile' => ['hasSideEffects' => true],
13781407
'readlink' => ['hasSideEffects' => false],
13791408
'realpath' => ['hasSideEffects' => false],
13801409
'realpath_cache_get' => ['hasSideEffects' => false],
13811410
'realpath_cache_size' => ['hasSideEffects' => false],
1411+
'rename' => ['hasSideEffects' => true],
13821412
'resourcebundle_count' => ['hasSideEffects' => false],
13831413
'resourcebundle_create' => ['hasSideEffects' => false],
13841414
'resourcebundle_get' => ['hasSideEffects' => false],
13851415
'resourcebundle_get_error_code' => ['hasSideEffects' => false],
13861416
'resourcebundle_get_error_message' => ['hasSideEffects' => false],
13871417
'resourcebundle_locales' => ['hasSideEffects' => false],
1418+
'rewind' => ['hasSideEffects' => true],
1419+
'rmdir' => ['hasSideEffects' => true],
13881420
'round' => ['hasSideEffects' => false],
13891421
'rtrim' => ['hasSideEffects' => false],
13901422
'sha1' => ['hasSideEffects' => false],
@@ -1445,9 +1477,11 @@
14451477
'substr_compare' => ['hasSideEffects' => false],
14461478
'substr_count' => ['hasSideEffects' => false],
14471479
'substr_replace' => ['hasSideEffects' => false],
1480+
'symlink' => ['hasSideEffects' => true],
14481481
'sys_getloadavg' => ['hasSideEffects' => false],
14491482
'tan' => ['hasSideEffects' => false],
14501483
'tanh' => ['hasSideEffects' => false],
1484+
'tempnam' => ['hasSideEffects' => true],
14511485
'timezone_abbreviations_list' => ['hasSideEffects' => false],
14521486
'timezone_identifiers_list' => ['hasSideEffects' => false],
14531487
'timezone_location_get' => ['hasSideEffects' => false],
@@ -1457,8 +1491,10 @@
14571491
'timezone_open' => ['hasSideEffects' => false],
14581492
'timezone_transitions_get' => ['hasSideEffects' => false],
14591493
'timezone_version_get' => ['hasSideEffects' => false],
1494+
'tmpfile' => ['hasSideEffects' => true],
14601495
'token_get_all' => ['hasSideEffects' => false],
14611496
'token_name' => ['hasSideEffects' => false],
1497+
'touch' => ['hasSideEffects' => true],
14621498
'transliterator_create' => ['hasSideEffects' => false],
14631499
'transliterator_create_from_rules' => ['hasSideEffects' => false],
14641500
'transliterator_create_inverse' => ['hasSideEffects' => false],
@@ -1469,7 +1505,9 @@
14691505
'trim' => ['hasSideEffects' => false],
14701506
'ucfirst' => ['hasSideEffects' => false],
14711507
'ucwords' => ['hasSideEffects' => false],
1508+
'umask' => ['hasSideEffects' => true],
14721509
'uniqid' => ['hasSideEffects' => false],
1510+
'unlink' => ['hasSideEffects' => true],
14731511
'unpack' => ['hasSideEffects' => false],
14741512
'urldecode' => ['hasSideEffects' => false],
14751513
'urlencode' => ['hasSideEffects' => false],

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,8 @@ public function dataFileAsserts(): iterable
541541
}
542542

543543
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2760.php');
544+
545+
yield from $this->gatherAssertTypes(__DIR__ . '/data/filesystem-functions.php');
544546
}
545547

546548
/**
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
namespace FilesystemFunctions;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Bug5461
8+
{
9+
10+
public function run(): void
11+
{
12+
$fh = fopen('foo.txt', 'r');
13+
if ($fh === false) {
14+
throw new \InvalidArgumentException('Could not open file');
15+
}
16+
17+
while (!feof($fh)) {
18+
$data = (string)fread($fh, 1024);
19+
assertType('bool', feof($fh));
20+
}
21+
22+
fclose($fh);
23+
}
24+
25+
}
26+
27+
class MoreTests
28+
{
29+
30+
public function test1(): void
31+
{
32+
if (fopen('foo.txt', 'r') === false) {
33+
assertType('resource|false', fopen('foo.txt', 'r'));
34+
}
35+
}
36+
37+
/**
38+
* @param resource $fh
39+
*/
40+
public function test2($fh): void
41+
{
42+
if (fread($fh, 4) === 'data') {
43+
assertType('string|false', fread($fh, 4));
44+
}
45+
}
46+
47+
/**
48+
* @param resource $fh
49+
*/
50+
public function test3($fh): void
51+
{
52+
if (ftell($fh) === 0) {
53+
assertType('0', ftell($fh));
54+
fseek($fh, 10);
55+
assertType('int|false', ftell($fh));
56+
}
57+
}
58+
59+
public function test4(string $path): void
60+
{
61+
if (file_get_contents($path) === 'data') {
62+
assertType('\'data\'', file_get_contents($path));
63+
file_put_contents($path, 'other');
64+
assertType('string|false', file_get_contents($path));
65+
}
66+
}
67+
68+
}

0 commit comments

Comments
 (0)