php 闭包:为啥绑定到静态类时匿名函数声明中的“静态”?

Posted

技术标签:

【中文标题】php 闭包:为啥绑定到静态类时匿名函数声明中的“静态”?【英文标题】:php closures: why the 'static' in the anonymous function declaration when binding to static class?php 闭包:为什么绑定到静态类时匿名函数声明中的“静态”? 【发布时间】:2013-11-22 20:21:35 【问题描述】:

Closure::bindphp 文档中的示例在匿名函数声明中包含 static。为什么?去掉的话我就找不到区别了。

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

没有

class A 
    private static $sfoo = 1;

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

【问题讨论】:

【参考方案1】:

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

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

【讨论】:

+1 好发现;我注意到$this 是未绑定的,但它无法被绑定的事实很有趣。【参考方案2】:

我不敢苟同。的确,很多时候这并不重要。但有时它非常重要

持有对$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);

这是正常关闭的输出:

This took 55ms and 134MB of memory

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

This took 22ms and 1MB of memory

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

【讨论】:

20000 次迭代:使用静态:这需要 107 毫秒和 7MB 内存/没有静态:这需要 545 毫秒和 1338MB 内存在 PHP 7.4.16 / linux mint (ubuntu beaver) 在各种php版本中尝试:3v4l.org/QnDuA,它在php 8.1中仍然有效【参考方案3】:

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

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

【讨论】:

你能提供静态闭包性能提升的来源吗? 我还想了解性能改进的来源以及它在代码库中的可测量性。在大多数情况下,需要解析的额外字符可能不会超过任何性能提升。 我的性能论据是基于传闻,后来我对其进行了基准测试,结果可以忽略不计【参考方案4】:

正如您所注意到的,这并不重要。

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

我想 PHP 可以解决你的意思是 Closure 静态访问 A 由于 null 的第二个参数 bind()

【讨论】:

error_reporting 设置为 E_ALL,我没有收到任何 E_STRICT 通知。 仍然没有错误。我尝试了error_reporting(-1) 和 error_reporting(E_ALL | E_STRICT)。我正在使用 PHP 5.5.5

以上是关于php 闭包:为啥绑定到静态类时匿名函数声明中的“静态”?的主要内容,如果未能解决你的问题,请参考以下文章

PHP匿名函数(闭包函数)详解_php技巧 - PHP

Golang中的匿名函数(闭包)

PHP函数-匿名函数(闭包函数)

php Closure类 闭包 匿名函数

PHP中的闭包和匿名函数

浅析PHP中的闭包和匿名函数