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::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
【问题讨论】:
【参考方案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 闭包:为啥绑定到静态类时匿名函数声明中的“静态”?的主要内容,如果未能解决你的问题,请参考以下文章