rfc:partial_function_application_this

PHP RFC: Partial Function Application for instance of non-static methods ("$this")

Introduction

Partial Function Application enabled convenient creation of Closures that just defer to an existing function with some parameters already filled in with the remaining ones being provided when the resulting Closure is called, which is particularly useful in combination with the array-processing functions (e.g. array_map()). Just being able to fill in parameters is however insufficient with instance methods which effectively carry an implicit $this parameter that is provided on the left side of the -> operator.

The lack of partial application support for the object instance of a method call thus still requires a manually written (short) closure when a common operation should be performed on a list of different objects. This RFC aims to provide a syntax that enables partial application of the implicit $this parameter.

<?php
 
$dates = [
    new DateTimeImmutable('now'),
];
 
$formattedDates = array_map(DateTimeImmutable::format(this: ?, "c"), $dates);
 
echo implode(", ", $formattedDates), PHP_EOL; // 2026-01-19T19:44:42+00:00
 
?>

Proposal

We propose allowing a named parameter this: ? to be combined with the “scope resolution operator” syntax of referring to a method. The resulting Closure will use the argument passed to the this: ? placeholder as the object to call the method on. The class name provided within the method reference will be used as the parameter type of the parameter accepting the object.

All other parameters will be (partially) applied as already known from the Partial Function Application RFC.

Since the this: ? parameter does not refer to a parameter in the underlying argument list and thus there is no ambiguity with regard to positional parameters it may be placed at any position of the parameter list (except for the variadic placeholder which must come last). In particular it may appear at the first position, before all positional parameters, mirroring the left-most position for a regular method call.

<?php
 
$c = DateTimeImmutable::format(this: ?, "c");
$c = DateTimeImmutable::format(this: ?, format: "c");
// are both effectively equivalent to:
$c = static fn (DateTimeImmutable $__this): string
    => $__this->format('c');

Any other position may be used to choose the position of the object instance in the resulting Closure, as already known from Partial Function Application:

<?php
 
$c = DateTimeImmutable::setTimestamp(this: ?, ?);
$c = DateTimeImmutable::setTimestamp(this: ?, timestamp: ?);
// are both effectively equivalent to:
$c = static fn (DateTimeImmutable $__this, int $timestamp): DateTimeImmutable
    => $__this->setTimestamp($timestamp);
 
// and
 
$c = DateTimeImmutable::setTimestamp(this: ?, ...);
// is effectively equivalent to:
$c = static fn (DateTimeImmutable $__this, int $timestamp): DateTimeImmutable
    => $__this->setTimestamp($timestamp, ...array_slice(func_get_args(), 2));
 
// but
 
$c = DateTimeImmutable::setTimestamp(?, this: ?);
$c = DateTimeImmutable::setTimestamp(timestamp: ?, this: ?);
// are both effectively equivalent to:
$c = static fn (int $timestamp, DateTimeImmutable $__this): DateTimeImmutable
    => $__this->setTimestamp($timestamp);

If the this: parameter is placed after optional parameters, they will become required:

<?php
 
$c = DateTimeImmutable::setTime(this: ?, ?, ?, ?, ?);
// is effectively equivalent to:
$c = static fn (DateTimeImmutable $__this, int $hour, int $minute, int $second = 0, int $microsecond = 0): DateTimeImmutable
    => $__this->setTime($hour, $minute, $second, $microsecond);
 
// but
 
$c = DateTimeImmutable::setTime(?, ?, ?, ?, this: ?);
// is effectively equivalent to:
$c = static fn (int $hour, int $minute, int $second, int $microsecond, DateTimeImmutable $__this): DateTimeImmutable
    => $__this->setTime($hour, $minute, $second, $microsecond);

Using the previously defined semantics, it naturally works to specify a method on an interface or a method that may be overridden in a child class. The parameter names, parameter types and the return type of the resulting Closure match that of the specified interface or parent class and do not adapt to the object in question. This is consistent with regular methods calls when implementing against an interface:

<?php
 
interface MyInterface {
    public function method(string $foo): int|string|bool;
}
 
class ParentClass implements MyInterface {
    public function method(string|array $foo): string {
        return '';
    }
}
 
class ChildClass extends ParentClass {
    public function method(string|array $bar): string {
        return '';
    }
}
 
$i = MyInterface::method(this: ?, ...);
// is effectively equivalent to:
$i = static fn (MyInterface $__this, string $foo): int|string|bool
    => $__this->method($foo);
 
$p = ParentClass::method(this: ?, ...);
// is effectively equivalent to:
$p = static fn (ParentClass $__this, string|array $foo): string
    => $__this->method($foo);
 
$c = ChildClass::method(this: ?, ...);
// is effectively equivalent to:
$c = static fn (ChildClass $__this, string|array $bar): string
    => $__this->method($bar);
 
// Throws TypeError, since an array is not a valid parameter on the interface,
// despite being valid on ChildClass::method().
$i(new ChildClass(), []); 
 
// Throws an Error about an unknown parameter 'bar', because the parameter
// is called 'foo' on the ParentClass::method().
$p(new ChildClass(), bar: []);

Virtual methods using __call() are supported as expected. Although not particularly useful, static methods are as well, similarly to how it is legal to call static methods using the -> operator.

Errors

Naturally, the this: parameter may not be used for free-standing functions.

$c = str_contains(this: ?, ?, ?); // Fatal error: Invalid use of 'this' placeholder

It may also not be used when partially applying an instance method using the -> operator, since the object is already specified:

$c = $dateTime->format(this: ?, "c"); // Fatal error: Invalid use of 'this' placeholder

The this: parameter may only be used when it is being partially applied. When the object is already known, the regular method call syntax can (and must) be used:

<?php
 
$date = new DateTimeImmutable('now');
 
$c = DateTimeImmutable::setTimestamp(this: $date, ...); // Invalid parameter name: this
// use instead:
$c = $date->setTimestamp(...);
 
$c = DateTimeImmutable::getTimestamp(this: $date); // Invalid parameter name: this
// use instead:
$c = $date->getTimestamp();

Note: All error messages are for illustrative purposes only and are subject to change in the final implementation to properly align them with existing messages in PHP.

Examples

Partially applying $this with array_map():

<?php
 
$dates = [
    new DateTimeImmutable('now'),
];
 
$formattedDates = array_map(DateTimeImmutable::format(this: ?, "c"), $dates);
 
?>

Partially applying $this for the 'choice_label' with Symfony Form’s ''ChoiceType'':

<?php
 
$builder->add('category', ChoiceType::class, [
    'placeholder' => false,
    'choices' => [
        new Category('Cat1'),
        new Category('Cat2'),
        new Category('Cat3'),
        new Category('Cat4'),
    ],
    'choice_label' => Category::getName(this: ?),
    /* … */
]);

Backward Incompatible Changes

While $this is a reserved variable name, thus is guaranteed to never be a valid parameter name, it may nevertheless be used as a named parameter name to use as a key for a variadic parameter:

<?php
 
function dump(...$args) {
    var_dump($args);
}
 
dump(this: 'this'); // array(1) { ["this"]=> string(4) "this" }

If this RFC is accepted, this would fail with a clear compile-time error, since this: must be followed by a placeholder. Users are still able to use "this" as a key in the resulting array by using the array unpacking syntax to pass parameters:

dump(...['this' => 'test']);

Seifeddine Gmati scanned 18975 Packagist packages containing 626044 files with Mago without finding any usage of this: as a named parameter. For reference, self: also had zero usages, object: had 32 and static: had 6.

Given that the backwards compatibility break results in a clear error message with a direct workaround that does not require complex tooling combined with the non-existent usage in public libraries, we expect the impact to be minimal in practice.

Proposed PHP Version(s)

Next PHP 8.x (8.6).

RFC Impact

To the Ecosystem

Partial Function Application itself is not yet released and it is unlikely that the ecosystem already adapted to it. Thus this additional proposal only has a small incremental impact, most notably by the new this: named parameter which is “magic” in that it does not refer to an actual parameter name, contains the leading dollar-sign ($) and may appear at the start of the argument list before all positional parameters.

To Existing Extensions

None.

To SAPIs

None.

Open Issues

  • The parameter name for the object instance in the generated Closure is currently selected to be $__this, since $this is not trivially possible in the implementation. This might still change.

Future Scope

None.

Voting Choices

Primary Vote requiring a 2/3 majority to accept the RFC:

Implement Partial Function Application for $this as described?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Patches and Tests

Implementation

After the RFC is implemented, this section should contain:

  1. the version(s) it was merged into
  2. a link to the git commit(s)
  3. a link to the PHP manual entry for the feature

References

Rejected Features

1. Using syntax like ?->method(?);. Since the target class is not known, the engine is unable to fill in parameter names, parameter types and the return type. It would also not allow to reorder the parameters in the resulting Closure, which is an explicit feature of Partial Function Application.

Changelog

  • 2026-01-31: Use this: ? instead of $this: ? as the placeholder.
  • 2026-01-22: Improve phrasing in “Errors” section.
  • 2026-01-22: Initial version.
rfc/partial_function_application_this.txt · Last modified: by timwolla