Skip to content

Bug: Typed private property initialization flag not updated during dynamic assignment in __unserialize #21584

@wheakerd

Description

@wheakerd

Description

Description
In PHP 8.4.17, assigning values to typed private properties using dynamic property names (e.g., $this->{$key} = $value) inside the __unserialize method fails to correctly update the property's internal initialization state.

Although var_dump() correctly displays the property value and the property is initialized, any attempt to access the property via a getter method results in a fatal error ($parameter must not be accessed before initialization). The Zend Engine's property hash table appears to be updated, but the initialization protection mechanism is not triggered when dynamically accessing private scopes.

PHP Version
PHP 8.4.17 (cli)

Reproduction Script

<?php

class Annotation 
{
    private ?string $method = null;

    public function __construct(string $method) 
    {
        $this->method = $method;
    }

    public function getMethod(): string 
    {
        // This fails even if var_dump shows $this->method has a string value
        if ($this->method === null) {
            throw new \LogicException("Method is null");
        }
        return $this->method;
    }

    public function __serialize(): array
	{
		return get_object_vars($this);
	}

	public function __unserialize(array $data): void
	{
		foreach ($data as $key => $value) {
			if (property_exists($this, $key)) {
				$this->{$key} = $value;
			}
		}
	}
}

// 1. Create and serialize
$obj = new Annotation("index");
$serialized = serialize($obj);

// 2. Unserialize
$unserialized = unserialize($serialized);

// 3. Inspection
echo "Var_dump output:\n";
var_dump($unserialized); 

try {
    echo "\nCalling getMethod(): " . $unserialized->getMethod() . "\n";
} catch (\Throwable $e) {
    echo "\nCaught Exception: " . $e->getMessage() . "\n";
}

Expected Result

The output should be:
Calling getMethod(): index

Actual Result
$method must not be accessed before initialization

(Note: var_dump inside the script will show ["method":"Annotation":private]=> string(5) "index", proving that the data exists in memory but cannot be accessed.)

Additional Context

  • This problem occurs with all visibility type properties.

  • Using explicit assignment $this->method = $data['method'] instead of a foreach loop also fails to solve this problem.

PHP Version

PHP 8.3.27 (cli) (built: Oct 25 2025 03:25:55) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.27, Copyright (c) Zend Technologies

Operating System

Ubuntu 24.04.4 LTS

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions