Skip to content

Commit 6a55c7c

Browse files
committed
PHP 8.5 | Tokenizer/PHP: polyfill the (void) cast
As part of the RFC for the `#[NoDiscard]` attribute, a new typecast `(void)` has been introduced. This commit polyfills this new token for PHP < 8.5. Includes tests covering the complete set of type casts, even though the PHPCS Tokenizer only handles the `(void)` cast. Reason being, that PHP has deprecated and removed some casts, like `(unset)`, and their token constants may be removed from PHP Core at some point in the future. These tests should serve as a warning system for that eventuality. Ref: https://wiki.php.net/rfc/marking_return_value_as_important#void_cast_to_suppress_the_warning
1 parent b246455 commit 6a55c7c

File tree

4 files changed

+598
-0
lines changed

4 files changed

+598
-0
lines changed

src/Tokenizers/PHP.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,58 @@ protected function tokenize(string $code)
11221122
continue;
11231123
}
11241124

1125+
/*
1126+
Detect PHP 8.5+ void casting and assign the casts their own token.
1127+
1128+
Mind: type cast tokens _may_ contain whitespace, but no new lines and no comments.
1129+
*/
1130+
1131+
if (PHP_VERSION_ID < 80500
1132+
&& $token[0] === '('
1133+
) {
1134+
$content = $token[0];
1135+
$i = ($stackPtr + 1);
1136+
1137+
if (is_array($tokens[$i]) === true
1138+
&& $tokens[$i][0] === T_WHITESPACE
1139+
&& strpos($tokens[$i][1], "\n") === false
1140+
&& strpos($tokens[$i][1], "\r") === false
1141+
) {
1142+
$content .= $tokens[$i][1];
1143+
++$i;
1144+
}
1145+
1146+
if (is_array($tokens[$i]) === true
1147+
&& $tokens[$i][0] === T_STRING
1148+
&& strtolower($tokens[$i][1]) === 'void'
1149+
) {
1150+
$content .= $tokens[$i][1];
1151+
++$i;
1152+
1153+
if (is_array($tokens[$i]) === true
1154+
&& $tokens[$i][0] === T_WHITESPACE
1155+
&& strpos($tokens[$i][1], "\n") === false
1156+
&& strpos($tokens[$i][1], "\r") === false
1157+
) {
1158+
$content .= $tokens[$i][1];
1159+
++$i;
1160+
}
1161+
1162+
if ($tokens[$i][0] === ')') {
1163+
$content .= $tokens[$i][0];
1164+
1165+
$finalTokens[$newStackPtr] = [
1166+
'code' => T_VOID_CAST,
1167+
'type' => 'T_VOID_CAST',
1168+
'content' => $content,
1169+
];
1170+
$newStackPtr++;
1171+
$stackPtr = $i;
1172+
continue;
1173+
}
1174+
}
1175+
}
1176+
11251177
/*
11261178
If this is a heredoc, PHP will tokenize the whole
11271179
thing which causes problems when heredocs don't

src/Util/Tokens.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@
143143
define('T_PRIVATE_SET', 'PHPCS_T_PRIVATE_SET');
144144
}
145145

146+
// Some PHP 8.5 tokens, replicated for lower versions.
147+
if (defined('T_VOID_CAST') === false) {
148+
define('T_VOID_CAST', 'PHPCS_T_VOID_CAST');
149+
}
150+
146151
// Tokens used for parsing doc blocks.
147152
define('T_DOC_COMMENT_STAR', 'PHPCS_T_DOC_COMMENT_STAR');
148153
define('T_DOC_COMMENT_WHITESPACE', 'PHPCS_T_DOC_COMMENT_WHITESPACE');
@@ -266,6 +271,7 @@ final class Tokens
266271
T_OBJECT_CAST => T_OBJECT_CAST,
267272
T_UNSET_CAST => T_UNSET_CAST,
268273
T_BINARY_CAST => T_BINARY_CAST,
274+
T_VOID_CAST => T_VOID_CAST,
269275
];
270276

271277
/**
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
3+
/*
4+
* Safeguard that all type casts past and present are tokenized correctly.
5+
*
6+
* This is also intended as an early warning system for when type cast tokens would be removed
7+
* for type casts which are no longer supported by PHP itself.
8+
*
9+
* Pertinent type cast changes in PHP:
10+
* - (unset) cast was introduced in PHP 5.0.
11+
* - (binary) cast was introduced in PHP 5.2.1.
12+
* - (unset) cast was deprecated in PHP 7.2 and removed in PHP 8.0.
13+
* - (real) cast was deprecated in PHP 7.4 and removed in PHP 8.0.
14+
* - (void) cast was introduced in PHP 8.5.
15+
* - (integer), (boolean), (double) and (binary) casts are deprecated since PHP 8.5 and will be removed in PHP 9.0.
16+
*/
17+
18+
/* testNotATypeCast1 */
19+
$a = (NOT_A_TYPECAST);
20+
21+
/* testBool */
22+
$a = (bool) $b;
23+
24+
/* testSpacyUppercaseBool */
25+
$a = ( BOOL) $b;
26+
27+
/* testBoolean */
28+
$a = (boolean) $b;
29+
30+
/* testSpacyUppercaseBoolean */
31+
$a = ( BOOLEAN ) $b;
32+
33+
/* testInt */
34+
$a = (int) $b;
35+
36+
/* testSpacyUppercaseInt */
37+
$a = ( INT ) $b;
38+
39+
/* testInteger */
40+
$a = (integer) $b;
41+
42+
/* testSpacyUppercaseInteger */
43+
$a = ( INTEGER ) $b;
44+
45+
/* testFloat */
46+
$a = (float) $b;
47+
48+
/* testSpacyUppercaseFloat */
49+
$a = ( FLOAT ) $b;
50+
51+
/* testReal */
52+
$a = (real) $b;
53+
54+
/* testSpacyUppercaseReal */
55+
$a = ( REAL ) $b;
56+
57+
/* testDouble */
58+
$a = (double) $b;
59+
60+
/* testSpacyUppercaseDouble */
61+
$a = ( DOUBLE ) $b;
62+
63+
/* testString */
64+
$a = (string) $b;
65+
66+
/* testSpacyUppercaseString */
67+
$a = (STRING ) $b;
68+
69+
/* testBinary */
70+
$a = (binary) $b;
71+
72+
/* testSpacyUppercaseBinary */
73+
$a = ( BINARY ) $b;
74+
75+
/* testArray */
76+
$a = (array) $b;
77+
78+
/* testSpacyUppercaseArray */
79+
$a = ( ARRAY ) $b;
80+
81+
/* testObject */
82+
$a = (object) $b;
83+
84+
/* testSpacyUppercaseObject */
85+
$a = ( OBJECT ) $b;
86+
87+
/* testUnset */
88+
$a = (unset) $b;
89+
90+
/* testSpacyUppercaseUnset */
91+
$a = ( UNSET ) $b;
92+
93+
/* testVoid */
94+
$a = (void) $b;
95+
96+
/* testVoidNested */
97+
$a = ((void) $b);
98+
99+
/* testSpacyVoid */
100+
$a = ( void ) $b;
101+
102+
/* testTabbyVoid */
103+
$a = ( void ) $b; // Tab whitespace.
104+
105+
/* testUppercaseVoid */
106+
$a = (VOID) $b;
107+
108+
109+
/*
110+
* New lines and comments are not allowed in a type cast.
111+
*/
112+
113+
/* testNotATypeCast2 */
114+
$a = (
115+
void
116+
) $b;
117+
118+
/* testNotATypeCast3 */
119+
$a = (
120+
121+
void
122+
123+
) $b;
124+
125+
/* testNotATypeCast4 */
126+
$a = ( /*comment*/ void /*comment */ ) $b;
127+
128+
// Parse error. This must be the last test in the file!
129+
/* testNotATypeCast5 */
130+
$a = (void

0 commit comments

Comments
 (0)