Skip to content

PHP 8.4 classList works not correctly if copy HTMLElement by clone keyword. #18744

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
asika32764 opened this issue Jun 3, 2025 · 1 comment
Closed

Comments

@asika32764
Copy link

asika32764 commented Jun 3, 2025

Description

The following code:

<?php
$doc = \Dom\HTMLDocument::createEmpty();
$ele1 = $doc->createElement('div');
$ele1->classList->add('foo');
$ele2 = clone $ele1;
$ele2->classList->add('bar');

echo "Element1 class: " . $ele1->getAttribute('class');
echo "\n";
echo "Element2 class: " . $ele2->getAttribute('class');

Resulted in this output:

Element1 class: foo bar
Element2 class: foo

But I expected this output instead:

Element1 class: foo
Element2 class: foo bar

3v4l.org: https://3v4l.org/eaosZ#v8.4.7

If try to clone classList will raise an error:

Fatal error: Uncaught Error: Trying to clone an uncloneable object of class Dom\TokenList

But $ele2 = $ele->cloneNode(true) works.

PHP Version

PHP 8.4.7 (cli) (built: May  6 2025 14:14:22) (NTS Visual C++ 2022 x64)
Copyright (c) The PHP Group
Zend Engine v4.4.7, Copyright (c) Zend Technologie

Operating System

Windows 11 and 3v4l.org

@asika32764 asika32764 changed the title PHP 8.4 classList works not correctly if HTMLElement cloned. PHP 8.4 classList works not correctly if copy HTMLElement by clone keyword. Jun 3, 2025
nielsdos added a commit to nielsdos/php-src that referenced this issue Jun 3, 2025
…ement by clone keyword.

The $classList property is special in the sense that it's a cached
object instance per (HTML)Element instance. The reason for this design
is because it has the [[SameObject]] IDL attribute.
Cloning in PHP also clones the properties, so it also clones the cached
instance. To solve this, we undo this by resetting the backing storage.
@nielsdos
Copy link
Member

nielsdos commented Jun 3, 2025

Good find.

Some clarification as to why cloneNode behaves correctly but clone does not:
clone creates a copy of the entire object, while cloneNode only copies the tree structure and then creates a new object instance. This is significant if you have custom properties on an Element instance, or you extend the Element class yourself.

The reason why TokenList is uncloneable is because the DOM spec requires it to always be the same object for a single Element. Therefore, the class can't be cloneable as it would violate this constraint.

nielsdos added a commit that referenced this issue Jun 4, 2025
* PHP-8.4:
  Fix GH-18744: PHP 8.4 classList works not correctly if copy HTMLElement by clone keyword.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants