public static function getCallerInfo($offset = 0)
    {
        $return = array(
            'file' => null,
            'line' => null,
            'function' => null,
            'class' => null,
            'type' => null,
        );
        $backtrace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT, 8);
        $numFrames = \count($backtrace);
        $regexInternal = '/^'.\preg_quote(__NAMESPACE__).'\b/';
        if (isset($backtrace[1]['class']) && \preg_match($regexInternal, $backtrace[1]['class'])) {
            // called from within
            // find the frame that called/triggered a debug function
            for ($i = $numFrames - 1; $i >= 0; $i--) {
                if (isset($backtrace[$i]['class']) && \preg_match($regexInternal, $backtrace[$i]['class'])) {
                    break;
                }
            }
        } else {
            $i = 1;
        }
        $i += $offset;
        $iLine = $i;
        $iFunc = $i + 1;
        if (isset($backtrace[$iFunc]) && \in_array($backtrace[$iFunc]['function'], array('call_user_func', 'call_user_func_array'))) {
            $iLine++;
            $iFunc++;
        } elseif (isset($backtrace[$iFunc]['class'])
            && $backtrace[$iFunc]['class'] == 'ReflectionMethod'
            && $backtrace[$iFunc]['function'] == 'invoke'
        ) {
            // called via ReflectionMethod->invoke()
            $iLine++;
            $iFunc--;
        }
        if (isset($backtrace[$iFunc])) {
            $return = \array_merge($return, \array_intersect_key($backtrace[$iFunc], $return));
            if ($return['type'] == '->') {
                $return['class'] = \get_class($backtrace[$iFunc]['object']);
            }
        }
        if (isset($backtrace[$iLine])) {
            $return['file'] = $backtrace[$iLine]['file'];
            $return['line'] = $backtrace[$iLine]['line'];
        } else {
            $return['file'] = $backtrace[$numFrames-1]['file'];
            $return['line'] = 0;
        }
        return $return;
    }
public static function getCallerInfo($offset = 0)
    {
        $return = array(
            'file' => null,
            'line' => null,
            'function' => null,
            'class' => null,
            'type' => null,
        );
        $backtrace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT, 8);
        $numFrames = \count($backtrace);
        $regexInternal = '/^'.\preg_quote(__NAMESPACE__).'\b/';
        if (isset($backtrace[1]['class']) && \preg_match($regexInternal, $backtrace[1]['class'])) {
            // called from within
            // find the frame that called/triggered a debug function
            for ($i = $numFrames - 1; $i >= 0; $i--) {
                if (isset($backtrace[$i]['class']) && \preg_match($regexInternal, $backtrace[$i]['class'])) {
                    break;
                }
            }
        } else {
            $i = 1;
        }
        $i += $offset;
        $iLine = $i;
        $iFunc = $i + 1;
        if (isset($backtrace[$iFunc]) && \in_array($backtrace[$iFunc]['function'], array('call_user_func', 'call_user_func_array'))) {
            $iLine++;
            $iFunc++;
        } elseif (isset($backtrace[$iFunc]['class'])
            && $backtrace[$iFunc]['class'] == 'ReflectionMethod'
            && $backtrace[$iFunc]['function'] == 'invoke'
        ) {
            // called via ReflectionMethod->invoke()
            $iLine++;
            $iFunc--;
        }
        if (isset($backtrace[$iFunc])) {
            $return = \array_merge($return, \array_intersect_key($backtrace[$iFunc], $return));
            if ($return['type'] == '->') {
                $return['class'] = \get_class($backtrace[$iFunc]['object']);
            }
        }
        if (isset($backtrace[$iLine])) {
            $return['file'] = $backtrace[$iLine]['file'];
            $return['line'] = $backtrace[$iLine]['line'];
        } else {
            $return['file'] = $backtrace[$numFrames-1]['file'];
            $return['line'] = 0;
        }
        return $return;
    }
Returns information regarding previous call stack position
call_user_func and call_user_func_array are skipped

Information returned:
function : function/method name
class :    fully qualified classname
file :     file
line :     line number
type :     "->": instance call, "::": static call, null: not object oriented

If a method is defined as static:
the class value will always be the class in which the method was defined,
type will always be "::", even if called with an ->

@param integer $offset Adjust how far to go back

@return array