src/DefinitionResolver.php
public function resolveVariableToNode($var)
    {
        $n = $var;
        // When a use is passed, start outside the closure to not return immediately
        // Use variable vs variable parsing?
        if ($var instanceof Node\UseVariableName) {
            $n = $var->getFirstAncestor(Node\Expression\AnonymousFunctionCreationExpression::class)->parent;
            $name = $var->getName();
        } else if ($var instanceof Node\Expression\Variable || $var instanceof Node\Parameter) {
            $name = $var->getName();
        } else {
            throw new \InvalidArgumentException('$var must be Variable, Param or ClosureUse, not ' . get_class($var));
        }
        if (empty($name)) {
            return null;
        }

        $shouldDescend = function ($nodeToDescand) {
            // Make sure not to decend into functions or classes (they represent a scope boundary)
            return !($nodeToDescand instanceof PhpParser\FunctionLike || $nodeToDescand instanceof PhpParser\ClassLike);
        };

        // Traverse the AST up
        do {
            // If a function is met, check the parameters and use statements
            if ($n instanceof PhpParser\FunctionLike) {
                if ($n->parameters !== null) {
                    foreach ($n->parameters->getElements() as $param) {
                        if ($param->getName() === $name) {
                            return $param;
                        }
                    }
                }
                // If it is a closure, also check use statements
                if ($n instanceof Node\Expression\AnonymousFunctionCreationExpression &&
                    $n->anonymousFunctionUseClause !== null &&
                    $n->anonymousFunctionUseClause->useVariableNameList !== null) {
                    foreach ($n->anonymousFunctionUseClause->useVariableNameList->getElements() as $use) {
                        if ($use->getName() === $name) {
                            return $use;
                        }
                    }
                }
                break;
            }

            // Check each previous sibling node and their descendents for a variable assignment to that variable
            // Each previous sibling could contain a declaration of the variable
            while (($prevSibling = $n->getPreviousSibling()) !== null && $n = $prevSibling) {

                // Check the sibling itself
                if (self::isVariableDeclaration($n, $name)) {
                    return $n;
                }

                // Check descendant of this sibling (e.g. the children of a previous if block)
                foreach ($n->getDescendantNodes($shouldDescend) as $descendant) {
                    if (self::isVariableDeclaration($descendant, $name)) {
                        return $descendant;
                    }
                }
            }
        } while (isset($n) && $n = $n->parent);
        // Return null if nothing was found
        return null;
    }
public function resolveVariableToNode($var)
    {
        $n = $var;
        // When a use is passed, start outside the closure to not return immediately
        // Use variable vs variable parsing?
        if ($var instanceof Node\UseVariableName) {
            $n = $var->getFirstAncestor(Node\Expression\AnonymousFunctionCreationExpression::class)->parent;
            $name = $var->getName();
        } else if ($var instanceof Node\Expression\Variable || $var instanceof Node\Parameter) {
            $name = $var->getName();
        } else {
            throw new \InvalidArgumentException('$var must be Variable, Param or ClosureUse, not ' . get_class($var));
        }
        if (empty($name)) {
            return null;
        }

        $shouldDescend = function ($nodeToDescand) {
            // Make sure not to decend into functions or classes (they represent a scope boundary)
            return !($nodeToDescand instanceof PhpParser\FunctionLike || $nodeToDescand instanceof PhpParser\ClassLike);
        };

        // Traverse the AST up
        do {
            // If a function is met, check the parameters and use statements
            if ($n instanceof PhpParser\FunctionLike) {
                if ($n->parameters !== null) {
                    foreach ($n->parameters->getElements() as $param) {
                        if ($param->getName() === $name) {
                            return $param;
                        }
                    }
                }
                // If it is a closure, also check use statements
                if ($n instanceof Node\Expression\AnonymousFunctionCreationExpression &&
                    $n->anonymousFunctionUseClause !== null &&
                    $n->anonymousFunctionUseClause->useVariableNameList !== null) {
                    foreach ($n->anonymousFunctionUseClause->useVariableNameList->getElements() as $use) {
                        if ($use->getName() === $name) {
                            return $use;
                        }
                    }
                }
                break;
            }

            // Check each previous sibling node and their descendents for a variable assignment to that variable
            // Each previous sibling could contain a declaration of the variable
            while (($prevSibling = $n->getPreviousSibling()) !== null && $n = $prevSibling) {

                // Check the sibling itself
                if (self::isVariableDeclaration($n, $name)) {
                    return $n;
                }

                // Check descendant of this sibling (e.g. the children of a previous if block)
                foreach ($n->getDescendantNodes($shouldDescend) as $descendant) {
                    if (self::isVariableDeclaration($descendant, $name)) {
                        return $descendant;
                    }
                }
            }
        } while (isset($n) && $n = $n->parent);
        // Return null if nothing was found
        return null;
    }
public function resolveVariableToNode ( $ var ) { $ n = $ var ; // When a use is passed, start outside the closure to not return immediately // Use variable vs variable parsing? if ( $ var instanceof Node \ UseVariableName ) { $ n = $ var -> getFirstAncestor ( Node \ Expression \ AnonymousFunctionCreationExpression :: class ) -> parent ; $ name = $ var -> getName ( ) ; } else if ( $ var instanceof Node \ Expression \ Variable || $ var instanceof Node \ Parameter ) { $ name = $ var -> getName ( ) ; } else { throw new \ InvalidArgumentException ( '$var must be Variable, Param or ClosureUse, not ' . get_class ( $ var ) ) ; } if ( empty ( $ name ) ) { return null ; } $ shouldDescend = function ( $ nodeToDescand ) { // Make sure not to decend into functions or classes (they represent a scope boundary) return ! ( $ nodeToDescand instanceof PhpParser \ FunctionLike || $ nodeToDescand instanceof PhpParser \ ClassLike ) ; } ; // Traverse the AST up do { // If a function is met, check the parameters and use statements if ( $ n instanceof PhpParser \ FunctionLike ) { if ( $ n -> parameters !== null ) { foreach ( $ n -> parameters -> getElements ( ) as $ param ) { if ( $ param -> getName ( ) === $ name ) { return $ param ; } } } // If it is a closure, also check use statements if ( $ n instanceof Node \ Expression \ AnonymousFunctionCreationExpression && $ n -> anonymousFunctionUseClause !== null && $ n -> anonymousFunctionUseClause -> useVariableNameList !== null ) { foreach ( $ n -> anonymousFunctionUseClause -> useVariableNameList -> getElements ( ) as $ use ) { if ( $ use -> getName ( ) === $ name ) { return $ use ; } } } break ; } // Check each previous sibling node and their descendents for a variable assignment to that variable // Each previous sibling could contain a declaration of the variable while ( ( $ prevSibling = $ n -> getPreviousSibling ( ) ) !== null && $ n = $ prevSibling ) { // Check the sibling itself if ( self :: isVariableDeclaration ( $ n , $ name ) ) { return $ n ; } // Check descendant of this sibling (e.g. the children of a previous if block) foreach ( $ n -> getDescendantNodes ( $ shouldDescend ) as $ descendant ) { if ( self :: isVariableDeclaration ( $ descendant , $ name ) ) { return $ descendant ; } } } } while ( isset ( $ n ) && $ n = $ n -> parent ) ; // Return null if nothing was found return null ; }
Returns the assignment or parameter node where a variable was defined

@param Node\Expression\Variable|Node\Expression\ClosureUse $var The variable access
@return Node\Expression\Assign|Node\Expression\AssignOp|Node\Param|Node\Expression\ClosureUse|null
Returns the assignment or parameter node where a variable was defined