learning php
learning php

Reputation: 1264

php closures: why the 'static' in the anonymous function declaration when binding to static class?

The example in the php documentation on Closure::bind include static on the anonymous function declaration. why? I can't find the difference if it is removed.

with:

class A {
    private static $sfoo = 1;
}
$cl1 = static function() { // notice the "static"
    return self::$sfoo;
};
$bcl1 = Closure::bind($cl1, null, 'A');
echo $bcl1(); // output: 1

without:

class A {
    private static $sfoo = 1;
}
$cl1 = function() {
    return self::$sfoo;
};
$bcl1 = Closure::bind($cl1, null, 'A');
echo $bcl1(); // output: 1

Upvotes: 48

Views: 23173

Answers (4)

jlh
jlh

Reputation: 4717

I beg to differ. It's true that often it won't matter. But sometimes it matters a whole lot.

The closure holding a reference to $this might prevent garbage collection of that object, which in turn may also impact performance significantly. Here's an example where it really makes a huge difference:

class LargeObject {
    protected $array;

    public function __construct() {
        $this->array = array_fill(0, 2000, 17);
    }

    public function getItemProcessor(): Closure {
        // Try with and without 'static' here
        return static function () {
            // do some processing unrelated to $this
        };
    }
}

$start = microtime(true);

$processors = [];
for ($i = 0; $i < 2000; $i++) {
    $lo = new LargeObject();
    $processors[] = $lo->getItemProcessor();
}

$memory = memory_get_usage() >> 20;
$time = (microtime(true) - $start) * 1000;
printf("This took %dms and %dMB of memory\n", $time, $memory);

Here's the output with a normal closure:

This took 55ms and 134MB of memory

Here's the output with a static closure:

This took 22ms and 1MB of memory

I tested this with PHP 7.3.19 on Debian Buster, so YMMV. Obviously this is a specially constructed example to demonstrate the difference. But things like this may happen in real applications as well. I started using Slevomat's SlevomatCodingStandard.Functions.StaticClosure sniff to remind me to always use static closures.

Upvotes: 63

Phil
Phil

Reputation: 164897

As you've noticed, it doesn't really matter.

It's like using the static keyword on a class method. You don't necessarily need it if you don't reference $this within the method (though this does violate strict standards).

I suppose PHP can work out you mean the Closure to access A statically due to the null 2nd argument to bind()

Upvotes: 8

Hendrik Rombach
Hendrik Rombach

Reputation: 340

Static Closures, like any other static method, cannot access $this.

Like any other method, a non-static Closure that does not access $this will generally work in a static context.

Upvotes: 23

learning php
learning php

Reputation: 1264

found the difference: you can't bind static closures to object, only change the object scope.

class foo { }

$cl = static function() { };

Closure::bind($cl, new foo); // PHP Warning:  Cannot bind an instance to a static closure
Closure::bind($cl, null, 'foo') // you can change the closure scope

Upvotes: 46

Related Questions