diff --git a/Zend/tests/assert/expect_015.phpt b/Zend/tests/assert/expect_015.phpt
index 695c4c166a83c..9f8e9b77003bc 100644
--- a/Zend/tests/assert/expect_015.phpt
+++ b/Zend/tests/assert/expect_015.phpt
@@ -183,7 +183,7 @@ assert(0 && ($a = function () {
     $x = $a ?? $b;
     [$a, $b, $c] = [1, 2 => 'x', 'z' => 'c'];
     @foo();
-    $y = clone $x;
+    $y = \clone($x);
     yield 1 => 2;
     yield from $x;
 }))
diff --git a/Zend/tests/clone/ast.phpt b/Zend/tests/clone/ast.phpt
new file mode 100644
index 0000000000000..13d94eb91d26c
--- /dev/null
+++ b/Zend/tests/clone/ast.phpt
@@ -0,0 +1,87 @@
+--TEST--
+Ast Printing
+--FILE--
+<?php
+
+$x = new stdClass();
+
+
+try {
+	assert(false &&  $y = clone $x);
+} catch (Error $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+
+try {
+	assert(false && $y = clone($x));
+} catch (Error $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+
+try {
+	assert(false && $y = clone($x, [ "foo" => $foo, "bar" => $bar ]));
+} catch (Error $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+
+try {
+	assert(false && $y = clone($x, $array));
+} catch (Error $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+
+try {
+	assert(false && $y = clone($x, $array, $extraParameter, $trailingComma, ));
+} catch (Error $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+
+try {
+	assert(false && $y = clone(object: $x, withProperties: [ "foo" => $foo, "bar" => $bar ]));
+} catch (Error $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+
+try {
+	assert(false && $y = clone($x, withProperties: [ "foo" => $foo, "bar" => $bar ]));
+} catch (Error $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+
+try {
+	assert(false && $y = clone(object: $x));
+} catch (Error $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+
+try {
+	assert(false && $y = clone(object: $x, [ "foo" => $foo, "bar" => $bar ]));
+} catch (Error $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+
+try {
+	assert(false && $y = clone(...["object" => $x, "withProperties" => [ "foo" => $foo, "bar" => $bar ]]));
+} catch (Error $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+
+try {
+	assert(false && $y = clone(...));
+} catch (Error $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECT--
+assert(false && ($y = \clone($x)))
+assert(false && ($y = \clone($x)))
+assert(false && ($y = \clone($x, ['foo' => $foo, 'bar' => $bar])))
+assert(false && ($y = \clone($x, $array)))
+assert(false && ($y = \clone($x, $array, $extraParameter, $trailingComma)))
+assert(false && ($y = \clone(object: $x, withProperties: ['foo' => $foo, 'bar' => $bar])))
+assert(false && ($y = \clone($x, withProperties: ['foo' => $foo, 'bar' => $bar])))
+assert(false && ($y = \clone(object: $x)))
+assert(false && ($y = \clone(object: $x, ['foo' => $foo, 'bar' => $bar])))
+assert(false && ($y = \clone(...['object' => $x, 'withProperties' => ['foo' => $foo, 'bar' => $bar]])))
+assert(false && ($y = \clone(...)))
diff --git a/Zend/tests/clone/bug36071.phpt b/Zend/tests/clone/bug36071.phpt
index 945118fef3754..d9b3bc9cbe1f2 100644
--- a/Zend/tests/clone/bug36071.phpt
+++ b/Zend/tests/clone/bug36071.phpt
@@ -8,7 +8,8 @@ $a = clone 0;
 $a[0]->b = 0;
 ?>
 --EXPECTF--
-Fatal error: Uncaught Error: __clone method called on non-object in %sbug36071.php:2
+Fatal error: Uncaught TypeError: clone(): Argument #1 ($object) must be of type object, int given in %s:%d
 Stack trace:
-#0 {main}
+#0 %s(%d): clone(0)
+#1 {main}
   thrown in %sbug36071.php on line 2
diff --git a/Zend/tests/clone/bug42817.phpt b/Zend/tests/clone/bug42817.phpt
index a681d861d0c8f..635e8f2a608d0 100644
--- a/Zend/tests/clone/bug42817.phpt
+++ b/Zend/tests/clone/bug42817.phpt
@@ -6,7 +6,8 @@ $a = clone(null);
 array_push($a->b, $c);
 ?>
 --EXPECTF--
-Fatal error: Uncaught Error: __clone method called on non-object in %sbug42817.php:2
+Fatal error: Uncaught TypeError: clone(): Argument #1 ($object) must be of type object, null given in %s:%d
 Stack trace:
-#0 {main}
+#0 %s(%d): clone(NULL)
+#1 {main}
   thrown in %sbug42817.php on line 2
diff --git a/Zend/tests/clone/bug42818.phpt b/Zend/tests/clone/bug42818.phpt
index b37ce13fd174a..9cd7050d55b97 100644
--- a/Zend/tests/clone/bug42818.phpt
+++ b/Zend/tests/clone/bug42818.phpt
@@ -5,7 +5,8 @@ Bug #42818 ($foo = clone(array()); leaks memory)
 $foo = clone(array());
 ?>
 --EXPECTF--
-Fatal error: Uncaught Error: __clone method called on non-object in %sbug42818.php:2
+Fatal error: Uncaught TypeError: clone(): Argument #1 ($object) must be of type object, array given in %s:%d
 Stack trace:
-#0 {main}
+#0 %s(%d): clone(Array)
+#1 {main}
   thrown in %sbug42818.php on line 2
diff --git a/Zend/tests/clone/callback.phpt b/Zend/tests/clone/callback.phpt
new file mode 100644
index 0000000000000..30ce6a93bc59f
--- /dev/null
+++ b/Zend/tests/clone/callback.phpt
@@ -0,0 +1,24 @@
+--TEST--
+As Callback
+--FILE--
+<?php
+
+class Foo {
+	private function __clone() {
+		
+	}
+
+	public function clone_me() {
+		return array_map(clone(...), [$this]);
+	}
+}
+
+$f = new Foo();
+
+$clone = $f->clone_me()[0];
+
+var_dump($f !== $clone);
+
+?>
+--EXPECT--
+bool(true)
diff --git a/Zend/tests/clone/clone_001.phpt b/Zend/tests/clone/clone_001.phpt
index 87024c3cd5614..dbbb16049b80b 100644
--- a/Zend/tests/clone/clone_001.phpt
+++ b/Zend/tests/clone/clone_001.phpt
@@ -7,7 +7,8 @@ $a = clone array();
 
 ?>
 --EXPECTF--
-Fatal error: Uncaught Error: __clone method called on non-object in %s:%d
+Fatal error: Uncaught TypeError: clone(): Argument #1 ($object) must be of type object, array given in %s:%d
 Stack trace:
-#0 {main}
+#0 %s(%d): clone(Array)
+#1 {main}
   thrown in %s on line %d
diff --git a/Zend/tests/clone/clone_003.phpt b/Zend/tests/clone/clone_003.phpt
index f163616a876dc..19f775f1e9ff3 100644
--- a/Zend/tests/clone/clone_003.phpt
+++ b/Zend/tests/clone/clone_003.phpt
@@ -9,7 +9,8 @@ $a = clone $b;
 --EXPECTF--
 Warning: Undefined variable $b in %s on line %d
 
-Fatal error: Uncaught Error: __clone method called on non-object in %s:%d
+Fatal error: Uncaught TypeError: clone(): Argument #1 ($object) must be of type object, null given in %s:%d
 Stack trace:
-#0 {main}
+#0 %s(%d): clone(NULL)
+#1 {main}
   thrown in %s on line %d
diff --git a/Zend/tests/clone/clone_with_001.phpt b/Zend/tests/clone/clone_with_001.phpt
new file mode 100644
index 0000000000000..ca6abd53a72eb
--- /dev/null
+++ b/Zend/tests/clone/clone_with_001.phpt
@@ -0,0 +1,75 @@
+--TEST--
+Clone with basic
+--FILE--
+<?php
+
+class Dummy { }
+
+$x = new stdClass();
+
+$foo = 'FOO';
+$bar = new Dummy();
+$array = [
+	'baz' => 'BAZ',
+	'array' => [1, 2, 3],
+];
+
+function gen() {
+	yield 'from_gen' => 'value';
+}
+
+var_dump(clone $x);
+var_dump(clone($x));
+var_dump(clone($x, [ 'foo' => $foo, 'bar' => $bar ]));
+var_dump(clone($x, $array));
+var_dump(clone($x, [ 'obj' => $x ]));
+
+var_dump(clone($x, [
+	'abc',
+	'def',
+	new Dummy(),
+	'named' => 'value',
+]));
+
+?>
+--EXPECTF--
+object(stdClass)#%d (0) {
+}
+object(stdClass)#%d (0) {
+}
+object(stdClass)#%d (2) {
+  ["foo"]=>
+  string(3) "FOO"
+  ["bar"]=>
+  object(Dummy)#%d (0) {
+  }
+}
+object(stdClass)#%d (2) {
+  ["baz"]=>
+  string(3) "BAZ"
+  ["array"]=>
+  array(3) {
+    [0]=>
+    int(1)
+    [1]=>
+    int(2)
+    [2]=>
+    int(3)
+  }
+}
+object(stdClass)#%d (1) {
+  ["obj"]=>
+  object(stdClass)#%d (0) {
+  }
+}
+object(stdClass)#%d (4) {
+  ["0"]=>
+  string(3) "abc"
+  ["1"]=>
+  string(3) "def"
+  ["2"]=>
+  object(Dummy)#%d (0) {
+  }
+  ["named"]=>
+  string(5) "value"
+}
diff --git a/Zend/tests/clone/clone_with_002.phpt b/Zend/tests/clone/clone_with_002.phpt
new file mode 100644
index 0000000000000..8b86e64c76aa8
--- /dev/null
+++ b/Zend/tests/clone/clone_with_002.phpt
@@ -0,0 +1,114 @@
+--TEST--
+Clone with respects visiblity
+--FILE--
+<?php
+
+class P {
+	public $a = 'default';
+	protected $b = 'default';
+	private $c = 'default';
+	public private(set) string $d = 'default';
+
+	public function m1() {
+		return clone($this, [ 'a' => 'updated A', 'b' => 'updated B', 'c' => 'updated C', 'd' => 'updated D' ]);
+	}
+}
+
+class C extends P {
+	public function m2() {
+		return clone($this, [ 'a' => 'updated A', 'b' => 'updated B', 'c' => 'dynamic C' ]);
+	}
+
+	public function m3() {
+		return clone($this, [ 'd' => 'inaccessible' ]);
+	}
+}
+
+class Unrelated {
+	public function m3(P $p) {
+		return clone($p, [ 'b' => 'inaccessible' ]);
+	}
+}
+
+$p = new P();
+
+var_dump(clone($p, [ 'a' => 'updated A' ]));
+var_dump($p->m1());
+
+$c = new C();
+var_dump($c->m1());
+var_dump($c->m2());
+try {
+	var_dump($c->m3());
+} catch (Error $e) {
+	echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+}
+
+try {
+	var_dump(clone($p, [ 'b' => 'inaccessible' ]));
+} catch (Error $e) {
+	echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+}
+
+try {
+	var_dump(clone($p, [ 'd' => 'inaccessible' ]));
+} catch (Error $e) {
+	echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+}
+
+try {
+	var_dump((new Unrelated())->m3($p));
+} catch (Error $e) {
+	echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECTF--
+object(P)#%d (4) {
+  ["a"]=>
+  string(9) "updated A"
+  ["b":protected]=>
+  string(7) "default"
+  ["c":"P":private]=>
+  string(7) "default"
+  ["d"]=>
+  string(7) "default"
+}
+object(P)#%d (4) {
+  ["a"]=>
+  string(9) "updated A"
+  ["b":protected]=>
+  string(9) "updated B"
+  ["c":"P":private]=>
+  string(9) "updated C"
+  ["d"]=>
+  string(9) "updated D"
+}
+object(C)#%d (4) {
+  ["a"]=>
+  string(9) "updated A"
+  ["b":protected]=>
+  string(9) "updated B"
+  ["c":"P":private]=>
+  string(9) "updated C"
+  ["d"]=>
+  string(9) "updated D"
+}
+
+Deprecated: Creation of dynamic property C::$c is deprecated in %s on line %d
+object(C)#%d (5) {
+  ["a"]=>
+  string(9) "updated A"
+  ["b":protected]=>
+  string(9) "updated B"
+  ["c":"P":private]=>
+  string(7) "default"
+  ["d"]=>
+  string(7) "default"
+  ["c"]=>
+  string(9) "dynamic C"
+}
+Error: Cannot modify private(set) property P::$d from scope C
+Error: Cannot access protected property P::$b
+Error: Cannot modify private(set) property P::$d from global scope
+Error: Cannot access protected property P::$b
diff --git a/Zend/tests/clone/clone_with_003.phpt b/Zend/tests/clone/clone_with_003.phpt
new file mode 100644
index 0000000000000..fa7ece0fe04fa
--- /dev/null
+++ b/Zend/tests/clone/clone_with_003.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Clone with supports property hooks
+--FILE--
+<?php
+
+class Clazz {
+	public string $hooked = 'default' {
+		set (string $value) {
+			$this->hooked = strtoupper($value);
+		}
+	}
+}
+
+$c = new Clazz();
+
+var_dump(clone($c, [ 'hooked' => 'updated' ]));
+
+?>
+--EXPECTF--
+object(Clazz)#%d (1) {
+  ["hooked"]=>
+  string(7) "UPDATED"
+}
diff --git a/Zend/tests/clone/clone_with_004.phpt b/Zend/tests/clone/clone_with_004.phpt
new file mode 100644
index 0000000000000..14d01bb75fa5b
--- /dev/null
+++ b/Zend/tests/clone/clone_with_004.phpt
@@ -0,0 +1,82 @@
+--TEST--
+Clone with evaluation order
+--FILE--
+<?php
+
+class Clazz {
+	public string $hooked = 'default' {
+		set (string $value) {
+			echo __FUNCTION__, PHP_EOL;
+
+			$this->hooked = strtoupper($value);
+		}
+	}
+
+	public string $maxLength {
+		set (string $value) {
+			echo __FUNCTION__, PHP_EOL;
+
+			if (strlen($value) > 5) {
+				throw new \Exception('Length exceeded');
+			}
+
+			$this->maxLength = $value;
+		}
+	}
+
+	public string $minLength {
+		set (string $value) {
+			echo __FUNCTION__, PHP_EOL;
+
+			if (strlen($value) < 5) {
+				throw new \Exception('Length unsufficient');
+			}
+
+			$this->minLength = $value;
+		}
+	}
+}
+
+$c = new Clazz();
+
+var_dump(clone($c, [ 'hooked' => 'updated' ]));
+echo PHP_EOL;
+var_dump(clone($c, [ 'hooked' => 'updated', 'maxLength' => 'abc', 'minLength' => 'abcdef' ]));
+echo PHP_EOL;
+var_dump(clone($c, [ 'minLength' => 'abcdef', 'hooked' => 'updated', 'maxLength' => 'abc' ]));
+
+?>
+--EXPECTF--
+$hooked::set
+object(Clazz)#%d (1) {
+  ["hooked"]=>
+  string(7) "UPDATED"
+  ["maxLength"]=>
+  uninitialized(string)
+  ["minLength"]=>
+  uninitialized(string)
+}
+
+$hooked::set
+$maxLength::set
+$minLength::set
+object(Clazz)#%d (3) {
+  ["hooked"]=>
+  string(7) "UPDATED"
+  ["maxLength"]=>
+  string(3) "abc"
+  ["minLength"]=>
+  string(6) "abcdef"
+}
+
+$minLength::set
+$hooked::set
+$maxLength::set
+object(Clazz)#%d (3) {
+  ["hooked"]=>
+  string(7) "UPDATED"
+  ["maxLength"]=>
+  string(3) "abc"
+  ["minLength"]=>
+  string(6) "abcdef"
+}
diff --git a/Zend/tests/clone/clone_with_005.phpt b/Zend/tests/clone/clone_with_005.phpt
new file mode 100644
index 0000000000000..40569c59192ad
--- /dev/null
+++ b/Zend/tests/clone/clone_with_005.phpt
@@ -0,0 +1,64 @@
+--TEST--
+Clone with error handling
+--FILE--
+<?php
+
+class Clazz {
+	public string $hooked = 'default' {
+		set (string $value) {
+			echo __FUNCTION__, PHP_EOL;
+
+			$this->hooked = strtoupper($value);
+		}
+	}
+
+	public string $maxLength {
+		set (string $value) {
+			echo __FUNCTION__, PHP_EOL;
+
+			if (strlen($value) > 5) {
+				throw new \Exception('Length exceeded');
+			}
+
+			$this->maxLength = $value;
+		}
+	}
+
+	public string $minLength {
+		set (string $value) {
+			echo __FUNCTION__, PHP_EOL;
+
+			if (strlen($value) < 5) {
+				throw new \Exception('Length insufficient');
+			}
+
+			$this->minLength = $value;
+		}
+	}
+}
+
+$c = new Clazz();
+
+try {
+	var_dump(clone($c, [ 'hooked' => 'updated', 'maxLength' => 'abcdef', 'minLength' => 'abc' ]));
+} catch (Throwable $e) {
+	echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+}
+
+echo PHP_EOL;
+
+try {
+	var_dump(clone($c, [ 'hooked' => 'updated', 'minLength' => 'abc', 'maxLength' => 'abcdef' ]));
+} catch (Throwable $e) {
+	echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECT--
+$hooked::set
+$maxLength::set
+Exception: Length exceeded
+
+$hooked::set
+$minLength::set
+Exception: Length insufficient
diff --git a/Zend/tests/clone/clone_with_006.phpt b/Zend/tests/clone/clone_with_006.phpt
new file mode 100644
index 0000000000000..7b0b8520b8a82
--- /dev/null
+++ b/Zend/tests/clone/clone_with_006.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Clone with error cases
+--FILE--
+<?php
+
+$x = new stdClass();
+
+try {
+	var_dump(clone($x, 1));
+} catch (Throwable $e) {
+	echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECT--
+TypeError: clone(): Argument #2 ($withProperties) must be of type array, int given
diff --git a/Zend/tests/clone/clone_with_007.phpt b/Zend/tests/clone/clone_with_007.phpt
new file mode 100644
index 0000000000000..08cefd7f8cbe3
--- /dev/null
+++ b/Zend/tests/clone/clone_with_007.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Clone with supports __clone
+--FILE--
+<?php
+
+class Clazz {
+	public function __construct(
+		public string $foo,
+		public string $bar,
+	) { }
+
+	public function __clone() {
+		$this->foo = 'foo updated in __clone';
+		$this->bar = 'bar updated in __clone';
+	}
+}
+
+$c = new Clazz('foo', 'bar');
+
+var_dump(clone($c, [ 'foo' => 'foo updated in clone-with' ]));
+
+?>
+--EXPECTF--
+object(Clazz)#%d (2) {
+  ["foo"]=>
+  string(25) "foo updated in clone-with"
+  ["bar"]=>
+  string(22) "bar updated in __clone"
+}
diff --git a/Zend/tests/clone/clone_with_008.phpt b/Zend/tests/clone/clone_with_008.phpt
new file mode 100644
index 0000000000000..aa2c639fb7f1c
--- /dev/null
+++ b/Zend/tests/clone/clone_with_008.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Clone with readonly
+--FILE--
+<?php
+
+readonly class Clazz {
+	public function __construct(
+		public public(set) string $a,
+		public public(set) string $b,
+	) { }
+
+	public function __clone() {
+		$this->b = '__clone';
+	}
+}
+
+$c = new Clazz('default', 'default');
+
+var_dump(clone($c, [ 'a' => "with" ]));
+
+try {
+	var_dump(clone($c, [ 'b' => "with" ]));
+} catch (Throwable $e) {
+	echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECTF--
+object(Clazz)#%d (2) {
+  ["a"]=>
+  string(4) "with"
+  ["b"]=>
+  string(7) "__clone"
+}
+object(Clazz)#%d (2) {
+  ["a"]=>
+  string(7) "default"
+  ["b"]=>
+  string(4) "with"
+}
diff --git a/Zend/tests/clone/clone_with_009.phpt b/Zend/tests/clone/clone_with_009.phpt
new file mode 100644
index 0000000000000..c6a7d2d18b982
--- /dev/null
+++ b/Zend/tests/clone/clone_with_009.phpt
@@ -0,0 +1,72 @@
+--TEST--
+Clone with lazy objects
+--FILE--
+<?php
+
+class C {
+    public $a = 1;
+
+    public function __construct() {
+    }
+}
+
+function test(string $name, object $obj) {
+    printf("# %s:\n", $name);
+
+    $reflector = new ReflectionClass($obj::class);
+    $clone = clone($obj, [ 'a' => 2 ]);
+
+    var_dump($reflector->isUninitializedLazyObject($obj));
+    var_dump($obj);
+    var_dump($reflector->isUninitializedLazyObject($clone));
+    var_dump($clone);
+}
+
+$reflector = new ReflectionClass(C::class);
+
+$obj = $reflector->newLazyGhost(function ($obj) {
+    var_dump("initializer");
+    $obj->__construct();
+});
+
+test('Ghost', $obj);
+
+$obj = $reflector->newLazyProxy(function ($obj) {
+    var_dump("initializer");
+    return new C();
+});
+
+test('Proxy', $obj);
+
+?>
+--EXPECTF--
+# Ghost:
+string(11) "initializer"
+bool(false)
+object(C)#%d (1) {
+  ["a"]=>
+  int(1)
+}
+bool(false)
+object(C)#%d (1) {
+  ["a"]=>
+  int(2)
+}
+# Proxy:
+string(11) "initializer"
+bool(false)
+lazy proxy object(C)#%d (1) {
+  ["instance"]=>
+  object(C)#%d (1) {
+    ["a"]=>
+    int(1)
+  }
+}
+bool(false)
+lazy proxy object(C)#%d (1) {
+  ["instance"]=>
+  object(C)#%d (1) {
+    ["a"]=>
+    int(2)
+  }
+}
diff --git a/Zend/tests/clone/clone_with_010.phpt b/Zend/tests/clone/clone_with_010.phpt
new file mode 100644
index 0000000000000..97afa737ab091
--- /dev/null
+++ b/Zend/tests/clone/clone_with_010.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Clone with native classes
+--FILE--
+<?php
+
+try {
+	var_dump(clone(new \Random\Engine\Secure(), [ 'with' => "something" ]));
+} catch (Throwable $e) {
+	echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+}
+
+try {
+	var_dump(clone(new \Random\Engine\Xoshiro256StarStar(), [ 'with' => "something" ]));
+} catch (Throwable $e) {
+	echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECT--
+Error: Trying to clone an uncloneable object of class Random\Engine\Secure
+Error: Trying to clone an object with updated properties that is not compatible Random\Engine\Xoshiro256StarStar
diff --git a/Zend/tests/clone/clone_with_011.phpt b/Zend/tests/clone/clone_with_011.phpt
new file mode 100644
index 0000000000000..5f8e99bb65f2f
--- /dev/null
+++ b/Zend/tests/clone/clone_with_011.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Clone with name mangling
+--FILE--
+<?php
+
+class Foo {
+	private string $bar = 'default';
+}
+
+try {
+	var_dump(clone(new Foo(), ["\0Foo\0bar" => 'updated']));
+} catch (Throwable $e) {
+	echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECT--
+Error: Cannot access property starting with "\0"
diff --git a/Zend/tests/magic_methods/bug73288.phpt b/Zend/tests/magic_methods/bug73288.phpt
index 52e8eedeaf013..09819f0853cca 100644
--- a/Zend/tests/magic_methods/bug73288.phpt
+++ b/Zend/tests/magic_methods/bug73288.phpt
@@ -28,7 +28,8 @@ test_clone();
 --EXPECTF--
 Fatal error: Uncaught Exception: No Cloneable in %sbug73288.php:%d
 Stack trace:
-#0 %s(%d): NoClone->__clone()
-#1 %s(%d): test_clone()
-#2 {main}
+#0 [internal function]: NoClone->__clone()
+#1 %s(%d): clone(Object(NoClone))
+#2 %s(%d): test_clone()
+#3 {main}
   thrown in %sbug73288.php on line %d
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index e0006e7d7275f..259481ebfb0e8 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -3641,6 +3641,7 @@ static void zend_disable_function(const char *function_name, size_t function_nam
 	if (UNEXPECTED(
 		(function_name_length == strlen("exit") && !memcmp(function_name, "exit", strlen("exit")))
 		|| (function_name_length == strlen("die") && !memcmp(function_name, "die", strlen("die")))
+		|| (function_name_length == strlen("clone") && !memcmp(function_name, "clone", strlen("clone")))
 	)) {
 		zend_error(E_WARNING, "Cannot disable function %s()", function_name);
 		return;
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c
index beecf51216a94..9b9652a865a07 100644
--- a/Zend/zend_ast.c
+++ b/Zend/zend_ast.c
@@ -2346,7 +2346,15 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
 			smart_str_appendc(str, '`');
 			break;
 		case ZEND_AST_CLONE:
-			PREFIX_OP("clone ", 270, 271);
+			smart_str_appends(str, "clone");
+			smart_str_appendc(str, '(');
+			zend_ast_export_ex(str, ast->child[0], 0, indent);
+			if (ast->child[1]) {
+				smart_str_appends(str, ", ");
+				zend_ast_export_ex(str, ast->child[1], 0, indent);
+			}
+			smart_str_appendc(str, ')');
+			break;
 		case ZEND_AST_PRINT:
 			PREFIX_OP("print ", 60, 61);
 		case ZEND_AST_INCLUDE_OR_EVAL:
diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h
index c82ca66c9f573..47469c5d2b2e4 100644
--- a/Zend/zend_ast.h
+++ b/Zend/zend_ast.h
@@ -89,7 +89,6 @@ enum _zend_ast_kind {
 	ZEND_AST_ISSET,
 	ZEND_AST_SILENCE,
 	ZEND_AST_SHELL_EXEC,
-	ZEND_AST_CLONE,
 	ZEND_AST_PRINT,
 	ZEND_AST_INCLUDE_OR_EVAL,
 	ZEND_AST_UNARY_OP,
@@ -155,6 +154,7 @@ enum _zend_ast_kind {
 	ZEND_AST_NAMED_ARG,
 	ZEND_AST_PARENT_PROPERTY_HOOK_CALL,
 	ZEND_AST_PIPE,
+	ZEND_AST_CLONE,
 
 	/* 3 child nodes */
 	ZEND_AST_METHOD_CALL = 3 << ZEND_AST_NUM_CHILDREN_SHIFT,
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 7a07ceadce2e2..75508ce89bd50 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -69,6 +69,63 @@ zend_result zend_startup_builtin_functions(void) /* {{{ */
 }
 /* }}} */
 
+ZEND_FUNCTION(clone)
+{
+	zend_object *zobj;
+	HashTable *with = NULL;
+
+	ZEND_PARSE_PARAMETERS_START(1, 2)
+		Z_PARAM_OBJ(zobj)
+		Z_PARAM_OPTIONAL
+		Z_PARAM_ARRAY_HT(with)
+	ZEND_PARSE_PARAMETERS_END();
+
+	zend_class_entry *scope = zend_get_executed_scope();
+
+	zend_class_entry *ce = zobj->ce;
+	zend_function *clone = ce->clone;
+
+	if (UNEXPECTED(zobj->handlers->clone_obj == NULL)) {
+		zend_throw_error(NULL, "Trying to clone an uncloneable object of class %s", ZSTR_VAL(ce->name));
+		RETURN_THROWS();
+	}
+
+	if (clone && !(clone->common.fn_flags & ZEND_ACC_PUBLIC)) {
+		if (clone->common.scope != scope) {
+			if (UNEXPECTED(clone->common.fn_flags & ZEND_ACC_PRIVATE)
+			 || UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) {
+				zend_throw_error(NULL, "Call to %s %s::__clone() from %s%s",
+					zend_visibility_string(clone->common.fn_flags), ZSTR_VAL(clone->common.scope->name),
+					scope ? "scope " : "global scope",
+					scope ? ZSTR_VAL(scope->name) : ""
+				);
+				RETURN_THROWS();
+			}
+		}
+	}
+
+	zend_object *cloned;
+	if (zobj->handlers->clone_obj_with) {
+		cloned = zobj->handlers->clone_obj_with(zobj, scope, with);
+	} else {
+		if (UNEXPECTED(with != NULL && zend_hash_num_elements(with) > 0)) {
+			zend_throw_error(NULL, "Trying to clone an object with updated properties that is not compatible %s", ZSTR_VAL(ce->name));
+			RETURN_THROWS();
+		}
+		cloned = zobj->handlers->clone_obj(zobj);
+	}
+	
+	if (EG(exception)) {
+		if (cloned) {
+			OBJ_RELEASE(cloned);
+		}
+
+		RETURN_THROWS();
+	}
+
+	RETURN_OBJ(cloned);
+}
+
 ZEND_FUNCTION(exit)
 {
 	zend_string *str = NULL;
diff --git a/Zend/zend_builtin_functions.stub.php b/Zend/zend_builtin_functions.stub.php
index 7f316835aea6b..ec1c31d994e2d 100644
--- a/Zend/zend_builtin_functions.stub.php
+++ b/Zend/zend_builtin_functions.stub.php
@@ -7,6 +7,8 @@ class stdClass
 {
 }
 
+function _clone(object $object, array $withProperties = []): object {}
+
 function exit(string|int $status = 0): never {}
 
 /** @alias exit */
diff --git a/Zend/zend_builtin_functions_arginfo.h b/Zend/zend_builtin_functions_arginfo.h
index 9498b8292f892..9d85ced893640 100644
--- a/Zend/zend_builtin_functions_arginfo.h
+++ b/Zend/zend_builtin_functions_arginfo.h
@@ -1,5 +1,10 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: a24761186f1ddf758e648b0a764826537cbd33b9 */
+ * Stub hash: 392169c2b4b974791e57c474be4ea2f8c9b58aae */
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_clone, 0, 1, IS_OBJECT, 0)
+	ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0)
+	ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, withProperties, IS_ARRAY, 0, "[]")
+ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_exit, 0, 0, IS_NEVER, 0)
 	ZEND_ARG_TYPE_MASK(0, status, MAY_BE_STRING|MAY_BE_LONG, "0")
@@ -243,6 +248,7 @@ static const zend_frameless_function_info frameless_function_infos_class_exists[
 	{ 0 },
 };
 
+ZEND_FUNCTION(clone);
 ZEND_FUNCTION(exit);
 ZEND_FUNCTION(zend_version);
 ZEND_FUNCTION(func_num_args);
@@ -306,6 +312,7 @@ ZEND_FUNCTION(gc_disable);
 ZEND_FUNCTION(gc_status);
 
 static const zend_function_entry ext_functions[] = {
+	ZEND_FE(clone, arginfo_clone)
 	ZEND_FE(exit, arginfo_exit)
 	ZEND_RAW_FENTRY("die", zif_exit, arginfo_die, 0, NULL, NULL)
 	ZEND_FE(zend_version, arginfo_zend_version)
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 2bc0cf7b703d9..ffd5d6c12e341 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -5404,7 +5404,14 @@ static void zend_compile_clone(znode *result, zend_ast *ast) /* {{{ */
 	znode obj_node;
 	zend_compile_expr(&obj_node, obj_ast);
 
-	zend_emit_op_tmp(result, ZEND_CLONE, &obj_node, NULL);
+	znode value_node;
+	if (ast->child[1]) {
+		zend_compile_expr(&value_node, ast->child[1]);
+	} else {
+		value_node.op_type = IS_UNUSED;
+	}
+
+	zend_emit_op_tmp(result, ZEND_CLONE, &obj_node, &value_node);
 }
 /* }}} */
 
diff --git a/Zend/zend_iterators.c b/Zend/zend_iterators.c
index f67033b11161c..64dbb0541a80d 100644
--- a/Zend/zend_iterators.c
+++ b/Zend/zend_iterators.c
@@ -31,6 +31,7 @@ static const zend_object_handlers iterator_object_handlers = {
 	iter_wrapper_free,
 	iter_wrapper_dtor,
 	NULL, /* clone_obj */
+	NULL, /* clone_obj_with */
 	NULL, /* prop read */
 	NULL, /* prop write */
 	NULL, /* read dim */
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index 816b8126cbf25..43058f2b159a5 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -287,7 +287,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
 %type <ast> enum_declaration_statement enum_backing_type enum_case enum_case_expr
 %type <ast> function_name non_empty_member_modifiers
 %type <ast> property_hook property_hook_list optional_property_hook_list hooked_property property_hook_body
-%type <ast> optional_parameter_list
+%type <ast> optional_parameter_list parens_less_argument_list non_empty_parens_less_argument_list
 
 %type <num> returns_ref function fn is_reference is_variadic property_modifiers property_hook_modifiers
 %type <num> method_modifiers class_const_modifiers member_modifier optional_cpp_modifiers
@@ -907,6 +907,22 @@ argument_list:
 	|	'(' T_ELLIPSIS ')' { $$ = zend_ast_create_fcc(); }
 ;
 
+parens_less_argument_list:
+		'(' ')'	{ $$ = zend_ast_create_list(0, ZEND_AST_ARG_LIST); }
+	|	'(' non_empty_parens_less_argument_list possible_comma ')' { $$ = $2; }
+	|	'(' T_ELLIPSIS ')' { $$ = zend_ast_create_fcc(); }
+;
+
+non_empty_parens_less_argument_list:
+		expr ',' argument
+			{ $$ = zend_ast_list_add(zend_ast_create_list(1, ZEND_AST_ARG_LIST, $1), $3); }
+	|	identifier ':' expr
+			{ $$ = zend_ast_create_list(1, ZEND_AST_ARG_LIST, zend_ast_create(ZEND_AST_NAMED_ARG, $1, $3)); }
+	|	T_ELLIPSIS expr	{ $$ = zend_ast_create_list(1, ZEND_AST_ARG_LIST, zend_ast_create(ZEND_AST_UNPACK, $2)); }
+	|	non_empty_parens_less_argument_list ',' argument
+			{ $$ = zend_ast_list_add($1, $3); }
+;
+
 non_empty_argument_list:
 		argument
 			{ $$ = zend_ast_create_list(1, ZEND_AST_ARG_LIST, $1); }
@@ -1228,7 +1244,16 @@ expr:
 			{ $$ = zend_ast_create(ZEND_AST_ASSIGN, $1, $3); }
 	|	variable '=' ampersand variable
 			{ $$ = zend_ast_create(ZEND_AST_ASSIGN_REF, $1, $4); }
-	|	T_CLONE expr { $$ = zend_ast_create(ZEND_AST_CLONE, $2); }
+	|	T_CLONE parens_less_argument_list {
+			zend_ast *name = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_CLONE));
+			name->attr = ZEND_NAME_FQ;
+			$$ = zend_ast_create(ZEND_AST_CALL, name, $2);
+		}
+	|	T_CLONE expr {
+			zend_ast *name = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_CLONE));
+			name->attr = ZEND_NAME_FQ;
+			$$ = zend_ast_create(ZEND_AST_CALL, name, zend_ast_create_list(1, ZEND_AST_ARG_LIST, $2));
+		}
 	|	variable T_PLUS_EQUAL expr
 			{ $$ = zend_ast_create_assign_op(ZEND_ADD, $1, $3); }
 	|	variable T_MINUS_EQUAL expr
diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c
index d1b950160e1cc..0300f078e48a5 100644
--- a/Zend/zend_lazy_objects.c
+++ b/Zend/zend_lazy_objects.c
@@ -709,7 +709,7 @@ ZEND_API HashTable *zend_lazy_object_get_properties(zend_object *object)
 
 /* Initialize object and clone it. For proxies, we clone both the proxy and its
  * real instance, and we don't call __clone() on the proxy. */
-zend_object *zend_lazy_object_clone(zend_object *old_obj)
+zend_object *zend_lazy_object_clone(zend_object *old_obj, zend_class_entry *scope, const HashTable *properties)
 {
 	ZEND_ASSERT(zend_object_is_lazy(old_obj));
 
@@ -724,7 +724,7 @@ zend_object *zend_lazy_object_clone(zend_object *old_obj)
 	}
 
 	if (!zend_object_is_lazy_proxy(old_obj)) {
-		return zend_objects_clone_obj(old_obj);
+		return zend_objects_clone_obj_with(old_obj, scope, properties);
 	}
 
 	zend_lazy_object_info *info = zend_lazy_object_get_info(old_obj);
@@ -748,7 +748,7 @@ zend_object *zend_lazy_object_clone(zend_object *old_obj)
 
 	zend_lazy_object_info *new_info = emalloc(sizeof(*info));
 	*new_info = *info;
-	new_info->u.instance = zend_objects_clone_obj(info->u.instance);
+	new_info->u.instance = zend_objects_clone_obj_with(info->u.instance, scope, properties);
 
 	zend_lazy_object_set_info(new_proxy, new_info);
 
diff --git a/Zend/zend_lazy_objects.h b/Zend/zend_lazy_objects.h
index 64f68d66360cd..f1850f0b97c34 100644
--- a/Zend/zend_lazy_objects.h
+++ b/Zend/zend_lazy_objects.h
@@ -71,7 +71,7 @@ zend_object *zend_lazy_object_get_instance(zend_object *obj);
 zend_lazy_object_flags_t zend_lazy_object_get_flags(zend_object *obj);
 void zend_lazy_object_del_info(zend_object *obj);
 ZEND_API HashTable *zend_lazy_object_get_properties(zend_object *object);
-zend_object *zend_lazy_object_clone(zend_object *old_obj);
+zend_object *zend_lazy_object_clone(zend_object *old_obj, zend_class_entry *scope, const HashTable *properties);
 HashTable *zend_lazy_object_debug_info(zend_object *object, int *is_temp);
 HashTable *zend_lazy_object_get_gc(zend_object *zobj, zval **table, int *n);
 bool zend_lazy_object_decr_lazy_props(zend_object *obj);
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index 7b804e7afe95a..5defe9689b89e 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -2543,6 +2543,7 @@ ZEND_API const zend_object_handlers std_object_handlers = {
 	zend_object_std_dtor,					/* free_obj */
 	zend_objects_destroy_object,			/* dtor_obj */
 	zend_objects_clone_obj,					/* clone_obj */
+	zend_objects_clone_obj_with,					/* clone_obj_with */
 
 	zend_std_read_property,					/* read_property */
 	zend_std_write_property,				/* write_property */
diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h
index 7e7d3df37a6ad..7b99f56454f18 100644
--- a/Zend/zend_object_handlers.h
+++ b/Zend/zend_object_handlers.h
@@ -180,6 +180,7 @@ typedef void (*zend_object_free_obj_t)(zend_object *object);
 typedef void (*zend_object_dtor_obj_t)(zend_object *object);
 
 typedef zend_object* (*zend_object_clone_obj_t)(zend_object *object);
+typedef zend_object* (*zend_object_clone_obj_with_t)(zend_object *object, zend_class_entry *scope, const HashTable *properties);
 
 /* Get class name for display in var_dump and other debugging functions.
  * Must be defined and must return a non-NULL value. */
@@ -209,6 +210,7 @@ struct _zend_object_handlers {
 	zend_object_free_obj_t					free_obj;             /* required */
 	zend_object_dtor_obj_t					dtor_obj;             /* required */
 	zend_object_clone_obj_t					clone_obj;            /* optional */
+	zend_object_clone_obj_with_t					clone_obj_with;            /* optional */
 	zend_object_read_property_t				read_property;        /* required */
 	zend_object_write_property_t			write_property;       /* required */
 	zend_object_read_dimension_t			read_dimension;       /* required */
diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c
index fd0e97c5f4131..db3f09c5adee7 100644
--- a/Zend/zend_objects.c
+++ b/Zend/zend_objects.c
@@ -213,9 +213,9 @@ ZEND_API zend_object* ZEND_FASTCALL zend_objects_new(zend_class_entry *ce)
 	return object;
 }
 
-ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, zend_object *old_object)
+ZEND_API void ZEND_FASTCALL zend_objects_clone_members_ex(zend_object *new_object, zend_object *old_object, zend_class_entry *scope, const HashTable *properties)
 {
-	bool has_clone_method = old_object->ce->clone != NULL;
+	bool has_clone_method = old_object->ce->clone != NULL || properties != NULL;
 
 	if (old_object->ce->default_properties_count) {
 		zval *src = old_object->properties_table;
@@ -289,7 +289,43 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object,
 
 	if (has_clone_method) {
 		GC_ADDREF(new_object);
-		zend_call_known_instance_method_with_0_params(new_object->ce->clone, new_object, NULL);
+		if (old_object->ce->clone) {
+			zend_call_known_instance_method_with_0_params(new_object->ce->clone, new_object, NULL);
+		}
+
+		if (EXPECTED(!EG(exception)) && properties != NULL) {
+			/* Unlock readonly properties once more. */
+			if (ZEND_CLASS_HAS_READONLY_PROPS(new_object->ce) && old_object->ce->clone) {
+				for (uint32_t i = 0; i < new_object->ce->default_properties_count; i++) {
+					zval* prop = OBJ_PROP_NUM(new_object, i);
+					Z_PROP_FLAG_P(prop) |= IS_PROP_REINITABLE;
+				}
+			}
+
+			zend_class_entry *old_scope = EG(fake_scope);
+
+			EG(fake_scope) = scope;
+
+			zend_ulong num_key;
+			zend_string *key;
+			zval *val;
+			ZEND_HASH_FOREACH_KEY_VAL(properties, num_key, key, val) {
+				if (UNEXPECTED(key == NULL)) {
+					key = zend_long_to_str(num_key);
+					new_object->handlers->write_property(new_object, key, val, NULL);
+					zend_string_release_ex(key, false);
+				} else {
+					new_object->handlers->write_property(new_object, key, val, NULL);
+				}
+	
+				if (UNEXPECTED(EG(exception))) {
+					break;
+				}
+			} ZEND_HASH_FOREACH_END();
+
+			EG(fake_scope) = old_scope;
+		}
+
 
 		if (ZEND_CLASS_HAS_READONLY_PROPS(new_object->ce)) {
 			for (uint32_t i = 0; i < new_object->ce->default_properties_count; i++) {
@@ -303,12 +339,33 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object,
 	}
 }
 
-ZEND_API zend_object *zend_objects_clone_obj(zend_object *old_object)
+ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, zend_object *old_object)
+{
+	ZEND_ASSERT(old_object->ce == new_object->ce);
+
+	zend_objects_clone_members_ex(new_object, old_object, old_object->ce, NULL);
+}
+
+ZEND_API zend_object *zend_objects_clone_obj_with(zend_object *old_object, zend_class_entry *scope, const HashTable *properties)
 {
 	zend_object *new_object;
 
+	/* Compatibility with code that only overrides clone_obj. */
+	if (UNEXPECTED(old_object->handlers->clone_obj != zend_objects_clone_obj)) {
+		if (!old_object->handlers->clone_obj) {
+			zend_throw_error(NULL, "Trying to clone an uncloneable object of class %s", ZSTR_VAL(old_object->ce->name));
+			return NULL;
+		}
+		if (properties && zend_hash_num_elements(properties) > 0) {
+			zend_throw_error(NULL, "Trying to clone an object with updated properties that is not compatible %s", ZSTR_VAL(old_object->ce->name));
+			return NULL;
+		} else {
+			return old_object->handlers->clone_obj(old_object);
+		}
+	}
+
 	if (UNEXPECTED(zend_object_is_lazy(old_object))) {
-		return zend_lazy_object_clone(old_object);
+		return zend_lazy_object_clone(old_object, scope, properties);
 	}
 
 	/* assume that create isn't overwritten, so when clone depends on the
@@ -325,7 +382,12 @@ ZEND_API zend_object *zend_objects_clone_obj(zend_object *old_object)
 		} while (p != end);
 	}
 
-	zend_objects_clone_members(new_object, old_object);
+	zend_objects_clone_members_ex(new_object, old_object, scope, properties);
 
 	return new_object;
 }
+
+ZEND_API zend_object *zend_objects_clone_obj(zend_object *old_object)
+{
+	return zend_objects_clone_obj_with(old_object, old_object->ce, NULL);
+}
diff --git a/Zend/zend_objects.h b/Zend/zend_objects.h
index 41e3bcd9594b1..9aea4a6245b36 100644
--- a/Zend/zend_objects.h
+++ b/Zend/zend_objects.h
@@ -30,6 +30,7 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object,
 ZEND_API void zend_object_std_dtor(zend_object *object);
 ZEND_API void zend_objects_destroy_object(zend_object *object);
 ZEND_API zend_object *zend_objects_clone_obj(zend_object *object);
+ZEND_API zend_object *zend_objects_clone_obj_with(zend_object *object, zend_class_entry *scope, const HashTable *properties);
 
 void zend_object_dtor_dynamic_properties(zend_object *object);
 void zend_object_dtor_property(zend_object *object, zval *p);
diff --git a/Zend/zend_string.h b/Zend/zend_string.h
index 0b2a484016ec3..f60e4dec4e71f 100644
--- a/Zend/zend_string.h
+++ b/Zend/zend_string.h
@@ -575,6 +575,7 @@ EMPTY_SWITCH_DEFAULT_CASE()
 	_(ZEND_STR_UNKNOWN,                "unknown") \
 	_(ZEND_STR_UNKNOWN_CAPITALIZED,    "Unknown") \
 	_(ZEND_STR_EXIT,                   "exit") \
+	_(ZEND_STR_CLONE,                  "clone") \
 	_(ZEND_STR_EVAL,                   "eval") \
 	_(ZEND_STR_INCLUDE,                "include") \
 	_(ZEND_STR_REQUIRE,                "require") \
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 617e114dd05db..6b7db9480cc74 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -6001,7 +6001,6 @@ ZEND_VM_COLD_CONST_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY)
 	zend_object *zobj;
 	zend_class_entry *ce, *scope;
 	zend_function *clone;
-	zend_object_clone_obj_t clone_call;
 
 	SAVE_OPLINE();
 	obj = GET_OP1_OBJ_ZVAL_PTR_UNDEF(BP_VAR_R);
@@ -6022,8 +6021,9 @@ ZEND_VM_COLD_CONST_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY)
 					HANDLE_EXCEPTION();
 				}
 			}
-			zend_throw_error(NULL, "__clone method called on non-object");
+			zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj));
 			FREE_OP1();
+			FREE_OP2();
 			HANDLE_EXCEPTION();
 		}
 	} while (0);
@@ -6031,10 +6031,10 @@ ZEND_VM_COLD_CONST_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY)
 	zobj = Z_OBJ_P(obj);
 	ce = zobj->ce;
 	clone = ce->clone;
-	clone_call = zobj->handlers->clone_obj;
-	if (UNEXPECTED(clone_call == NULL)) {
+	if (UNEXPECTED(zobj->handlers->clone_obj == NULL)) {
 		zend_throw_error(NULL, "Trying to clone an uncloneable object of class %s", ZSTR_VAL(ce->name));
 		FREE_OP1();
+		FREE_OP2();
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
 		HANDLE_EXCEPTION();
 	}
@@ -6046,15 +6046,55 @@ ZEND_VM_COLD_CONST_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY)
 			 || UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) {
 				zend_wrong_clone_call(clone, scope);
 				FREE_OP1();
+				FREE_OP2();
 				ZVAL_UNDEF(EX_VAR(opline->result.var));
 				HANDLE_EXCEPTION();
 			}
 		}
 	}
 
-	ZVAL_OBJ(EX_VAR(opline->result.var), clone_call(zobj));
+	zend_object *cloned;
+	if (zobj->handlers->clone_obj_with) {
+		scope = EX(func)->op_array.scope;
+		if (OP2_TYPE != IS_UNUSED) {
+			zval *properties = GET_OP2_ZVAL_PTR(BP_VAR_R);
+			if (Z_TYPE_P(properties) != IS_ARRAY) {
+				zend_type_error("clone(): Argument #2 ($withProperties) must be of type array, %s given", zend_zval_value_name(obj));
+				FREE_OP1();
+				FREE_OP2();
+				ZVAL_UNDEF(EX_VAR(opline->result.var));
+				HANDLE_EXCEPTION();
+			}
+			
+			cloned = zobj->handlers->clone_obj_with(zobj, scope, Z_ARR_P(properties));
+		} else {
+			cloned = zobj->handlers->clone_obj_with(zobj, scope, NULL);
+		}
+
+		if (UNEXPECTED(EG(exception))) {
+			if (cloned) {
+				OBJ_RELEASE(cloned);
+			}
+			FREE_OP1();
+			FREE_OP2();
+			ZVAL_UNDEF(EX_VAR(opline->result.var));
+			HANDLE_EXCEPTION();
+		}
+	} else {
+		if (OP2_TYPE != IS_UNUSED) {
+			zend_throw_error(NULL, "Trying to clone an object with updated properties that is not compatible %s", ZSTR_VAL(ce->name));
+			FREE_OP1();
+			FREE_OP2();
+			ZVAL_UNDEF(EX_VAR(opline->result.var));
+			HANDLE_EXCEPTION();
+		}
+
+		cloned = zobj->handlers->clone_obj(zobj);
+	}
 
+	ZVAL_OBJ(EX_VAR(opline->result.var), cloned);
 	FREE_OP1();
+	FREE_OP2();
 	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 791e4b4e88437..c77154aae0b0c 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -5175,7 +5175,6 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CONST_
 	zend_object *zobj;
 	zend_class_entry *ce, *scope;
 	zend_function *clone;
-	zend_object_clone_obj_t clone_call;
 
 	SAVE_OPLINE();
 	obj = RT_CONSTANT(opline, opline->op1);
@@ -5196,8 +5195,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CONST_
 					HANDLE_EXCEPTION();
 				}
 			}
-			zend_throw_error(NULL, "__clone method called on non-object");
+			zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj));
 
+			FREE_OP(opline->op2_type, opline->op2.var);
 			HANDLE_EXCEPTION();
 		}
 	} while (0);
@@ -5205,10 +5205,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CONST_
 	zobj = Z_OBJ_P(obj);
 	ce = zobj->ce;
 	clone = ce->clone;
-	clone_call = zobj->handlers->clone_obj;
-	if (UNEXPECTED(clone_call == NULL)) {
+	if (UNEXPECTED(zobj->handlers->clone_obj == NULL)) {
 		zend_throw_error(NULL, "Trying to clone an uncloneable object of class %s", ZSTR_VAL(ce->name));
 
+		FREE_OP(opline->op2_type, opline->op2.var);
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
 		HANDLE_EXCEPTION();
 	}
@@ -5220,14 +5220,55 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CONST_
 			 || UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) {
 				zend_wrong_clone_call(clone, scope);
 
+				FREE_OP(opline->op2_type, opline->op2.var);
+				ZVAL_UNDEF(EX_VAR(opline->result.var));
+				HANDLE_EXCEPTION();
+			}
+		}
+	}
+
+	zend_object *cloned;
+	if (zobj->handlers->clone_obj_with) {
+		scope = EX(func)->op_array.scope;
+		if (opline->op2_type != IS_UNUSED) {
+			zval *properties = get_zval_ptr(opline->op2_type, opline->op2, BP_VAR_R);
+			if (Z_TYPE_P(properties) != IS_ARRAY) {
+				zend_type_error("clone(): Argument #2 ($withProperties) must be of type array, %s given", zend_zval_value_name(obj));
+
+				FREE_OP(opline->op2_type, opline->op2.var);
 				ZVAL_UNDEF(EX_VAR(opline->result.var));
 				HANDLE_EXCEPTION();
 			}
+
+			cloned = zobj->handlers->clone_obj_with(zobj, scope, Z_ARR_P(properties));
+		} else {
+			cloned = zobj->handlers->clone_obj_with(zobj, scope, NULL);
+		}
+
+		if (UNEXPECTED(EG(exception))) {
+			if (cloned) {
+				OBJ_RELEASE(cloned);
+			}
+
+			FREE_OP(opline->op2_type, opline->op2.var);
+			ZVAL_UNDEF(EX_VAR(opline->result.var));
+			HANDLE_EXCEPTION();
+		}
+	} else {
+		if (opline->op2_type != IS_UNUSED) {
+			zend_throw_error(NULL, "Trying to clone an object with updated properties that is not compatible %s", ZSTR_VAL(ce->name));
+
+			FREE_OP(opline->op2_type, opline->op2.var);
+			ZVAL_UNDEF(EX_VAR(opline->result.var));
+			HANDLE_EXCEPTION();
 		}
+
+		cloned = zobj->handlers->clone_obj(zobj);
 	}
 
-	ZVAL_OBJ(EX_VAR(opline->result.var), clone_call(zobj));
+	ZVAL_OBJ(EX_VAR(opline->result.var), cloned);
 
+	FREE_OP(opline->op2_type, opline->op2.var);
 	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
@@ -15423,7 +15464,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_TMPVAR_HANDLER(ZEND
 	zend_object *zobj;
 	zend_class_entry *ce, *scope;
 	zend_function *clone;
-	zend_object_clone_obj_t clone_call;
 
 	SAVE_OPLINE();
 	obj = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC);
@@ -15444,8 +15484,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_TMPVAR_HANDLER(ZEND
 					HANDLE_EXCEPTION();
 				}
 			}
-			zend_throw_error(NULL, "__clone method called on non-object");
+			zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj));
 			zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
+			FREE_OP(opline->op2_type, opline->op2.var);
 			HANDLE_EXCEPTION();
 		}
 	} while (0);
@@ -15453,10 +15494,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_TMPVAR_HANDLER(ZEND
 	zobj = Z_OBJ_P(obj);
 	ce = zobj->ce;
 	clone = ce->clone;
-	clone_call = zobj->handlers->clone_obj;
-	if (UNEXPECTED(clone_call == NULL)) {
+	if (UNEXPECTED(zobj->handlers->clone_obj == NULL)) {
 		zend_throw_error(NULL, "Trying to clone an uncloneable object of class %s", ZSTR_VAL(ce->name));
 		zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
+		FREE_OP(opline->op2_type, opline->op2.var);
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
 		HANDLE_EXCEPTION();
 	}
@@ -15468,15 +15509,55 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_TMPVAR_HANDLER(ZEND
 			 || UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) {
 				zend_wrong_clone_call(clone, scope);
 				zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
+				FREE_OP(opline->op2_type, opline->op2.var);
 				ZVAL_UNDEF(EX_VAR(opline->result.var));
 				HANDLE_EXCEPTION();
 			}
 		}
 	}
 
-	ZVAL_OBJ(EX_VAR(opline->result.var), clone_call(zobj));
+	zend_object *cloned;
+	if (zobj->handlers->clone_obj_with) {
+		scope = EX(func)->op_array.scope;
+		if (opline->op2_type != IS_UNUSED) {
+			zval *properties = get_zval_ptr(opline->op2_type, opline->op2, BP_VAR_R);
+			if (Z_TYPE_P(properties) != IS_ARRAY) {
+				zend_type_error("clone(): Argument #2 ($withProperties) must be of type array, %s given", zend_zval_value_name(obj));
+				zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
+				FREE_OP(opline->op2_type, opline->op2.var);
+				ZVAL_UNDEF(EX_VAR(opline->result.var));
+				HANDLE_EXCEPTION();
+			}
+
+			cloned = zobj->handlers->clone_obj_with(zobj, scope, Z_ARR_P(properties));
+		} else {
+			cloned = zobj->handlers->clone_obj_with(zobj, scope, NULL);
+		}
+
+		if (UNEXPECTED(EG(exception))) {
+			if (cloned) {
+				OBJ_RELEASE(cloned);
+			}
+			zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
+			FREE_OP(opline->op2_type, opline->op2.var);
+			ZVAL_UNDEF(EX_VAR(opline->result.var));
+			HANDLE_EXCEPTION();
+		}
+	} else {
+		if (opline->op2_type != IS_UNUSED) {
+			zend_throw_error(NULL, "Trying to clone an object with updated properties that is not compatible %s", ZSTR_VAL(ce->name));
+			zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
+			FREE_OP(opline->op2_type, opline->op2.var);
+			ZVAL_UNDEF(EX_VAR(opline->result.var));
+			HANDLE_EXCEPTION();
+		}
+
+		cloned = zobj->handlers->clone_obj(zobj);
+	}
 
+	ZVAL_OBJ(EX_VAR(opline->result.var), cloned);
 	zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
+	FREE_OP(opline->op2_type, opline->op2.var);
 	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
@@ -33518,7 +33599,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND
 	zend_object *zobj;
 	zend_class_entry *ce, *scope;
 	zend_function *clone;
-	zend_object_clone_obj_t clone_call;
 
 	SAVE_OPLINE();
 	obj = &EX(This);
@@ -33539,8 +33619,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND
 					HANDLE_EXCEPTION();
 				}
 			}
-			zend_throw_error(NULL, "__clone method called on non-object");
+			zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj));
 
+			FREE_OP(opline->op2_type, opline->op2.var);
 			HANDLE_EXCEPTION();
 		}
 	} while (0);
@@ -33548,10 +33629,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND
 	zobj = Z_OBJ_P(obj);
 	ce = zobj->ce;
 	clone = ce->clone;
-	clone_call = zobj->handlers->clone_obj;
-	if (UNEXPECTED(clone_call == NULL)) {
+	if (UNEXPECTED(zobj->handlers->clone_obj == NULL)) {
 		zend_throw_error(NULL, "Trying to clone an uncloneable object of class %s", ZSTR_VAL(ce->name));
 
+		FREE_OP(opline->op2_type, opline->op2.var);
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
 		HANDLE_EXCEPTION();
 	}
@@ -33563,14 +33644,55 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND
 			 || UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) {
 				zend_wrong_clone_call(clone, scope);
 
+				FREE_OP(opline->op2_type, opline->op2.var);
+				ZVAL_UNDEF(EX_VAR(opline->result.var));
+				HANDLE_EXCEPTION();
+			}
+		}
+	}
+
+	zend_object *cloned;
+	if (zobj->handlers->clone_obj_with) {
+		scope = EX(func)->op_array.scope;
+		if (opline->op2_type != IS_UNUSED) {
+			zval *properties = get_zval_ptr(opline->op2_type, opline->op2, BP_VAR_R);
+			if (Z_TYPE_P(properties) != IS_ARRAY) {
+				zend_type_error("clone(): Argument #2 ($withProperties) must be of type array, %s given", zend_zval_value_name(obj));
+
+				FREE_OP(opline->op2_type, opline->op2.var);
 				ZVAL_UNDEF(EX_VAR(opline->result.var));
 				HANDLE_EXCEPTION();
 			}
+
+			cloned = zobj->handlers->clone_obj_with(zobj, scope, Z_ARR_P(properties));
+		} else {
+			cloned = zobj->handlers->clone_obj_with(zobj, scope, NULL);
+		}
+
+		if (UNEXPECTED(EG(exception))) {
+			if (cloned) {
+				OBJ_RELEASE(cloned);
+			}
+
+			FREE_OP(opline->op2_type, opline->op2.var);
+			ZVAL_UNDEF(EX_VAR(opline->result.var));
+			HANDLE_EXCEPTION();
+		}
+	} else {
+		if (opline->op2_type != IS_UNUSED) {
+			zend_throw_error(NULL, "Trying to clone an object with updated properties that is not compatible %s", ZSTR_VAL(ce->name));
+
+			FREE_OP(opline->op2_type, opline->op2.var);
+			ZVAL_UNDEF(EX_VAR(opline->result.var));
+			HANDLE_EXCEPTION();
 		}
+
+		cloned = zobj->handlers->clone_obj(zobj);
 	}
 
-	ZVAL_OBJ(EX_VAR(opline->result.var), clone_call(zobj));
+	ZVAL_OBJ(EX_VAR(opline->result.var), cloned);
 
+	FREE_OP(opline->op2_type, opline->op2.var);
 	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
@@ -41037,7 +41159,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPC
 	zend_object *zobj;
 	zend_class_entry *ce, *scope;
 	zend_function *clone;
-	zend_object_clone_obj_t clone_call;
 
 	SAVE_OPLINE();
 	obj = EX_VAR(opline->op1.var);
@@ -41058,8 +41179,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPC
 					HANDLE_EXCEPTION();
 				}
 			}
-			zend_throw_error(NULL, "__clone method called on non-object");
+			zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj));
 
+			FREE_OP(opline->op2_type, opline->op2.var);
 			HANDLE_EXCEPTION();
 		}
 	} while (0);
@@ -41067,10 +41189,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPC
 	zobj = Z_OBJ_P(obj);
 	ce = zobj->ce;
 	clone = ce->clone;
-	clone_call = zobj->handlers->clone_obj;
-	if (UNEXPECTED(clone_call == NULL)) {
+	if (UNEXPECTED(zobj->handlers->clone_obj == NULL)) {
 		zend_throw_error(NULL, "Trying to clone an uncloneable object of class %s", ZSTR_VAL(ce->name));
 
+		FREE_OP(opline->op2_type, opline->op2.var);
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
 		HANDLE_EXCEPTION();
 	}
@@ -41082,14 +41204,55 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPC
 			 || UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) {
 				zend_wrong_clone_call(clone, scope);
 
+				FREE_OP(opline->op2_type, opline->op2.var);
 				ZVAL_UNDEF(EX_VAR(opline->result.var));
 				HANDLE_EXCEPTION();
 			}
 		}
 	}
 
-	ZVAL_OBJ(EX_VAR(opline->result.var), clone_call(zobj));
+	zend_object *cloned;
+	if (zobj->handlers->clone_obj_with) {
+		scope = EX(func)->op_array.scope;
+		if (opline->op2_type != IS_UNUSED) {
+			zval *properties = get_zval_ptr(opline->op2_type, opline->op2, BP_VAR_R);
+			if (Z_TYPE_P(properties) != IS_ARRAY) {
+				zend_type_error("clone(): Argument #2 ($withProperties) must be of type array, %s given", zend_zval_value_name(obj));
+
+				FREE_OP(opline->op2_type, opline->op2.var);
+				ZVAL_UNDEF(EX_VAR(opline->result.var));
+				HANDLE_EXCEPTION();
+			}
+
+			cloned = zobj->handlers->clone_obj_with(zobj, scope, Z_ARR_P(properties));
+		} else {
+			cloned = zobj->handlers->clone_obj_with(zobj, scope, NULL);
+		}
+
+		if (UNEXPECTED(EG(exception))) {
+			if (cloned) {
+				OBJ_RELEASE(cloned);
+			}
 
+			FREE_OP(opline->op2_type, opline->op2.var);
+			ZVAL_UNDEF(EX_VAR(opline->result.var));
+			HANDLE_EXCEPTION();
+		}
+	} else {
+		if (opline->op2_type != IS_UNUSED) {
+			zend_throw_error(NULL, "Trying to clone an object with updated properties that is not compatible %s", ZSTR_VAL(ce->name));
+
+			FREE_OP(opline->op2_type, opline->op2.var);
+			ZVAL_UNDEF(EX_VAR(opline->result.var));
+			HANDLE_EXCEPTION();
+		}
+
+		cloned = zobj->handlers->clone_obj(zobj);
+	}
+
+	ZVAL_OBJ(EX_VAR(opline->result.var), cloned);
+
+	FREE_OP(opline->op2_type, opline->op2.var);
 	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
diff --git a/build/gen_stub.php b/build/gen_stub.php
index ff86106e8a2a4..ea2c1ad58c3e8 100755
--- a/build/gen_stub.php
+++ b/build/gen_stub.php
@@ -1009,6 +1009,9 @@ class FunctionName implements FunctionOrMethodName {
     private /* readonly */ Name $name;
 
     public function __construct(Name $name) {
+        if ($name->name === '_clone') {
+            $name = new Name('clone', $name->getAttributes());
+        }
         $this->name = $name;
     }
 
@@ -3057,6 +3060,7 @@ class PropertyInfo extends VariableLike
         "parent" => "ZEND_STR_PARENT",
         "username" => "ZEND_STR_USERNAME",
         "password" => "ZEND_STR_PASSWORD",
+        "clone" => "ZEND_STR_CLONE",
     ];
 
     /**
diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c
index af980b7b86f2a..638fc5d8a3ae6 100644
--- a/ext/com_dotnet/com_handlers.c
+++ b/ext/com_dotnet/com_handlers.c
@@ -514,6 +514,7 @@ zend_object_handlers php_com_object_handlers = {
 	php_com_object_free_storage,
 	zend_objects_destroy_object,
 	php_com_object_clone,
+	NULL, /* clone_with */
 	com_property_read,
 	com_property_write,
 	com_read_dimension,
diff --git a/ext/com_dotnet/com_saproxy.c b/ext/com_dotnet/com_saproxy.c
index ea0e9e47a13d9..ec79faa30a32b 100644
--- a/ext/com_dotnet/com_saproxy.c
+++ b/ext/com_dotnet/com_saproxy.c
@@ -402,6 +402,7 @@ zend_object_handlers php_com_saproxy_handlers = {
 	saproxy_free_storage,
 	zend_objects_destroy_object,
 	saproxy_clone,
+	NULL, /* clone_with */
 	saproxy_property_read,
 	saproxy_property_write,
 	saproxy_read_dimension,