Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Property::isVirtual() #1032

Open
JanTvrdik opened this issue Oct 5, 2024 · 5 comments
Open

Add Property::isVirtual() #1032

JanTvrdik opened this issue Oct 5, 2024 · 5 comments

Comments

@JanTvrdik
Copy link

In order to determine whether property is writable, it is now required among other thing to determine if property is virtual, which requires iterating over body of property hooks.

It would be helpful if new isVirtual() method was added to Property class.

As far as I can tell, this is the C implementation that the PHP code should match.

@nikic
Copy link
Owner

nikic commented Oct 5, 2024

This sounds like useful information to provide. As it requires a full recursive traversal of the body, this probably has to be via a visitor that adds an attribute?

@JanTvrdik
Copy link
Author

Visitor adding attribute would be one option.

Another would to locally recusively iterate over hooks nodes.

/**
 * Whether the property is virtual.
 */
public function isVirtual(): bool {
    if (\count($this->hooks) === 0) {
        return false;
    }

    foreach ($this->hooks as $hook) {
        if ($hook->body instanceof Node\Expr) {
            if ($hook->name->name === 'set' || $this->isHookUsingProperty([$hook->body])) {
                return false;
            }
        } elseif (\is_array($hook->body)) {
            if ($this->isHookUsingProperty($hook->body)) {
                return false;
            }
        }
    }

    return true;
}

/**
 * @param array<mixed> $nodes
 */
private function isHookUsingProperty(array $nodes): bool {
    foreach ($nodes as $node) {
        if ($node instanceof Node\Expr\PropertyFetch || $node instanceof Node\Expr\NullsafePropertyFetch) {
            if ($node->name->name === $this->props[0]->name->name && $node->var instanceof Node\Expr\Variable && $node->var->name === 'this') {
                return true;
            }
        }

        if ($node instanceof Node) {
            foreach ($node->getSubNodeNames() as $name) {
                if ($this->isHookUsingProperty(\is_array($node->$name) ? $node->$name : [$node->$name])) {
                    return true;
                }
            }
        }
    }

    return false;
}

@ondrejmirtes
Copy link
Contributor

I guess this code is a bit wrong when anonymous classes are involved in the hook body: https://3v4l.org/uumta

@ondrejmirtes
Copy link
Contributor

And maybe we can confuse the PHP algorithm with closures that have $this bound to a different object.

@ondrejmirtes
Copy link
Contributor

Even a hook like this still makes property virtual: https://3v4l.org/tLqed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants
@ondrejmirtes @JanTvrdik @nikic and others