Skip to content

fix: walk parent_class chain when looking up __clone for op_clone (#57)#1562

Open
KorsarOfficial wants to merge 1 commit intoVKCOM:masterfrom
KorsarOfficial:bugfix/issue-57-inherited-clone
Open

fix: walk parent_class chain when looking up __clone for op_clone (#57)#1562
KorsarOfficial wants to merge 1 commit intoVKCOM:masterfrom
KorsarOfficial:bugfix/issue-57-inherited-clone

Conversation

@KorsarOfficial
Copy link

Problem

When cloning an object whose class Child does not define __clone() but ancestor Parent does, KPHP silently skips the inherited magic method — violating PHP semantics.

Formal Analysis: Method Resolution Order

Define the class hierarchy:

  • parent : C → C ∪ {∅} — parent class function
  • MRO(C) = [C₀, C₁, …, Cₖ] where C₀ = C, Cᵢ₊₁ = parent(Cᵢ)
  • methods(C) = set of methods declared directly in C
  • lookup(C, m) = Cⱼ where j = min{i : m ∈ methods(Cᵢ)}

Bug: The code used m ∈ methods(C₀) instead of lookup(C, m).

Example:
methods(Child) = ∅__clone ∈ ∅ = false → skip
lookup(Child, __clone) = Parent ≠ ∅ → should call Parent::__clone()

Fix

Replace klass->members.has_instance_method() (checks only C₀'s own members) with klass->find_instance_method_by_local_name() which traverses the full parent_class chain.

Correctness proof (by code inspection of class-data.cpp:268-299):
find_instance_method_by_local_name(C, m) iterates cur = C, parent(C), parent²(C), … returning the first match — exactly implementing lookup(C, m). ∎

Complexity: O(d) where d = inheritance depth (typically 1–5).

Tests

  • tests/phpt/clone_keyword/105_inherited_clone_method.php — parent defines __clone(), child inherits
  • tests/phpt/clone_keyword/106_deep_inheritance_clone.php__clone() two levels up

Technical Report

📄 Full report with mathematical formalization (PDF)

Closes #57

…COM#57)

When cloning an object whose class does not define __clone() but an
ancestor does, KPHP was not calling the inherited magic method because
members.has_instance_method() only checks the class's own methods and
does not walk the inheritance chain.

Changed on_clone() in ConvertInvokeToFuncCallPass to use
find_instance_method_by_local_name() which walks the full parent_class
chain, matching PHP semantics.

Also adds two regression tests:
- tests/phpt/clone_keyword/105_inherited_clone_method.php
- tests/phpt/clone_keyword/106_deep_inheritance_clone.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inherited __clone is not called

1 participant