HomeSectionsAboutMerch
« Chained comparison operatorsClass scoping improvements »

Class method callable

General idea

Since the First-class callable syntax was passed, it has been able to create a closure directly from any function, static class method, or instance class method when also provided an instance.

This is useful as:

However it is not currently possible to create a closure to a class instance method, without also providing an instance.

This means programmers need to write small anonymous functions to call the instance method.

class Verification
{
    public function __construct(private string $id) {}

    public function getId(): string
    {
        return $this->id;
    }
}

$items = [new Verification('1-2-3-4')];

// If we copied the Java way of doing it, this:
// $fn = Verification::getId(...);

// $fn would be equivalent to:
$fn = static fn (Verification $v) => $v->getId();

$ids = array_map($fn, $items);

var_dump($ids);

// Output is:
// array(1) {
//     [0]=>
// string(7) "1-2-3-4"
// }

Hurdles to overcome

Distaste

It would be possible to 'just' allow the same syntax for static methods as instance methods, except the callable generated would have a parameter typed to the object type at the start, and the dispatch to the method happens internally:

class Foo {
    function bar(string $name): string {
        echo "Hello $name";
    } 
}

$fn = Foo::bar(...);

// $fn is equivalent to:
$fn = fn (Foo $foo, string $name): string => $foo->bar($name);

This seems to meet all of the required goals, except that it is novel and not immediately aesthetically pleasing.

Forecast

It's one of the tiny but important missing pieces in the language. Particularly for things like routers, you want to be able to specify instance methods of a class as a thing, without having to resort to string based programming.

Notes

Java uses the same syntax

Java uses the same syntax as I'm currently suggesting.

Hard to read documentation here.

Easier to read blog post.

Given this code:

class Integer {
    ...
    public int compareTo(Integer anotherInteger) {...}
}

List<Integer> numbers = Arrays.asList(5, 3, 50, 24, 40, 2, 9, 18);

Then you can use a "Reference to an instance method of an arbitrary object of a particular type"

numbers.stream()
.sorted(Integer::compareTo);

Is equivalent to creating a lambda:

numbers.stream()
  .sorted((a, b) -> a.compareTo(b));

i.e. the instance needs to be the first parameter.

Previously on internals

https://externals.io/message/119392 https://externals.io/message/120011