11<?php namespace lang \ast \emit ;
22
3- use lang \ast \nodes \{Signature , Parameter , UnpackExpression };
3+ use lang \ast \nodes \{ArrayLiteral , UnpackExpression };
44
55/** @see https://wiki.php.net/rfc/clone_with_v2 */
66trait RewriteCloneWith {
77
88 protected function emitClone ($ result , $ clone ) {
9+ static $ wrapper = '(function($c, array $w) { foreach ($w as $p=>$v) { $c->$p=$v; } return $c;}) ' ;
10+
911 $ expr = $ clone ->arguments ['object ' ] ?? $ clone ->arguments [0 ] ?? null ;
1012 $ with = $ clone ->arguments ['withProperties ' ] ?? $ clone ->arguments [1 ] ?? null ;
1113
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 ' );
1726 $ this ->emitOne ($ result , $ expr );
1827 $ result ->out ->write (', ' );
1928 $ this ->emitOne ($ result , $ with );
2029 $ result ->out ->write (') ' );
21- } else if ( isset ( $ clone -> arguments [ ' object ' ])) {
30+ } else {
2231 $ result ->out ->write ('clone ' );
2332 $ 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 );
3133 }
3234 }
3335}
0 commit comments