Hi
Clarifying on the technical questions.
Am 2025-05-26 16:37, schrieb Nicolas Grekas:
I think the RFC is missing a few bits to be complete:
- making "clone" a function means suddenly a "use clone;" or a "\clone" is
going to be needed to not get a perf hit, isn't it? But since $y = clone
$x; is still going to be valid, how will this be handled? The RFC could
give some more hints on the topic.
The implementation of making clone a function matches that of making exit()
a function in PHP 8.4 (https://wiki.php.net/rfc/exit-as-function). Specifically, clone
will remain a keyword and any use of a bare clone
will compile to a fully-qualified call to the clone function, as if you would have written \clone()
. For the same reason it will remain impossible to define a clone()
function within a namespace. It will also be disallowed to use disable_functions=clone
(the same as with exit and die).
That clone()
will become a function should be considered an implementation detail. You might start seeing a clone()
frame in your stack traces, within assert(false && clone($foo))
the \clone()
call will be fully-qualified in the error message output and error messages might slightly change (e.g. when passing a non-object to clone). Other than that, it should not be noticeable. Perhaps even the ZEND_CLONE opcode will remain when using clone with a single-parameter (this is similarly to the other optimization of “special functions”, such as count() or sprintf()).
I have made the following changes to the RFC that should hopefully clarify things: https://wiki.php.net/rfc/clone_with_v2?do=diff&rev2%5B0%5D=1748270099&rev2%5B1%5D=1748272162&difftype=sidebyside
- writing code with a wide range of supported PHP versions means we'll
start using construct such as:
if (PHP_VERSION_ID>=80500) {
$b = 'clone'($a, [...]); // note 'clone' is a string here, so that the
line is valid syntax on PHP <= 8.4
else {
// another code path for PHP 8.4
}
That's of course because "use clone", "\clone" or "clone($foo)" is invalid
PHP syntax currently.
Only use function clone;
is currently invalid syntax (and it will remain invalid syntax, similarly to use function exit;
). clone($a)
currently is a perfectly valid cloning statement (with redundant parentheses) and \clone($a)
is a valid call to a function called clone
that does not exist: https://3v4l.org/VB3j1
But as I said above, it is not necessary to change any existing code. The RFC is clear on that: There are no backwards incompatible changes regarding the usage. When finalizing the implementation, I'll make sure to run some benchmarks to determine whether or not keeping the OPcode is worth it for the “non-with” case, or whether making clone a “frameless” function would bring any benefit. But making sure it runs fast is the job of the engine, not the job of the PHP developer and generally speaking performance characteristics can change even without RFCs.
It could make sense to tell about this and show an example like this one in
the RFC.
Given that your question appears to be based on a misunderstanding, I believe adding such an example to the RFC is not useful.
- what if one gives a mangled property in the array? clone($foo,
["\0Foo\0bar" => 123])
It could be useful to write something about this case and/or at least have
a test case that shows how this should behave.
As the RFC specifies, clone-with behaves exactly like regular property assignments. This means your example behaves like `$foo->{"\0Foo\0bar"} = 123;` and thus will throw “Error: Cannot access property starting with "\0"”. I have added a test to the implementation [1]. Adding that to the RFC text itself is probably not useful to the average reader, since this is not something they will encounter.
Best regards
Tim Düsterhus
[1] https://github.com/TimWolla/php-src/pull/6/commits/6f55e142e55af013bed0f31d7dc1633ef8201bff