Document and test unique behavior of CRM_Utils_Array::value()
authorNoah Miller <nm@lemnisc.us>
Sat, 14 Oct 2023 17:27:59 +0000 (13:27 -0400)
committerNoah Miller <nm@lemnisc.us>
Sat, 14 Oct 2023 17:27:59 +0000 (13:27 -0400)
CRM/Utils/Array.php
tests/phpunit/CRM/Utils/ArrayTest.php

index f1e2fd0adaed02094300e2b3eb68f8174661f717..b96b4bbc63e69e8f2ebec8dfd29e531a75fd8ea5 100644 (file)
@@ -43,18 +43,22 @@ class CRM_Utils_Array {
   }
 
   /**
-   * Returns $list[$key] if such element exists, or a default value otherwise.
+   * Returns $list[$key] if such element exists, or $default otherwise.
    *
-   * If $list is not actually an array at all, then the default value is
-   * returned. We hope to deprecate this behaviour.
+   * If $list is not an array or ArrayAccess object, $default is returned.
    *
+   * This function behaves exactly like:
+   *   $list[$key] ?? $default
+   * except that when $list[$key] exists and is NULL, this function will always
+   * return NULL.
    *
    * @param string $key
    *   Key value to look up in the array.
    * @param array|ArrayAccess $list
    *   Array from which to look up a value.
    * @param mixed $default
-   *   (optional) Value to return $list[$key] does not exist.
+   *   (optional) Value to return when $list[$key] does not exist. If $default
+   *   is not specified, NULL is used.
    *
    * @return mixed
    *   Can return any type, since $list might contain anything.
@@ -64,7 +68,6 @@ class CRM_Utils_Array {
       return array_key_exists($key, $list) ? $list[$key] : $default;
     }
     if ($list instanceof ArrayAccess) {
-      // ArrayAccess requires offsetExists is implemented for the equivalent to array_key_exists.
       return $list->offsetExists($key) ? $list[$key] : $default;
     }
     // @todo - eliminate these from core & uncomment this line.
index 5d2e152faa95d94e3fc52717bd8f667c1057d46f..9485e91bcbc7051bd3944a9819e5bbff0f1599a8 100644 (file)
@@ -513,4 +513,19 @@ class CRM_Utils_ArrayTest extends CiviUnitTestCase {
     $this->assertEquals(0, $todoCount);
   }
 
+  public function testValue() {
+    $list = ['a' => 'apple', 'b' => 'banana', 'c' => NULL];
+
+    // array key exists; value is not null
+    $this->assertEquals('apple', CRM_Utils_Array::value('a', $list, 'fruit'));
+
+    // array key does not exist
+    $this->assertEquals('fruit', CRM_Utils_Array::value(999, $list, 'fruit'));
+
+    // array key exists; value is null
+    // This is the one situation in which the function's behavior differs from
+    // that of PHP's null-coalescing operator (??)
+    $this->assertEquals(NULL, CRM_Utils_Array::value('c', $list, 'fruit'));
+  }
+
 }