Skip to content

Commit 1d6d3f3

Browse files
authored
Fix handling of dynamic constants (#286)
* Fix handling of dynamic constants * Remove SAVEQUERIES from dynamicConstantNames * Revert "Remove SAVEQUERIES from dynamicConstantNames" This reverts commit 96deab8. It is handled separately in #287. * Readd WP_DEBUG_LOG to bootstrap.php * Add tests for dynamic constants
1 parent a2ad171 commit 1d6d3f3

File tree

7 files changed

+297
-8
lines changed

7 files changed

+297
-8
lines changed

bootstrap.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@
55
// phpcs:disable Generic.PHP.ForbiddenFunctions.Found
66

77
// There are no core functions to read these constants.
8-
define('ABSPATH', './');
8+
define('ABSPATH', '/');
9+
define('WP_CONTENT_DIR', sprintf('%swp-content', ABSPATH));
10+
define('WP_PLUGIN_DIR', sprintf('%s/plugins', WP_CONTENT_DIR));
11+
define('WPMU_PLUGIN_DIR', sprintf('%s/mu-plugins', WP_CONTENT_DIR));
912
define('WP_DEBUG', true);
1013
define('WP_DEBUG_LOG', true);
11-
define('WP_DEBUG_DISPLAY', true);
12-
define('WP_PLUGIN_DIR', './');
13-
define('WPMU_PLUGIN_DIR', './');
14-
define('EMPTY_TRASH_DAYS', 30 * 86400);
14+
define('WP_DEBUG_DISPLAY', false);
15+
define('EMPTY_TRASH_DAYS', 30);
1516
define('SCRIPT_DEBUG', false);
16-
define('WP_LANG_DIR', './');
17-
define('WP_CONTENT_DIR', './');
17+
define('WP_LANG_DIR', sprintf('%s/languages', WP_CONTENT_DIR));
18+
define('COOKIE_DOMAIN', '');
1819

1920
// Constants for expressing human-readable intervals.
2021
define('MINUTE_IN_SECONDS', 60);

extension.neon

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,26 @@ parameters:
3434
- ../../php-stubs/wordpress-stubs/wordpress-stubs.php
3535
- bootstrap.php
3636
dynamicConstantNames:
37+
# Debug constants
3738
- WP_DEBUG
3839
- WP_DEBUG_LOG
3940
- WP_DEBUG_DISPLAY
40-
- EMPTY_TRASH_DAYS
41+
# Directory constants
42+
- ABSPATH
43+
- WP_PLUGIN_DIR
44+
- WP_LANG_DIR
45+
- WP_CONTENT_DIR
46+
- WPMU_PLUGIN_DIR
47+
# Templating constants
48+
- WP_DEFAULT_THEME
49+
# Filesystem constants
50+
- FS_CONNECT_TIMEOUT
51+
- FS_TIMEOUT
52+
- FS_CHMOD_DIR
53+
- FS_CHMOD_FILE
54+
# Other constants
4155
- COOKIE_DOMAIN
56+
- EMPTY_TRASH_DAYS
4257
- SCRIPT_DEBUG
4358
earlyTerminatingFunctionCalls:
4459
- wp_send_json

phpcs.xml.dist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<file>tests/</file>
66

77
<exclude-pattern>tests/data/*</exclude-pattern>
8+
<exclude-pattern>tests/phpstan-data/*</exclude-pattern>
89
<exclude-pattern>tests/functions.php</exclude-pattern>
910
<exclude-pattern>tests/WP_UnitTestCase_Base.php</exclude-pattern>
1011

@@ -19,6 +20,7 @@
1920
<rule ref="NeutronStandard.Functions.TypeHint.UnusedReturnType">
2021
<exclude-pattern>tests/AssertMethodTypeSpecifyingExtensionTest.php</exclude-pattern>
2122
<exclude-pattern>tests/DynamicReturnTypeExtensionTest.php</exclude-pattern>
23+
<exclude-pattern>tests/DynamicConstantTypeTest.php</exclude-pattern>
2224
</rule>
2325

2426
<!-- Allow string concatenation in tests -->

phpstan.neon.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
includes:
22
- vendor/phpstan/phpstan/conf/bleedingEdge.neon
33
- vendor/phpstan/phpstan-strict-rules/rules.neon
4+
- vendor/szepeviktor/phpstan-wordpress/extension.neon
45
parameters:
56
level: 9
67
scanFiles:

tests/DynamicConstantTypeTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SzepeViktor\PHPStan\WordPress\Tests;
6+
7+
class DynamicConstantTypeTest extends \PHPStan\Testing\TypeInferenceTestCase
8+
{
9+
/**
10+
* @return iterable<mixed>
11+
*/
12+
public function dataFileAsserts(): iterable
13+
{
14+
yield from self::gatherAssertTypes(__DIR__ . '/data/dynamic-constants.php');
15+
}
16+
17+
/**
18+
* @dataProvider dataFileAsserts
19+
* @param array<string> ...$args
20+
*/
21+
public function testFileAsserts(string $assertType, string $file, ...$args): void
22+
{
23+
$this->assertFileAsserts($assertType, $file, ...$args);
24+
}
25+
26+
public static function getAdditionalConfigFiles(): array
27+
{
28+
return [dirname(__DIR__) . '/vendor/szepeviktor/phpstan-wordpress/extension.neon'];
29+
}
30+
}

tests/data/dynamic-constants.php

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SzepeViktor\PHPStan\WordPress\Tests;
6+
7+
use const ABSPATH;
8+
use const WP_CONTENT_DIR;
9+
use const WP_LANG_DIR;
10+
use const WPMU_PLUGIN_DIR;
11+
use const WP_PLUGIN_DIR;
12+
use const WP_DEBUG;
13+
use const WP_DEBUG_DISPLAY;
14+
use const EMPTY_TRASH_DAYS;
15+
use const SCRIPT_DEBUG;
16+
use const COOKIE_DOMAIN;
17+
use const WP_DEFAULT_THEME;
18+
use const MINUTE_IN_SECONDS;
19+
use const HOUR_IN_SECONDS;
20+
use const DAY_IN_SECONDS;
21+
use const WEEK_IN_SECONDS;
22+
use const MONTH_IN_SECONDS;
23+
use const YEAR_IN_SECONDS;
24+
use const KB_IN_BYTES;
25+
use const MB_IN_BYTES;
26+
use const GB_IN_BYTES;
27+
use const TB_IN_BYTES;
28+
use const PB_IN_BYTES;
29+
use const EB_IN_BYTES;
30+
use const OBJECT;
31+
use const OBJECT_K;
32+
use const ARRAY_A;
33+
use const ARRAY_N;
34+
use const EP_NONE;
35+
use const EP_PERMALINK;
36+
use const EP_ATTACHMENT;
37+
use const EP_DATE;
38+
use const EP_YEAR;
39+
use const EP_MONTH;
40+
use const EP_DAY;
41+
use const EP_ROOT;
42+
use const EP_COMMENTS;
43+
use const EP_SEARCH;
44+
use const EP_CATEGORIES;
45+
use const EP_TAGS;
46+
use const EP_AUTHORS;
47+
use const EP_PAGES;
48+
use const EP_ALL_ARCHIVES;
49+
use const EP_ALL;
50+
use const FS_CONNECT_TIMEOUT;
51+
use const FS_TIMEOUT;
52+
use const FS_CHMOD_DIR;
53+
use const FS_CHMOD_FILE;
54+
55+
use function PHPStan\Testing\assertType;
56+
57+
/*
58+
* Unconditional constants resolve to constant values and are
59+
* - defined in bootstrap.php
60+
* - NOT part of the dynamicConstantNames list in extension.neon.
61+
*/
62+
63+
assertType('60', MINUTE_IN_SECONDS);
64+
assertType('3600', HOUR_IN_SECONDS);
65+
assertType('86400', DAY_IN_SECONDS);
66+
assertType('604800', WEEK_IN_SECONDS);
67+
assertType('2592000', MONTH_IN_SECONDS);
68+
assertType('31536000', YEAR_IN_SECONDS);
69+
70+
assertType('1024', KB_IN_BYTES);
71+
assertType('1048576', MB_IN_BYTES);
72+
assertType('1073741824', GB_IN_BYTES);
73+
74+
if (PHP_INT_SIZE === 8) {
75+
// 64bit
76+
assertType('1099511627776', TB_IN_BYTES);
77+
assertType('1125899906842624', PB_IN_BYTES);
78+
assertType('1152921504606846976', EB_IN_BYTES);
79+
// ZB_IN_BYTES and YB_IN_BYTES will be converted to floats.
80+
}
81+
82+
assertType("'OBJECT'", OBJECT);
83+
assertType("'OBJECT_K'", OBJECT_K);
84+
assertType("'ARRAY_A'", ARRAY_A);
85+
assertType("'ARRAY_N'", ARRAY_N);
86+
87+
assertType('0', EP_NONE);
88+
assertType('1', EP_PERMALINK);
89+
assertType('2', EP_ATTACHMENT);
90+
assertType('4', EP_DATE);
91+
assertType('8', EP_YEAR);
92+
assertType('16', EP_MONTH);
93+
assertType('32', EP_DAY);
94+
assertType('64', EP_ROOT);
95+
assertType('128', EP_COMMENTS);
96+
assertType('256', EP_SEARCH);
97+
assertType('512', EP_CATEGORIES);
98+
assertType('1024', EP_TAGS);
99+
assertType('2048', EP_AUTHORS);
100+
assertType('4096', EP_PAGES);
101+
assertType('3644', EP_ALL_ARCHIVES);
102+
assertType('8191', EP_ALL);
103+
104+
/*
105+
* Conditional constants resolve to non constant types and are
106+
* - defined in bootstrap.php
107+
* - part of the dynamicConstantNames list in extension.neon.
108+
*/
109+
110+
assertType('bool', WP_DEBUG);
111+
// assertType('bool|string', WP_DEBUG_LOG); // PHPStan does not yet support more than one type for constants
112+
assertType('bool', WP_DEBUG_DISPLAY);
113+
114+
assertType('string', ABSPATH);
115+
assertType('string', WP_CONTENT_DIR);
116+
assertType('string', WP_PLUGIN_DIR);
117+
assertType('string', WPMU_PLUGIN_DIR);
118+
assertType('string', WP_LANG_DIR);
119+
120+
assertType('int', FS_CONNECT_TIMEOUT);
121+
assertType('int', FS_TIMEOUT);
122+
assertType('int', FS_CHMOD_DIR);
123+
assertType('int', FS_CHMOD_FILE);
124+
125+
assertType('string', COOKIE_DOMAIN);
126+
assertType('int', EMPTY_TRASH_DAYS);
127+
assertType('bool', SCRIPT_DEBUG);
128+
assertType('string', WP_DEFAULT_THEME);
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SzepeViktor\PHPStan\WordPress\Tests;
6+
7+
// These should not be reported as errors by PHPStan's ConstantRule
8+
use const ABSPATH;
9+
use const WP_CONTENT_DIR;
10+
use const WP_LANG_DIR;
11+
use const WPMU_PLUGIN_DIR;
12+
use const WP_PLUGIN_DIR;
13+
use const WP_DEBUG;
14+
use const WP_DEBUG_LOG;
15+
use const WP_DEBUG_DISPLAY;
16+
use const EMPTY_TRASH_DAYS;
17+
use const SCRIPT_DEBUG;
18+
use const COOKIE_DOMAIN;
19+
use const WP_DEFAULT_THEME;
20+
use const MINUTE_IN_SECONDS;
21+
use const HOUR_IN_SECONDS;
22+
use const DAY_IN_SECONDS;
23+
use const WEEK_IN_SECONDS;
24+
use const MONTH_IN_SECONDS;
25+
use const YEAR_IN_SECONDS;
26+
use const KB_IN_BYTES;
27+
use const MB_IN_BYTES;
28+
use const GB_IN_BYTES;
29+
use const TB_IN_BYTES;
30+
use const PB_IN_BYTES;
31+
use const EB_IN_BYTES;
32+
use const OBJECT;
33+
use const OBJECT_K;
34+
use const ARRAY_A;
35+
use const ARRAY_N;
36+
use const EP_NONE;
37+
use const EP_PERMALINK;
38+
use const EP_ATTACHMENT;
39+
use const EP_DATE;
40+
use const EP_YEAR;
41+
use const EP_MONTH;
42+
use const EP_DAY;
43+
use const EP_ROOT;
44+
use const EP_COMMENTS;
45+
use const EP_SEARCH;
46+
use const EP_CATEGORIES;
47+
use const EP_TAGS;
48+
use const EP_AUTHORS;
49+
use const EP_PAGES;
50+
use const EP_ALL_ARCHIVES;
51+
use const EP_ALL;
52+
use const FS_CONNECT_TIMEOUT;
53+
use const FS_TIMEOUT;
54+
use const FS_CHMOD_DIR;
55+
use const FS_CHMOD_FILE;
56+
57+
// These should not be reported as errors by PHPStan's ConstantRule and RequireFileExistsRule
58+
require_once ABSPATH . 'file.php';
59+
require_once WP_PLUGIN_DIR . '/file.php';
60+
require_once WP_CONTENT_DIR . '/file.php';
61+
require_once WP_LANG_DIR . '/file.php';
62+
require_once WPMU_PLUGIN_DIR . '/file.php';
63+
64+
// These should not be reported as errors by PHPStan's ConstantRule
65+
$testVariable = ABSPATH;
66+
$testVariable = WP_CONTENT_DIR;
67+
$testVariable = WP_LANG_DIR;
68+
$testVariable = WPMU_PLUGIN_DIR;
69+
$testVariable = WP_PLUGIN_DIR;
70+
$testVariable = WP_DEBUG_LOG;
71+
$testVariable = WP_DEBUG;
72+
$testVariable = WP_DEBUG_DISPLAY;
73+
$testVariable = WP_DEFAULT_THEME;
74+
$testVariable = EMPTY_TRASH_DAYS;
75+
$testVariable = SCRIPT_DEBUG;
76+
$testVariable = COOKIE_DOMAIN;
77+
$testVariable = MINUTE_IN_SECONDS;
78+
$testVariable = HOUR_IN_SECONDS;
79+
$testVariable = DAY_IN_SECONDS;
80+
$testVariable = WEEK_IN_SECONDS;
81+
$testVariable = MONTH_IN_SECONDS;
82+
$testVariable = YEAR_IN_SECONDS;
83+
$testVariable = KB_IN_BYTES;
84+
$testVariable = MB_IN_BYTES;
85+
$testVariable = GB_IN_BYTES;
86+
$testVariable = TB_IN_BYTES;
87+
$testVariable = PB_IN_BYTES;
88+
$testVariable = EB_IN_BYTES;
89+
$testVariable = OBJECT;
90+
$testVariable = OBJECT_K;
91+
$testVariable = ARRAY_A;
92+
$testVariable = ARRAY_N;
93+
$testVariable = EP_NONE;
94+
$testVariable = EP_PERMALINK;
95+
$testVariable = EP_ATTACHMENT;
96+
$testVariable = EP_DATE;
97+
$testVariable = EP_YEAR;
98+
$testVariable = EP_MONTH;
99+
$testVariable = EP_DAY;
100+
$testVariable = EP_ROOT;
101+
$testVariable = EP_COMMENTS;
102+
$testVariable = EP_SEARCH;
103+
$testVariable = EP_CATEGORIES;
104+
$testVariable = EP_TAGS;
105+
$testVariable = EP_AUTHORS;
106+
$testVariable = EP_PAGES;
107+
$testVariable = EP_ALL_ARCHIVES;
108+
$testVariable = EP_ALL;
109+
$testVariable = FS_CONNECT_TIMEOUT;
110+
$testVariable = FS_TIMEOUT;
111+
$testVariable = FS_CHMOD_DIR;
112+
$testVariable = FS_CHMOD_FILE;

0 commit comments

Comments
 (0)