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);
    }