php闭包:为什么绑定到静态类时匿名函数声明中的'static'?

lea*_*php 13 php closures bind

php文档中的示例Closure::bind包含static匿名函数声明.为什么?如果删除它,我找不到区别.

:

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

没有:

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

lea*_*php 24

发现了区别:你不能将静态闭包绑定到对象,只能更改对象范围.

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
Run Code Online (Sandbox Code Playgroud)

  • +1 好发现;我注意到 `$this` 是未绑定的,但它 *不能* 绑定的事实很有趣。 (2认同)

jlh*_*jlh 13

我不敢苟同。确实,这通常无关紧要。但有时它的问题一大堆

持有对 的引用的闭包$this可能会阻止对该对象的垃圾收集,这反过来也可能显着影响性能。这是一个真正产生巨大差异的例子:

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);
Run Code Online (Sandbox Code Playgroud)

这是正常关闭的输出:

This took 55ms and 134MB of memory
Run Code Online (Sandbox Code Playgroud)

这是带有静态闭包的输出:

This took 22ms and 1MB of memory
Run Code Online (Sandbox Code Playgroud)

我在 Debian Buster 上用 PHP 7.3.19 对此进行了测试,所以 YMMV。显然,这是一个专门构造的示例来演示差异。但是这样的事情也可能发生在实际应用中。我开始使用 Slevomat 的SlevomatCodingStandard.Functions.StaticClosure嗅探来提醒我总是使用静态闭包。

  • 在各种 php 版本中尝试:https://3v4l.org/QnDuA,它在 php 8.1 中仍然有效 (6认同)
  • 20000 次迭代: 使用静态:这花费了 107 毫秒和 7MB 内存/没有静态:这花费了 545 毫秒和 1338MB 内存 在 PHP 7.4.16 / linux mint (ubuntu beaver) (2认同)

小智 11

与其他静态方法一样,静态闭包也无法访问$this

像任何其他方法一样,不访问的非静态闭包$this通常将在静态上下文中工作。

但是,静态闭包与任何其他静态方法一样,在性能上比非静态闭包略有好处,因此,出于微代码优化的考虑,我个人建议声明任何不需要访问$this为静态的闭包。

  • 你能提供静态闭包性能增益的来源吗? (3认同)

Phi*_*hil 5

正如您所注意到的,这并不重要,尽管如果您将E_STRICT包括在内,它可能会显示为错误error_reporting。(更新:不,不是

就像static在类方法上使用关键字一样。如果您未在方法中进行引用,则不一定需要$this(尽管这确实违反了严格的标准)。

我想PHP可以解决您的问题ClosureA因为null第二个参数是静态访问bind()

  • @learningphp`E_ALL`不包含`E_STRICT` (3认同)