Skip to content

Commit c5834df

Browse files
authored
Merge pull request #1006 from PHPCSStandards/phpcs-4.0/feature/708-ruleset-improve-property-setting-type-handling
Ruleset: improve type handling of user-set properties
2 parents b63cedf + 3f06fb4 commit c5834df

File tree

6 files changed

+81
-38
lines changed

6 files changed

+81
-38
lines changed

src/Ruleset.php

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,43 +1673,74 @@ public function setSniffProperty($sniffClass, $name, $settings)
16731673
return;
16741674
}
16751675

1676-
$value = $settings['value'];
1676+
$value = $this->getRealPropertyValue($settings['value']);
16771677

1678-
if (is_string($value) === true) {
1679-
$value = trim($value);
1680-
}
1681-
1682-
if ($value === '') {
1683-
$value = null;
1684-
}
1685-
1686-
// Special case for booleans.
1687-
if ($value === 'true') {
1688-
$value = true;
1689-
} else if ($value === 'false') {
1690-
$value = false;
1691-
} else if (substr($name, -2) === '[]') {
1692-
$name = $propertyName;
1678+
// Handle properties set inline via phpcs:set.
1679+
if (substr($name, -2) === '[]') {
16931680
$values = [];
1694-
if ($value !== null) {
1681+
if (is_string($value) === true) {
16951682
foreach (explode(',', $value) as $val) {
16961683
list($k, $v) = explode('=>', $val.'=>');
16971684
if ($v !== '') {
1698-
$values[trim($k)] = trim($v);
1685+
$values[trim($k)] = $v;
16991686
} else {
1700-
$values[] = trim($k);
1687+
$values[] = $k;
17011688
}
17021689
}
17031690
}
17041691

1705-
$value = $values;
1692+
$value = $this->getRealPropertyValue($values);
17061693
}
17071694

1708-
$sniffObject->$name = $value;
1695+
$sniffObject->$propertyName = $value;
17091696

17101697
}//end setSniffProperty()
17111698

17121699

1700+
/**
1701+
* Transform a property value received via a ruleset or inline annotation to a typed value.
1702+
*
1703+
* @param string|array<int|string, string> $value The current property value.
1704+
*
1705+
* @return mixed
1706+
*/
1707+
private function getRealPropertyValue($value)
1708+
{
1709+
if (is_array($value) === true) {
1710+
foreach ($value as $k => $v) {
1711+
$value[$k] = $this->getRealPropertyValue($v);
1712+
}
1713+
1714+
return $value;
1715+
}
1716+
1717+
if (is_string($value) === true) {
1718+
$value = trim($value);
1719+
1720+
if ($value === '') {
1721+
return null;
1722+
}
1723+
1724+
$valueLc = strtolower($value);
1725+
1726+
if ($valueLc === 'true') {
1727+
return true;
1728+
}
1729+
1730+
if ($valueLc === 'false') {
1731+
return false;
1732+
}
1733+
1734+
if ($valueLc === 'null') {
1735+
return null;
1736+
}
1737+
}//end if
1738+
1739+
return $value;
1740+
1741+
}//end getRealPropertyValue()
1742+
1743+
17131744
/**
17141745
* Gets the array of ignore patterns.
17151746
*

src/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,7 @@ protected function addError($phpcsFile, $stackPtr, $function, $pattern=null)
226226
$pattern = strtolower($function);
227227
}
228228

229-
if ($this->forbiddenFunctions[$pattern] !== null
230-
&& $this->forbiddenFunctions[$pattern] !== 'null'
231-
) {
229+
if ($this->forbiddenFunctions[$pattern] !== null) {
232230
$type .= 'WithAlternative';
233231
$data[] = $this->forbiddenFunctions[$pattern];
234232
$error .= '; use %s() instead';

tests/Core/Ruleset/Fixtures/PropertyTypeHandlingInline.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsNull null
1414
// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsNullCase NULL
15+
// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsNullTrimmed null
1516

1617
// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsBooleanTrue true
1718
// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsBooleanTrueCase True

tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/PropertyTypeHandlingSniff.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,26 @@ final class PropertyTypeHandlingSniff implements Sniff
5353
public $expectsFloatButAcceptsString;
5454

5555
/**
56-
* Used to verify that null gets set as a string.
56+
* Used to verify that null gets set as a proper null value.
5757
*
5858
* @var null
5959
*/
6060
public $expectsNull;
6161

6262
/**
63-
* Used to verify that null gets set as a string.
63+
* Used to verify that null gets set as a proper null value.
6464
*
6565
* @var null
6666
*/
6767
public $expectsNullCase;
6868

69+
/**
70+
* Used to verify that null gets set as a proper null value.
71+
*
72+
* @var null
73+
*/
74+
public $expectsNullTrimmed;
75+
6976
/**
7077
* Used to verify that booleans get set as proper boolean values.
7178
*

tests/Core/Ruleset/PropertyTypeHandlingTest.php

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*
2020
* @covers \PHP_CodeSniffer\Ruleset::processRule
2121
* @covers \PHP_CodeSniffer\Ruleset::setSniffProperty
22+
* @covers \PHP_CodeSniffer\Ruleset::getRealPropertyValue
2223
*/
2324
final class PropertyTypeHandlingTest extends TestCase
2425
{
@@ -91,17 +92,17 @@ public static function dataTypeHandling()
9192
'string',
9293
'10',
9394
'1.5',
94-
'null',
95-
'true',
96-
'false',
95+
null,
96+
true,
97+
false,
9798
];
9899
$expectedArrayKeysAndValues = [
99100
'string' => 'string',
100101
10 => '10',
101102
'float' => '1.5',
102-
'null' => 'null',
103-
'true' => 'true',
104-
'false' => 'false',
103+
'null' => null,
104+
'true' => true,
105+
'false' => false,
105106
];
106107

107108
return [
@@ -125,21 +126,25 @@ public static function dataTypeHandling()
125126
'propertyName' => 'expectsFloatButAcceptsString',
126127
'expected' => '12.345',
127128
],
128-
'Null value gets set as string' => [
129+
'Null value gets set as null' => [
129130
'propertyName' => 'expectsNull',
130-
'expected' => 'null',
131+
'expected' => null,
131132
],
132-
'Null (uppercase) value gets set as string' => [
133+
'Null (uppercase) value gets set as null' => [
133134
'propertyName' => 'expectsNullCase',
134-
'expected' => 'NULL',
135+
'expected' => null,
136+
],
137+
'Null (with spaces) value gets set as null' => [
138+
'propertyName' => 'expectsNullTrimmed',
139+
'expected' => null,
135140
],
136141
'True value gets set as boolean' => [
137142
'propertyName' => 'expectsBooleanTrue',
138143
'expected' => true,
139144
],
140145
'True (mixed case) value gets set as string' => [
141146
'propertyName' => 'expectsBooleanTrueCase',
142-
'expected' => 'True',
147+
'expected' => true,
143148
],
144149
'True (with spaces) value gets set as boolean' => [
145150
'propertyName' => 'expectsBooleanTrueTrimmed',
@@ -151,7 +156,7 @@ public static function dataTypeHandling()
151156
],
152157
'False (mixed case) value gets set as string' => [
153158
'propertyName' => 'expectsBooleanFalseCase',
154-
'expected' => 'fALSe',
159+
'expected' => false,
155160
],
156161
'False (with spaces) value gets set as boolean' => [
157162
'propertyName' => 'expectsBooleanFalseTrimmed',

tests/Core/Ruleset/PropertyTypeHandlingTest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
<property name="expectsNull" value="null"/>
1414
<property name="expectsNullCase" value="NULL"/>
15+
<property name="expectsNullTrimmed" value=" null"/>
1516

1617
<!-- Also tests that property names get cleaned of surrounding whitespace. -->
1718
<property name=" expectsBooleanTrue " value="true"/>

0 commit comments

Comments
 (0)