Skip to content

Commit f9c63e4

Browse files
committed
Support clone(...) first-class callable syntax
1 parent 511d04f commit f9c63e4

File tree

6 files changed

+38
-6
lines changed

6 files changed

+38
-6
lines changed

src/main/php/lang/ast/emit/CallablesAsClosures.class.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,12 @@ private function emitQuoted($result, $node) {
4848
}
4949

5050
protected function emitCallable($result, $callable) {
51-
$result->out->write('\Closure::fromCallable(');
52-
$this->emitQuoted($result, $callable->expression);
53-
$result->out->write(')');
51+
if ($callable->expression instanceof Literal && 'clone' === $callable->expression->expression) {
52+
$result->out->write('fn($o) => clone $o');
53+
} else {
54+
$result->out->write('\Closure::fromCallable(');
55+
$this->emitQuoted($result, $callable->expression);
56+
$result->out->write(')');
57+
}
5458
}
5559
}

src/main/php/lang/ast/emit/PHP81.class.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class PHP81 extends PHP {
2222
use
2323
EmulatePipelines,
2424
RewriteBlockLambdaExpressions,
25+
RewriteCallableClone,
2526
RewriteCloneWith,
2627
RewriteDynamicClassConstants,
2728
RewriteStaticVariableInitializations,

src/main/php/lang/ast/emit/PHP82.class.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class PHP82 extends PHP {
2222
use
2323
EmulatePipelines,
2424
RewriteBlockLambdaExpressions,
25+
RewriteCallableClone,
2526
RewriteCloneWith,
2627
RewriteDynamicClassConstants,
2728
RewriteStaticVariableInitializations,

src/main/php/lang/ast/emit/PHP84.class.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
* @see https://wiki.php.net/rfc#php_84
2020
*/
2121
class PHP84 extends PHP {
22-
use EmulatePipelines, RewriteCloneWith, RewriteBlockLambdaExpressions;
22+
use EmulatePipelines, RewriteCallableClone, RewriteCloneWith, RewriteBlockLambdaExpressions;
2323

2424
public $targetVersion= 80400;
2525

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php namespace lang\ast\emit;
2+
3+
use lang\ast\nodes\Literal;
4+
5+
/** @see https://wiki.php.net/rfc/clone_with_v2 */
6+
trait RewriteCallableClone {
7+
8+
protected function emitCallable($result, $callable) {
9+
if ($callable->expression instanceof Literal && 'clone' === $callable->expression->expression) {
10+
$result->out->write('fn($o) => clone $o');
11+
} else {
12+
parent::emitCallable($result, $callable);
13+
}
14+
}
15+
}

src/test/php/lang/ast/unittest/emit/CloningTest.class.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,19 @@ public function run() {
126126
}'));
127127
}
128128

129-
#[Test, Values(['clone(...)', '"clone"', '$func']), Runtime(php: '>=8.5.0')]
130-
public function clone_callable($expression) {
129+
#[Test]
130+
public function clone_callable() {
131+
$clone= $this->run('class %T {
132+
public function run($in) {
133+
return array_map(clone(...), [$in])[0];
134+
}
135+
}', $this->fixture);
136+
137+
Assert::true($clone instanceof $this->fixture && $this->fixture !== $clone);
138+
}
139+
140+
#[Test, Values(['"clone"', '$func']), Runtime(php: '>=8.5.0')]
141+
public function clone_callable_reference($expression) {
131142
$clone= $this->run('class %T {
132143
public function run($in) {
133144
$func= "clone";

0 commit comments

Comments
 (0)