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

Closure::bind 的 php 文档中的示例在匿名函数声明中包含 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

【问题讨论】:

    标签: php closures bind


    【解决方案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
    猜你喜欢
    • 2015-03-31
    • 2021-12-12
    • 1970-01-01
    • 1970-01-01
    • 2011-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多