====== PHP RFC: Partial Function Application for instance of non-static methods ("$this") ====== * Version: 1.0 * Date: 2026-01-16 * Author: Tim Düsterhus (tim@tideways-gmbh.com), Arnaud Le Blanc (arnaud.lb@gmail.com) * Status: Under Discussion * Implementation: https://github.com/arnaud-lb/php-src/pull/27 ===== Introduction ===== [[partial_function_application_v2|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. ===== 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. $__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: $__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: $__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: $__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: 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(): Partially applying $this for the 'choice_label' [[https://symfony.com/doc/current/reference/forms/types/choice.html#advanced-example-with-objects|with Symfony Form’s ''ChoiceType'']]: 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: 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: * Yes * No * Abstain ===== Patches and Tests ===== * https://github.com/arnaud-lb/php-src/pull/27 ===== Implementation ===== After the RFC is implemented, this section should contain: - the version(s) it was merged into - a link to the git commit(s) - a link to the PHP manual entry for the feature ===== References ===== * [[partial_function_application_v2|PHP RFC: Partial Function Application (v2)]] * [[https://github.com/php/php-src/pull/20934|zend_compile: Optimize array_map() with callable convert callback into foreach]] which is an optimization for array_map() that is dependent on Partial Function Application and thus nicely synergizes with this RFC. ===== 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.