1
1
<?php namespace lang \ast \emit ;
2
2
3
- use lang \ast \nodes \{Signature , Parameter , UnpackExpression };
3
+ use lang \ast \nodes \{ArrayLiteral , UnpackExpression };
4
4
5
5
/** @see https://wiki.php.net/rfc/clone_with_v2 */
6
6
trait RewriteCloneWith {
7
7
8
8
protected function emitClone ($ result , $ clone ) {
9
+ static $ wrapper = '(function($c, array $w) { foreach ($w as $p=>$v) { $c->$p=$v; } return $c;}) ' ;
10
+
9
11
$ expr = $ clone ->arguments ['object ' ] ?? $ clone ->arguments [0 ] ?? null ;
10
12
$ with = $ clone ->arguments ['withProperties ' ] ?? $ clone ->arguments [1 ] ?? null ;
11
13
12
- // Wrap clone with, e.g. clone($x, ['id' => 6100]), inside an IIFE which
13
- /// iterates over the property-value pairs, assigning them to the clone.
14
- if ($ with ) {
15
- $ result ->out ->write ('(function($object, array $withProperties) { ' );
16
- $ result ->out ->write ('foreach ($withProperties as $p=>$v) { $object->$p=$v; } return $object;})(clone ' );
14
+ // Built ontop of a wrapper function which iterates over the property-value pairs,
15
+ // assigning them to the clone. Unwind unpack statements, e.g. `clone(...$args)`,
16
+ // into an array, manually unpacking it for invocation.
17
+ if ($ expr instanceof UnpackExpression || $ with instanceof UnpackExpression) {
18
+ $ t = $ result ->temp ();
19
+ $ result ->out ->write ('( ' .$ t .'= ' );
20
+ $ this ->emitOne ($ result , new ArrayLiteral ($ with ? [[null , $ expr ], [null , $ with ]] : [[null , $ expr ]], $ clone ->line ));
21
+ $ result ->out ->write (')? ' );
22
+ $ result ->out ->write ($ wrapper .'(clone ( ' .$ t .'["object"] ?? ' .$ t .'[0]), ' .$ t .'["withProperties"] ?? ' .$ t .'[1] ?? []) ' );
23
+ $ result ->out ->write (':null ' );
24
+ } else if ($ with ) {
25
+ $ result ->out ->write ($ wrapper .'(clone ' );
17
26
$ this ->emitOne ($ result , $ expr );
18
27
$ result ->out ->write (', ' );
19
28
$ this ->emitOne ($ result , $ with );
20
29
$ result ->out ->write (') ' );
21
- } else if ( isset ( $ clone -> arguments [ ' object ' ])) {
30
+ } else {
22
31
$ result ->out ->write ('clone ' );
23
32
$ this ->emitOne ($ result , $ expr );
24
- } else if ($ expr instanceof UnpackExpression) {
25
- $ result ->out ->write ('(function($u) { $c= clone $u["object"] ?? $u[0]; ' );
26
- $ result ->out ->write ('foreach ($u["withProperties"] ?? $u[1] ?? [] as $p=>$v) { $c->$p=$v; } return $c;})( ' );
27
- $ this ->emitOne ($ result , $ expr ->expression );
28
- $ result ->out ->write (') ' );
29
- } else {
30
- return parent ::emitClone ($ result , $ clone );
31
33
}
32
34
}
33
35
}
0 commit comments