public function getAbstraction($obj, $method = null, &$hist = array())
    {
        if (!\is_object($obj)) {
            return $obj;
        }
        $reflector = new \ReflectionObject($obj);
        $className = $reflector->getName();
        $isTableTop = $method === 'table' && \count($hist) < 2;  // rows (traversable) || row (traversable)
        $abs = new Event($obj, array(
            'className' => $className,
            'collectMethods' => !$isTableTop && $this->abstracter->getCfg('collectMethods') || $className == 'Closure',
            'constants' => array(),
            'debug' => $this->abstracter->ABSTRACTION,
            'debugMethod' => $method,
            'definition' => array(
                'fileName' => $reflector->getFileName(),
                'startLine' => $reflector->getStartLine(),
                'extensionName' => $reflector->getExtensionName(),
            ),
            'extends' => array(),
            'implements' => $reflector->getInterfaceNames(),
            'isExcluded' => $this->isObjExcluded($obj),
            'isRecursion' => \in_array($obj, $hist, true),
            'methods' => array(),   // if !collectMethods, may still get ['__toString']['returnValue']
            'phpDoc' => array(
                'summary' => null,
                'description' => null,
                // additional tags
            ),
            'properties' => array(),
            'scopeClass' => $this->getScopeClass($hist),
            'stringified' => null,
            'type' => 'object',
            'traverseValues' => array(),    // populated if method is table && traversable
            'viaDebugInfo' => $this->abstracter->getCfg('useDebugInfo') && $reflector->hasMethod('__debugInfo'),
            // these are temporary values available during abstraction
            'collectPropertyValues' => true,
            'hist' => $hist,
            'propertyOverrideValues' => array(),
            'reflector' => $reflector,
        ));
        $keysTemp = \array_flip(array('collectPropertyValues','hist','propertyOverrideValues','reflector'));
        if ($abs['isRecursion']) {
            return \array_diff_key($abs->getValues(), $keysTemp);
        }
        /*
            debug.objAbstractStart subscriber may
            set isExcluded
            set collectPropertyValues (boolean)
            set collectMethods (boolean)
            set propertyOverrideValues
            set stringified
            set traverseValues
        */
        $abs = $this->abstracter->debug->internal->publishBubbleEvent('debug.objAbstractStart', $abs);
        if (\array_filter(array($abs['isExcluded'], $abs->isPropagationStopped()))) {
            return \array_diff_key($abs->getValues(), $keysTemp);
        }
        $this->getAbstractionDetails($abs);
        /*
            debug.objAbstractEnd subscriber has free reign to modify abtraction array
        */
        $return = $this->abstracter->debug->internal->publishBubbleEvent('debug.objAbstractEnd', $abs)->getValues();
        $this->sort($return['properties']);
        $this->sort($return['methods']);
        return \array_diff_key($return, $keysTemp);
    }