code: private static function keys($val)
      {
          if (Abstracter::isAbstraction($val)) {
              // abstraction
              if ($val['type'] == 'object') {
                  if ($val['traverseValues']) {
                      // probably Traversable
                      $val = $val['traverseValues'];
                  } elseif ($val['stringified']) {
                      $val = null;
                  } elseif (isset($val['methods']['__toString']['returnValue'])) {
                      $val = null;
                  } else {
                      $val = \array_filter($val['properties'], function ($prop) {
                          return $prop['visibility'] === 'public';
                      });
                      /*
                          Reflection doesn't return properties in any given order
                          so, we'll sort for consistency
                      */
                      \ksort($val, SORT_NATURAL | SORT_FLAG_CASE);
                  }
              } else {
                  // ie callable or resource
                  $val = null;
              }
          }
          return \is_array($val)
              ? \array_keys($val)
              : array(self::SCALAR);
      }
docs: Get the keys contained in value
  
  @param mixed $val scalar value or abstraction
  
  @return string[]