symfony / symfony/php-ext-deepclone

deepclone_to_array(): loses initializer of uninitialized PHP lazy ghost objects

Open
#32 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C
Stars
17
Forks
3
PR merge metrics
No merged PRs in 30d

Description

Title

deepclone_to_array() loses initializer of uninitialized PHP lazy ghost objects

Description

When an uninitialized native PHP lazy ghost object is passed to deepclone_to_array() and then reconstructed using deepclone_from_array(), the resulting object no longer has its lazy initializer and its lazy properties remain uninitialized.

This can produce an object in an invalid state and later cause errors such as:

Typed property Foo::$value must not be accessed before initialization
Minimal reproducer
<?php

final class Foo
{
    public function __construct(
        public string $value,
    ) {
    }
}

$reflection = new ReflectionClass(Foo::class);

$foo = $reflection->newLazyGhost(
    static function (Foo $foo): void {
        $foo->__construct('test');
    },
);

$clone = deepclone_from_array(
    deepclone_to_array($foo),
);

var_dump($clone->value);
Expected behavior

The cloned object should contain the fully cloned state:

string(4) "test"

I would expect deepclone_to_array() to initialize an existing uninitialized lazy object before serializing its state, similarly to operations such as native clone.

Actual behavior

The object reconstructed by deepclone_from_array() has no lazy initializer anymore, while its typed properties are still uninitialized.

Accessing the property therefore fails with:

Typed property Foo::$value must not be accessed before initialization
Workaround

Initializing the lazy object explicitly before calling deepclone_to_array() avoids the problem:

$reflection = new ReflectionObject($foo);

if ($reflection->isUninitializedLazyObject($foo)) {
    $reflection->initializeLazyObject($foo);
}

$clone = deepclone_from_array(
    deepclone_to_array($foo),
);

It would be useful if deepclone_to_array() handled already-existing native lazy ghost objects automatically, so callers do not need to detect and initialize them beforehand.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the deepclone_to_array() and deepclone_from_array() entry points and reproduce the issue using ReflectionClass::newLazyGhost() as shown. Verify that a round trip initializes the lazy ghost and that accessing Foo::$value produces string(4) "test" rather than an uninitialized-property error.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, php
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.