Skip to content

Commit 2818d88

Browse files
committed
Simplify implementation
1 parent 3a36357 commit 2818d88

File tree

2 files changed

+20
-14
lines changed

2 files changed

+20
-14
lines changed

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

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,14 @@ protected function emitClone($result, $clone) {
99
$expr= $clone->arguments['object'] ?? $clone->arguments[0] ?? null;
1010
$with= $clone->arguments['withProperties'] ?? $clone->arguments[1] ?? null;
1111

12-
// Wrap clone with, e.g. clone($x, ['id' => 6100]), inside an IIFE as follows:
13-
// `function($args) { $this->id= $args['id']; return $this; }`, then bind
14-
// this closure to the cloned instance before invoking it with the named
15-
// arguments so we can access non-public members.
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.
1614
if ($with) {
17-
$c= $result->temp();
18-
$a= $result->temp();
19-
20-
$result->out->write('['.$c.'=clone ');
15+
$result->out->write('(function($c, $a) { foreach ($a as $p=>$v) { $c->$p= $v; } return $c;})(clone ');
2116
$this->emitOne($result, $expr);
22-
$result->out->write(','.$a.'=');
17+
$result->out->write(',');
2318
$this->emitOne($result, $with);
24-
$result->out->write(']?(function($a) { foreach ($a as $p=>$v) { $this->$p= $v; }return $this;})');
25-
$result->out->write('->bindTo('.$c.','.$c.')('.$a.'):null');
19+
$result->out->write(')');
2620
} else if (isset($clone->arguments['object'])) {
2721
$result->out->write('clone ');
2822
$this->emitOne($result, $expr);

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php namespace lang\ast\unittest\emit;
22

3-
use test\{Assert, Before, Test, Values};
3+
use lang\Error;
4+
use test\{Assert, Before, Ignore, Test, Values};
45

56
/** @see https://www.php.net/manual/en/language.oop5.cloning.php */
67
class CloningTest extends EmittingTest {
@@ -17,8 +18,8 @@ private function arguments() {
1718
#[Before]
1819
public function fixture() {
1920
$this->fixture= new class() {
20-
private $id= 1;
21-
private $name= 'Test';
21+
public $id= 1;
22+
public $name= 'Test';
2223

2324
public function toString() {
2425
return "<id: {$this->id}, name: {$this->name}>";
@@ -97,4 +98,15 @@ public function run($in) {
9798
[$this->fixture->toString(), $clone->toString()]
9899
);
99100
}
101+
102+
#[Test, Ignore('Could be done with reflection but with significant performance cost')]
103+
public function clone_with_respects_visibility() {
104+
$base= $this->type('class %T { private $id= 1; }');
105+
106+
Assert::throws(Error::class, fn() => $this->run('class %T extends '.$base.' {
107+
public function run() {
108+
clone($this, ["id" => 6100]); // Tries to set private member from base
109+
}
110+
}'));
111+
}
100112
}

0 commit comments

Comments
 (0)