Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.5.0alpha3

- Core:
. Add clone-with support to the clone() function. (timwolla, edorian)
. Fix support for non-userland stream notifiers. (timwolla)

- Curl:
. Add support for CURLINFO_CONN_ID in curl_getinfo() (thecaliskan)
. Add support for CURLINFO_QUEUE_TIME_T in curl_getinfo() (thecaliskan)
Expand Down
3 changes: 2 additions & 1 deletion UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,8 @@ PHP 8.5 UPGRADE NOTES
. get_exception_handler() allows retrieving the current user-defined exception
handler function.
RFC: https://wiki.php.net/rfc/get-error-exception-handler
. The clone language construct is now a function.
. The clone language construct is now a function and supports reassigning
(readonly) properties during cloning via the new $withProperties parameter.
RFC: https://wiki.php.net/rfc/clone_with_v2

- Curl:
Expand Down
5 changes: 5 additions & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ PHP 8.5 INTERNALS UPGRADE NOTES
the user side when requiring libphp.so, by using dlmopen with LM_ID_NEWLM
instead of dlopen.
RTLD_DEEPBIND is still enabled when the Apache SAPI is in use.
. The ptr field of the php_stream_notifier struct is now a void* instead
of a zval. If the zval was used to store IS_PTR values only, the
extra layer of indirection can be removed. In other cases a zval can
be heap-allocated and stored in the pointer as a minimal change to keep
compatibility.

- Zend
. Added zend_safe_assign_to_variable_noref() function to safely assign
Expand Down
71 changes: 71 additions & 0 deletions Zend/tests/clone/clone_with_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
--TEST--
Clone with basic
--FILE--
<?php

class Dummy { }

$x = new stdClass();

$foo = 'FOO';
$bar = new Dummy();
$array = [
'baz' => 'BAZ',
'array' => [1, 2, 3],
];

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"
}
114 changes: 114 additions & 0 deletions Zend/tests/clone/clone_with_002.phpt
Original file line number Diff line number Diff line change
@@ -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
23 changes: 23 additions & 0 deletions Zend/tests/clone/clone_with_003.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
Clone with supports property hooks
--FILE--
<?php

class Clazz {
public string $hooked = 'default' {
set {
$this->hooked = strtoupper($value);
}
}
}

$c = new Clazz();

var_dump(clone($c, [ 'hooked' => 'updated' ]));

?>
--EXPECTF--
object(Clazz)#%d (1) {
["hooked"]=>
string(7) "UPDATED"
}
82 changes: 82 additions & 0 deletions Zend/tests/clone/clone_with_004.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
--TEST--
Clone with evaluation order
--FILE--
<?php

class Clazz {
public string $hooked = 'default' {
set {
echo __FUNCTION__, PHP_EOL;

$this->hooked = strtoupper($value);
}
}

public string $maxLength {
set {
echo __FUNCTION__, PHP_EOL;

if (strlen($value) > 5) {
throw new \Exception('Length exceeded');
}

$this->maxLength = $value;
}
}

public string $minLength {
set {
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"
}
64 changes: 64 additions & 0 deletions Zend/tests/clone/clone_with_005.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
--TEST--
Clone with error handling
--FILE--
<?php

class Clazz {
public string $hooked = 'default' {
set {
echo __FUNCTION__, PHP_EOL;

$this->hooked = strtoupper($value);
}
}

public string $maxLength {
set {
echo __FUNCTION__, PHP_EOL;

if (strlen($value) > 5) {
throw new \Exception('Length exceeded');
}

$this->maxLength = $value;
}
}

public string $minLength {
set {
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
Loading