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

Override static in return types with self in final classes #17725

Open
rekmixa opened this issue Feb 6, 2025 · 10 comments
Open

Override static in return types with self in final classes #17725

rekmixa opened this issue Feb 6, 2025 · 10 comments

Comments

@rekmixa
Copy link

rekmixa commented Feb 6, 2025

Description

After implementing static types in return methods, I noticed one thing that was illogical, in my opinion.

We have the following code:

<?php

declare(strict_types=1);

interface A
{
    public function method1(): static;
}

abstract class B
{
    abstract public function method2(): static;
}

trait C
{
    abstract public function method3(): static;
}

final class Foo extends B implements A
{
    use C;

    public function method1(): static
    {
        return $this;
    }

    public function method2(): static
    {
        return $this;
    }

    public function method3(): static
    {
        return $this;
    }
}

$foo = new Foo();

var_dump($foo->method1());
var_dump($foo->method2());
var_dump($foo->method3());

It seems to me that in final classes, redefining return types in methods from static to self will not be a violation of covariance, because the final class will never have children. But now it triggers an error Fatal error: Declaration of Foo::method2(): Foo must be compatible with B::method2(): static. What do you think about this?

final class Foo extends B implements A
{
    use C;

    public function method1(): self
    {
        return $this;
    }

    public function method2(): self
    {
        return $this;
    }

    public function method3(): self
    {
        return $this;
    }
}

In addition, the same PHPStorm suggests replacing static types with self types in final classes (if this type is not specified in the prototype).

Below I attach a link to the pull request in which I implemented this logic.

#17724

  • There are no changes that break backward compatibility or covariance logic.
rekmixa pushed a commit to rekmixa/php-src that referenced this issue Feb 7, 2025
@Girgias
Copy link
Member

Girgias commented Feb 7, 2025

I cannot see anything wrong with this transformation either.

static ⊑ self where static is dependent on the class calling it. If self is final, then the class calling the method is always self as such static = self.

@iluuu1994
Copy link
Member

It's sound, but is it necessary? If the child removes final, it will need to migrate back to static. But I don't object.

@Girgias
Copy link
Member

Girgias commented Feb 10, 2025

The one advantage I could see is for the engine to do this transformation, which could simplify some variance checks and give more robust Reflection information if/when we add isSubTypeOf style methods to reflection if done in tandem with #17755 / #11460

@iluuu1994
Copy link
Member

Letting the engine do it would be fine, although it is obviously observable. Might be worth sending a quick e-mail to the list.

rekmixa added a commit to rekmixa/php-src that referenced this issue Feb 10, 2025
@rekmixa
Copy link
Author

rekmixa commented Feb 10, 2025

I added union types support for this feature and wrote additional tests for it. But I don't understand how to add support for this with intersection types) So for now I just added the !intersection check :)

https://github.com/php/php-src/pull/17724/files#diff-16d00017a3ed574cca152e8754246a1424db74e221934eb1c0c2513442882615R575

Maybe someone else can do this?

@rekmixa
Copy link
Author

rekmixa commented Feb 10, 2025

It's sound, but is it necessary? If the child removes final, it will need to migrate back to static. But I don't object.

Yes, there may be some inconvenience with this. But here, in fact, we are talking only about the fact that the language has the ability to replace static with self. This should not be mandatory. For me personally, it would be convenient. I am used to not using the static keyword inside when writing final classes, because it is a little confusing.

@rekmixa
Copy link
Author

rekmixa commented Feb 10, 2025

It's sound, but is it necessary? If the child removes final, it will need to migrate back to static. But I don't object.

It seems to me that using static inside classes always implies that the class can have children. And when static occurs in the final class, it's a bit confusing. So I'd like to see the language provide the ability to replace static with self, because again, it's not a violation of covariance.

@rekmixa
Copy link
Author

rekmixa commented Feb 10, 2025

Letting the engine do it would be fine, although it is obviously observable. Might be worth sending a quick e-mail to the list.

Okay, i'll send

@rekmixa
Copy link
Author

rekmixa commented Feb 10, 2025

rekmixa added a commit to rekmixa/php-src that referenced this issue Feb 10, 2025
rekmixa added a commit to rekmixa/php-src that referenced this issue Feb 10, 2025
rekmixa added a commit to rekmixa/php-src that referenced this issue Feb 10, 2025
rekmixa added a commit to rekmixa/php-src that referenced this issue Feb 10, 2025
rekmixa added a commit to rekmixa/php-src that referenced this issue Feb 10, 2025
@Girgias
Copy link
Member

Girgias commented Feb 11, 2025

I added union types support for this feature and wrote additional tests for it. But I don't understand how to add support for this with intersection types) So for now I just added the !intersection check :)

https://github.com/php/php-src/pull/17724/files#diff-16d00017a3ed574cca152e8754246a1424db74e221934eb1c0c2513442882615R575

Maybe someone else can do this?

You don't need to handle intersection types as they cannot contain self/parent/static.

rekmixa added a commit to rekmixa/php-src that referenced this issue Feb 11, 2025
rekmixa added a commit to rekmixa/php-src that referenced this issue Feb 11, 2025
…tests to folder Zend/tests/type_declarations/variance/override_static_with_self
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants