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) | ||||
| - 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 #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) | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -282,7 +282,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface | ||||
|      */ | ||||
|     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]; | ||||
|         } | ||||
|  | ||||
| @ -290,7 +290,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         if (isset($this->_related[$name]) || array_key_exists($name, $this->_related)) { | ||||
|         if (array_key_exists($name, $this->_related)) { | ||||
|             return $this->_related[$name]; | ||||
|         } | ||||
|         $value = parent::__get($name); | ||||
|  | ||||
| @ -327,7 +327,12 @@ class BaseArrayHelper | ||||
|      */ | ||||
|     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]; | ||||
|             unset($array[$key]); | ||||
|  | ||||
| @ -608,17 +613,20 @@ class BaseArrayHelper | ||||
|      * Checks if the given array contains the specified key. | ||||
|      * This method enhances the `array_key_exists()` function by supporting case-insensitive | ||||
|      * 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 bool $caseSensitive whether the key comparison should be case-sensitive | ||||
|      * @return bool whether the array contains the specified key | ||||
|      */ | ||||
|     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) { | ||||
|             // Function `isset` checks key faster but skips `null`, `array_key_exists` handles this case | ||||
|             // https://www.php.net/manual/en/function.array-key-exists.php#107786 | ||||
|             if (is_array($array) && (isset($array[$key]) || array_key_exists($key, $array))) { | ||||
|             if (is_array($array) && array_key_exists($key, $array)) { | ||||
|                 return true; | ||||
|             } | ||||
|             // 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); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @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() | ||||
|     { | ||||
|         $array = [ | ||||
| @ -506,14 +529,21 @@ class ArrayHelperTest extends TestCase | ||||
|     /** | ||||
|      * @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[1.0] = 'some value'; | ||||
|  | ||||
|         $result = ArrayHelper::getValue($array, 1.0); | ||||
|         $array[1.1] = 'some value'; | ||||
|         $array[2.1] = null; | ||||
|  | ||||
|         $result = ArrayHelper::getValue($array, 1.2); | ||||
|         $this->assertEquals('some value', $result); | ||||
|  | ||||
|         $result = ArrayHelper::getValue($array, 2.2); | ||||
|         $this->assertNull($result); | ||||
|     } | ||||
|  | ||||
|     public function testIndex() | ||||
| @ -712,6 +742,7 @@ class ArrayHelperTest extends TestCase | ||||
|             'a' => 1, | ||||
|             'B' => 2, | ||||
|         ]; | ||||
|  | ||||
|         $this->assertTrue(ArrayHelper::keyExists('a', $array)); | ||||
|         $this->assertFalse(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)); | ||||
|     } | ||||
|  | ||||
|     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() | ||||
|     { | ||||
|         $array = new TraversableArrayAccessibleObject([ | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 rhertogh
					rhertogh