- Add test for property hooks preservation and invocation after __clone - Add test for private/protected/readonly property scope handling in clone-with - Add test for trait method scope usage inside clone-with operations - Update documentation to reflect completed clone-with implementation coverage - Remove pending classification for clone-with scoped/readonly/hooked properties - Remove TODO comment about property handlers preservation in clone-with operationmaster
parent
795a8e0a1d
commit
b2246cd456
6 changed files with 154 additions and 8 deletions
@ -0,0 +1,71 @@ |
|||||||
|
--TEST-- |
||||||
|
PHP 8.5 clone-with preserves TypePHP property handlers and invokes hooks after __clone |
||||||
|
--SKIPIF-- |
||||||
|
<?php |
||||||
|
if (PHP_VERSION_ID < 80500) { |
||||||
|
die('skip requires PHP 8.5'); |
||||||
|
} |
||||||
|
?> |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
class CloneWithHookValue |
||||||
|
{ |
||||||
|
public int $value { |
||||||
|
get => $this->value * 2; |
||||||
|
set { |
||||||
|
echo 'set:', $value, "\n"; |
||||||
|
if ($value < 0) { |
||||||
|
throw new InvalidArgumentException('negative value'); |
||||||
|
} |
||||||
|
$this->value = $value + 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public function __construct() |
||||||
|
{ |
||||||
|
$this->value = 1; |
||||||
|
} |
||||||
|
|
||||||
|
public function __clone(): void |
||||||
|
{ |
||||||
|
echo '__clone:', $this->value, "\n"; |
||||||
|
} |
||||||
|
|
||||||
|
public function withValue(int $value): self |
||||||
|
{ |
||||||
|
return clone($this, ['value' => $value]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class CloneWithHookChild extends CloneWithHookValue {} |
||||||
|
|
||||||
|
function read_clone_hook_dynamically(mixed $object): int |
||||||
|
{ |
||||||
|
return $object->value; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$source = new CloneWithHookChild(); |
||||||
|
$copy = $source->withValue(5); |
||||||
|
|
||||||
|
var_dump(read_clone_hook_dynamically($source)); |
||||||
|
var_dump(read_clone_hook_dynamically($copy)); |
||||||
|
|
||||||
|
try { |
||||||
|
$source->withValue(-1); |
||||||
|
} catch (InvalidArgumentException $error) { |
||||||
|
echo $error->getMessage(), "\n"; |
||||||
|
} |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
set:1 |
||||||
|
__clone:4 |
||||||
|
set:5 |
||||||
|
int(4) |
||||||
|
int(12) |
||||||
|
__clone:4 |
||||||
|
set:-1 |
||||||
|
negative value |
||||||
@ -0,0 +1,45 @@ |
|||||||
|
--TEST-- |
||||||
|
PHP 8.5 clone-with uses the consuming class scope inside trait methods |
||||||
|
--SKIPIF-- |
||||||
|
<?php |
||||||
|
if (PHP_VERSION_ID < 80500) { |
||||||
|
die('skip requires PHP 8.5'); |
||||||
|
} |
||||||
|
?> |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
trait CloneWithTraitScope |
||||||
|
{ |
||||||
|
private int $traitPrivate = 1; |
||||||
|
|
||||||
|
public function withTraitPrivate(int $value): self |
||||||
|
{ |
||||||
|
return clone($this, ['traitPrivate' => $value]); |
||||||
|
} |
||||||
|
|
||||||
|
public function traitPrivate(): int |
||||||
|
{ |
||||||
|
return $this->traitPrivate; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class CloneWithTraitBase |
||||||
|
{ |
||||||
|
use CloneWithTraitScope; |
||||||
|
} |
||||||
|
|
||||||
|
class CloneWithTraitChild extends CloneWithTraitBase {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$source = new CloneWithTraitChild(); |
||||||
|
$copy = $source->withTraitPrivate(9); |
||||||
|
|
||||||
|
var_dump($source->traitPrivate()); |
||||||
|
var_dump($copy->traitPrivate()); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
int(1) |
||||||
|
int(9) |
||||||
Loading…
Reference in new issue