[PHP-DEV] Add $this return type

I’m looking for initial feedback on the following proposal.

Often, we have the following (fluent interface) setter method:

public function setName(?string $name): static
{
$this->name = $name;

return $this;
}

I propose to add “$this” as a return type, ie:

public function setName(?string $name): $this
{
$this->name = $name;
// implicit return $this;
}

public function setName(?string $name): $this

{
$this->name = $name;
// this would be an (compiler?) error
return $somethingOtherThanThis;
}

public function setName(?string $name): $this

{
$this->name = $name;
$self = $this;
// this would not be an error
return $self;
}

public function setName(?string $name): $this

{
$this->name = $name;
// technically useless, but not an error
return $this;
}

public function setName(?string $name): $this

{
$this->name = $name;
if (‘foobar’ === $name) {
// not an error to return early
return;
}
// do some other stuff

// any of the above legal examples
}

It should be obvious, but functions outside of a class context would not be able to use this syntax.

BC:
There would be no BC breaks, as this syntax is currently invalid (Parse error: syntax error, unexpected variable “$this”).

Other Considerations:
With regards to reflection and inheritance, “$this” would be considered an alias for “static”.

Regards,
radar3301

On Tue, Jun 25, 2024 at 2:29 AM radar3301 <radar3301@gmail.com> wrote:

I’m looking for initial feedback on the following proposal.

Often, we have the following (fluent interface) setter method:

public function setName(?string $name): static
{
$this->name = $name;

return $this;
}

I propose to add “$this” as a return type, ie:

public function setName(?string $name): $this
{
$this->name = $name;
// implicit return $this;
}

public function setName(?string $name): $this

{
$this->name = $name;
// this would be an (compiler?) error
return $somethingOtherThanThis;
}

public function setName(?string $name): $this

{
$this->name = $name;
$self = $this;
// this would not be an error
return $self;
}

public function setName(?string $name): $this

{
$this->name = $name;
// technically useless, but not an error
return $this;
}

public function setName(?string $name): $this

{
$this->name = $name;
if (‘foobar’ === $name) {
// not an error to return early
return;
}
// do some other stuff

// any of the above legal examples
}

It should be obvious, but functions outside of a class context would not be able to use this syntax.

BC:
There would be no BC breaks, as this syntax is currently invalid (Parse error: syntax error, unexpected variable “$this”).

Other Considerations:
With regards to reflection and inheritance, “$this” would be considered an alias for “static”.

Regards,
radar3301

I strongly agree that an alias for the “static” keyword is really necessary to improve the semantics of the language.

The word “static” is used for many things: static methods, static classes and Late Static Bindings (that is the case that you are discussing).

I think that in the case of Late Static Bindings (e.g. new static() or return type ..(): static), the word “static” does not give any clue about
the meaning of that code.
Thus, I like your proposal.

The part that I do not like is the implicit return: it may confuse developers and static analysis tools.

Is it possible to replace “$this” with “this”? Cleaner and coherent with “self”.

Regards,

Luigi

On Tue, Jun 25, 2024 at 3:28 AM radar3301 <radar3301@gmail.com> wrote:

I’m looking for initial feedback on the following proposal.

I propose to add “$this” as a return type, ie:

Worth reading:

@Alexandru:

Worth reading:

Ah shoot, my search-fu failed me (it's not listed on the RFC page, and
I suppose I was not using
the right search terms). I'm glad to find out this rfc previously
existed, and in that case, I
guess I'd like to revive that discussion. :slight_smile:

@Luigi:

The part that I do not like is the implicit return: it may confuse developers and static analysis
tools.

I understand the implicit return may be somewhat confusing, but one of
the secondary driving
factors, aside from a much clearer API signature (without requiring a
docblock comment), and engine
enforced object safety, was the benefit of reduced "boilerplate" code.
However, I suppose I can
accept that this may not be possible, but I would like to discuss it
as a potential option. However,
I disagree with you about the static analysis tools.

Is it possible to replace "$this" with "this"? Cleaner and coherent with "self".

I actually thought about this a bit before posting, and I came to the
same conclusion as Nicolas,
i.e.:
/**
* @return $this
*/

To quote Nicolas:

About the syntax, I think the one proposed in the RFC is crystal clear. I've been used to seeing
the "$" symbol [snip]

More on this below.

@previous commenters on the old thread

Andreas Heigl said:

If we allow a $this [snip] as a returntype to clarify that it has to be the same instance that is
returned, I would also either expect that the returntype 'self' does explicitly not allow the
same instance to be returned. As that would be a huge BC break [snip] we should implement a
returntype "!$this" to explicitly state that the contract here returns not the current instance
but a new one.

Strongly disagree. This would be too much of a BC, and I don't really
see the benefit, even allowing
for a "!$this"-style returntype. I'm not opposed to a separate RFC or
discussion regarding this, but
I don't feel it's appropriate here.

Sebastian Bergmann said:

[snip] please not "$this" as the name for a type.
Off the top of my head, I think that "same" could make sense.

My primary vote would still be for "$this" as explained above, but I
could potentially be persuaded
to switch to "this" or "same" as alternatives if the dollar-sign is
too much of a hang-up.

Regards,
radar3301

Not a fan of using a variable as a return type. This will cause havoc for Tokenizer based static analysis tooling. Not a fan of the implicit return either. Also don’t really see the need as there is the static return type already.

···

On 25-6-2024 19:53, radar3301 wrote:

Sebastian Bergmann said:

[snip] please not "$this" as the name for a type.
Off the top of my head, I think that "same" could make sense.

My primary vote would still be for "$this" as explained above, but I
could potentially be persuaded
to switch to "this" or "same" as alternatives if the dollar-sign is
too much of a hang-up.

That wouldn’t be possible, as this is a valid class name: https://3v4l.org/ujGOT

···

Best regards,
Bruce Weirdan mailto:weirdan@gmail.com

I’d see it as useful if the type conveyed identity too, although it also means that I would never use it, since I design immutable APIs, when possible :smiley:

···

Marco Pivetta

https://mastodon.social/@ocramius

https://ocramius.github.io/

Juliette Reinders Folmer said:

Not a fan of using a variable as a return type. This will cause
havoc for Tokenizer based static analysis tooling.

I will concede that until the tools are updated to handle the new
(currently invalid) syntax, it would cause issues. But that happens
everytime a new syntax is introduced into PHP anyway (the original
return-types RFC, match, the proposed property accessors, etc.), so
I'm a bit confused as why this is an issue that would stop the RFC?

---

Juliette Reinders Folmer said:

Also don't really see the need as there is the `static` return type
already.

To quote Nicolas, who said it far better than I could:

I tried switching from the `@return $this` annotation to
`function (): static`, which is the closest approximation currently
supported by the engine, when I realized that this would loosen the
semantics of the corresponding interfaces[.]

---

Marco Pivetta said:

I'd see it as useful if the type conveyed identity too, although it
means that I would never use it, since I design immutable APIs, when
possible :smiley:

If reading documentation, I'd argue that seeing `function(): $this` in
a class already conveys plenty of "identity". If you're talking about
using the Reflection API to get identity the original RFC by Nikita
stated:

The `$this` type is a subtype of `static`. As such, it is possible
to restrict a `static` type to `$this` in a subclass (but not the
other way around).
In reflection, the `$this` type is represented as a
`ReflectionNamedType` with `isBuiltin() == true` and
`getName() == "$this"`.

So perhaps a change is needed in the returned `ReflectionNamedType` to
better identity the actual class of `$this`? Or am I missing your
point about identity here?

---

Bruce Weirdan said:

Luigi Cardamone wrote:
Is it possible to replace "$this" with "this"? Cleaner and coherent
with "self".

That wouldn't be possible, as `this` is a valid class name:

The "Return Type Declarations", "Scalar Type Declarations", "Reserve
More Types", and "Void Return Type" RFCs all prohibited their usage as
class, interface and trait names. Using `this` or `same` or `whatever`
else is decided is just par for the course.

However, that said, a search of github for:
- `language:php "class This "` returns 5.1k results
  (but it appears that most results are docblock comments)
- `language:php "class This extends"` returns 27 results
- `language:php "class This implements"` returns 8 results
- `language:php "class Same "` returns 290 results
- `language:php "class Same extends"` returns 193 results
- `language:php "class Same implements"` returns 14 results
- `language:php "@return $this"` returns 485k results.

---

Regards,
radar3301