mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-10-31 18:47:33 +08:00 
			
		
		
		
	Fix #19914: Fixed ArrayHelper::keyExists() and  ::remove() functions when the key is a float and the value is null
				
					
				
			This commit is contained in:
		| @ -16,6 +16,7 @@ Yii Framework 2 Change Log | |||||||
| - Enh #19884: Added support Enums in Query Builder (sk1t0n) | - Enh #19884: Added support Enums in Query Builder (sk1t0n) | ||||||
| - Bug #19908: Fix associative array cell content rendering in Table widget (rhertogh) | - Bug #19908: Fix associative array cell content rendering in Table widget (rhertogh) | ||||||
| - Bug #19906: Fixed multiline strings in the `\yii\console\widgets\Table` widget (rhertogh) | - Bug #19906: Fixed multiline strings in the `\yii\console\widgets\Table` widget (rhertogh) | ||||||
|  | - Bug #19914: Fixed `ArrayHelper::keyExists()` and  `::remove()` functions when the key is a float and the value is `null` (rhertogh) | ||||||
| - Enh #19920: Broadened the accepted type of `Cookie::$expire` from `int` to `int|string|\DateTimeInterface|null` (rhertogh) | - Enh #19920: Broadened the accepted type of `Cookie::$expire` from `int` to `int|string|\DateTimeInterface|null` (rhertogh) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | |||||||
| @ -282,7 +282,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface | |||||||
|      */ |      */ | ||||||
|     public function __get($name) |     public function __get($name) | ||||||
|     { |     { | ||||||
|         if (isset($this->_attributes[$name]) || array_key_exists($name, $this->_attributes)) { |         if (array_key_exists($name, $this->_attributes)) { | ||||||
|             return $this->_attributes[$name]; |             return $this->_attributes[$name]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @ -290,7 +290,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface | |||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (isset($this->_related[$name]) || array_key_exists($name, $this->_related)) { |         if (array_key_exists($name, $this->_related)) { | ||||||
|             return $this->_related[$name]; |             return $this->_related[$name]; | ||||||
|         } |         } | ||||||
|         $value = parent::__get($name); |         $value = parent::__get($name); | ||||||
|  | |||||||
| @ -327,7 +327,12 @@ class BaseArrayHelper | |||||||
|      */ |      */ | ||||||
|     public static function remove(&$array, $key, $default = null) |     public static function remove(&$array, $key, $default = null) | ||||||
|     { |     { | ||||||
|         if (is_array($array) && (isset($array[$key]) || array_key_exists($key, $array))) { |         // ToDo: This check can be removed when the minimum PHP version is >= 8.1 (Yii2.2) | ||||||
|  |         if (is_float($key)) { | ||||||
|  |             $key = (int)$key; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (is_array($array) && array_key_exists($key, $array)) { | ||||||
|             $value = $array[$key]; |             $value = $array[$key]; | ||||||
|             unset($array[$key]); |             unset($array[$key]); | ||||||
|  |  | ||||||
| @ -608,17 +613,20 @@ class BaseArrayHelper | |||||||
|      * Checks if the given array contains the specified key. |      * Checks if the given array contains the specified key. | ||||||
|      * This method enhances the `array_key_exists()` function by supporting case-insensitive |      * This method enhances the `array_key_exists()` function by supporting case-insensitive | ||||||
|      * key comparison. |      * key comparison. | ||||||
|      * @param string $key the key to check |      * @param string|int $key the key to check | ||||||
|      * @param array|ArrayAccess $array the array with keys to check |      * @param array|ArrayAccess $array the array with keys to check | ||||||
|      * @param bool $caseSensitive whether the key comparison should be case-sensitive |      * @param bool $caseSensitive whether the key comparison should be case-sensitive | ||||||
|      * @return bool whether the array contains the specified key |      * @return bool whether the array contains the specified key | ||||||
|      */ |      */ | ||||||
|     public static function keyExists($key, $array, $caseSensitive = true) |     public static function keyExists($key, $array, $caseSensitive = true) | ||||||
|     { |     { | ||||||
|  |         // ToDo: This check can be removed when the minimum PHP version is >= 8.1 (Yii2.2) | ||||||
|  |         if (is_float($key)) { | ||||||
|  |             $key = (int)$key; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if ($caseSensitive) { |         if ($caseSensitive) { | ||||||
|             // Function `isset` checks key faster but skips `null`, `array_key_exists` handles this case |             if (is_array($array) && array_key_exists($key, $array)) { | ||||||
|             // https://www.php.net/manual/en/function.array-key-exists.php#107786 |  | ||||||
|             if (is_array($array) && (isset($array[$key]) || array_key_exists($key, $array))) { |  | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|             // Cannot use `array_has_key` on Objects for PHP 7.4+, therefore we need to check using [[ArrayAccess::offsetExists()]] |             // Cannot use `array_has_key` on Objects for PHP 7.4+, therefore we need to check using [[ArrayAccess::offsetExists()]] | ||||||
|  | |||||||
| @ -135,6 +135,29 @@ class ArrayHelperTest extends TestCase | |||||||
|         $this->assertEquals('defaultValue', $default); |         $this->assertEquals('defaultValue', $default); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function testRemoveWithFloat() | ||||||
|  |     { | ||||||
|  |         if (version_compare(PHP_VERSION, '8.1.0', '>=')) { | ||||||
|  |             $this->markTestSkipped('Using floats as array key is deprecated.'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $array = ['name' => 'b', 'age' => 3, 1.1 => null]; | ||||||
|  |  | ||||||
|  |         $name = ArrayHelper::remove($array, 'name'); | ||||||
|  |         $this->assertEquals($name, 'b'); | ||||||
|  |         $this->assertEquals($array, ['age' => 3, 1.1 => null]); | ||||||
|  |  | ||||||
|  |         $floatVal = ArrayHelper::remove($array, 1.1); | ||||||
|  |         $this->assertNull($floatVal); | ||||||
|  |         $this->assertEquals($array, ['age' => 3]); | ||||||
|  |  | ||||||
|  |         $default = ArrayHelper::remove($array, 'nonExisting', 'defaultValue'); | ||||||
|  |         $this->assertEquals('defaultValue', $default); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public function testRemoveValueMultiple() |     public function testRemoveValueMultiple() | ||||||
|     { |     { | ||||||
|         $array = [ |         $array = [ | ||||||
| @ -506,14 +529,21 @@ class ArrayHelperTest extends TestCase | |||||||
|     /** |     /** | ||||||
|      * @see https://github.com/yiisoft/yii2/pull/11549 |      * @see https://github.com/yiisoft/yii2/pull/11549 | ||||||
|      */ |      */ | ||||||
|     public function test() |     public function testGetValueWithFloatKeys() | ||||||
|     { |     { | ||||||
|  |         if (version_compare(PHP_VERSION, '8.1.0', '>=')) { | ||||||
|  |             $this->markTestSkipped('Using floats as array key is deprecated.'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         $array = []; |         $array = []; | ||||||
|         $array[1.0] = 'some value'; |         $array[1.1] = 'some value'; | ||||||
|  |         $array[2.1] = null; | ||||||
|         $result = ArrayHelper::getValue($array, 1.0); |  | ||||||
|  |  | ||||||
|  |         $result = ArrayHelper::getValue($array, 1.2); | ||||||
|         $this->assertEquals('some value', $result); |         $this->assertEquals('some value', $result); | ||||||
|  |  | ||||||
|  |         $result = ArrayHelper::getValue($array, 2.2); | ||||||
|  |         $this->assertNull($result); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function testIndex() |     public function testIndex() | ||||||
| @ -712,6 +742,7 @@ class ArrayHelperTest extends TestCase | |||||||
|             'a' => 1, |             'a' => 1, | ||||||
|             'B' => 2, |             'B' => 2, | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         $this->assertTrue(ArrayHelper::keyExists('a', $array)); |         $this->assertTrue(ArrayHelper::keyExists('a', $array)); | ||||||
|         $this->assertFalse(ArrayHelper::keyExists('b', $array)); |         $this->assertFalse(ArrayHelper::keyExists('b', $array)); | ||||||
|         $this->assertTrue(ArrayHelper::keyExists('B', $array)); |         $this->assertTrue(ArrayHelper::keyExists('B', $array)); | ||||||
| @ -723,6 +754,27 @@ class ArrayHelperTest extends TestCase | |||||||
|         $this->assertFalse(ArrayHelper::keyExists('c', $array, false)); |         $this->assertFalse(ArrayHelper::keyExists('c', $array, false)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function testKeyExistsWithFloat() | ||||||
|  |     { | ||||||
|  |         if (version_compare(PHP_VERSION, '8.1.0', '>=')) { | ||||||
|  |             $this->markTestSkipped('Using floats as array key is deprecated.'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $array = [ | ||||||
|  |             1 => 3, | ||||||
|  |             2.2 => 4, // Note: Floats are cast to ints, which means that the fractional part will be truncated. | ||||||
|  |             3.3 => null, | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         $this->assertTrue(ArrayHelper::keyExists(1, $array)); | ||||||
|  |         $this->assertTrue(ArrayHelper::keyExists(1.1, $array)); | ||||||
|  |         $this->assertTrue(ArrayHelper::keyExists(2, $array)); | ||||||
|  |         $this->assertTrue(ArrayHelper::keyExists('2', $array)); | ||||||
|  |         $this->assertTrue(ArrayHelper::keyExists(2.2, $array)); | ||||||
|  |         $this->assertTrue(ArrayHelper::keyExists(3, $array)); | ||||||
|  |         $this->assertTrue(ArrayHelper::keyExists(3.3, $array)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public function testKeyExistsArrayAccess() |     public function testKeyExistsArrayAccess() | ||||||
|     { |     { | ||||||
|         $array = new TraversableArrayAccessibleObject([ |         $array = new TraversableArrayAccessibleObject([ | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 rhertogh
					rhertogh