Skip to content

[RFC] Introduce ImprovedParentConnectingVisitor #8035

@samsonasik

Description

@samsonasik

Background

@TomasVotruba @staabm currently, we use PhpParser\NodeVisitor\ParentConnectingVisitor which work with stack of every nodes, eg, the following code:

$a['a'['b'['c']]];

Above, c parent is b and b parent is a, and so on. That may cause a lot of stack saved on:

$this->stack[] = $node;

ref https://github.com/nikic/PHP-Parser/blob/19526a33fb561ef417e822e85f08a00db4059c17/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php#L34

Current approach to removing parent call usage is by:

  • use top possible use case, which Expression, Return_, then traverse() inside to refactor.
  • mark new attribute to know if the node is part of other node, eg: is_arg_value

That set and get will increased and possibly will bite use again, then the memory will increase instead of decrease.

Possible Solution

Scope is get from the parent node, and mostly if inside same Stmt, eg: on same Expression stmt, we will have same Scope, I think we can create improved ParentConnectingVisitor, let's say named: ImprovedParentConnectingVisitor, the pseudocode will be something like:

final class ImprovedParentConnectingVisitor extends NodeVisitorAbstract
{
    private ?Node $parentNode = null;

    public function enterNode(Node $node)
    {
        if ($node instanceof Stmt) {
            $this->parentNode = $node;
        }

        if ($node instanceof StmtsAwareInterface || $node instanceof ClassLike || $node instanceof Declare_) {
            if ($node->stmts !== null) {
                foreach ($node->stmts as $stmt) {
                    $stmt->setAttribute(AttributeKey::PARENT_NODE, $node);
                }
            }

            return null;
        }

        // parent already filled
        if ($node instanceof Stmt) {
            return null;
        }

        if ($this->parentNode instanceof Stmt) {    
            $node->setAttribute(AttributeKey::PARENT_NODE, $this->parentNode);
        }

        return null;
    }
}

That should will make the following code:

$a['a'['b'['c']]];

the c, b, and a parent will be a Expression stmt, which now no need stack to save previous passed node.

PARENT_NODE will no longer deprecated, but got slimmer relation it only do:

`Stmt` -> `Expr` 

instead of

`Stmt` -> `Expr` -> `Expr` -> `Expr`.

what do you guys think?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions