This RFC proposes to prevent instantiation and cloning of the internal class __PHP_Incomplete_Class.
__PHP_Incomplete_Class is used as a placeholder when unserialise encounters an object whose original class definition is not available. It represents an incomplete deserialization state and is not intended to be constructed or duplicated directly.
The following changes are proposed:
__PHP_Incomplete_Class via new__PHP_Incomplete_Class instances
Attempting to instantiate the class will throw an Error stating that instantiation of __PHP_Incomplete_Class is not allowed.
Attempting to clone an instance will throw an Error indicating that the object is not cloneable. ReflectionClass::isCloneable will report false for this class.
Objects created internally by unserialize when a class definition is missing remain fully supported and unchanged.
__PHP_Incomplete_Class models a failure scenario during deserialization. Allowing it to be instantiated or cloned creates an artificial state that does not reflect how incomplete objects arise in practice.
Incomplete objects should only originate from unserialize when the serialized payload references a class that is not loaded. PHP then creates an __PHP_Incomplete_Class instance and stores the original class name for diagnostic purposes.
This change also aligns with existing constraints: extending __PHP_Incomplete_Class is already not possible, and instantiation via reflection based creation paths that would normally bypass constructors is already not possible. Preventing direct construction and cloning completes the model by ensuring incomplete objects can only arise from their intended source.
Code that directly instantiates or clones __PHP_Incomplete_Class will now fail as __PHP_Incomplete_Class is an internal class not intended for direct use. However, any such usage will need to be refactored to create incomplete objects through unserialization or other means that do not involve direct instantiation or cloning.
Instantiating __PHP_Incomplete_Class directly will now throw an Error:
// Fatal error: Uncaught Error: Instantiation of class __PHP_Incomplete_Class is not allowed new __PHP_Incomplete_Class();
Cloning an instance of __PHP_Incomplete_Class will now throw an Error:
// Fatal error: Uncaught Error: Trying to clone an uncloneable object of class __PHP_Incomplete_Class $incomplete = unserialize('O:16:"NonExistentClass":0:{}'); $clone = clone($incomplete);
Tests that previously relied on direct instantiation can create an incomplete object through unserialize of an unknown class name instead:
// This will create an instance of __PHP_Incomplete_Class without directly instantiating it $incomplete = unserialize('O:16:"NonExistentClass":0:{}'); /* * object(__PHP_Incomplete_Class)#1 (1) { * ["__PHP_Incomplete_Class_Name"]=> * string(16) "NonExistentClass" * } */
This change is proposed for PHP 8.6.
No expected impact. __PHP_Incomplete_Class is an internal class and extensions should not rely on constructing or cloning it directly.
Only code that explicitly constructs or clones __PHP_Incomplete_Class is affected. Normal serialization and deserialization flows are unaffected.
No measurable performance impact is expected. The change only adds guards to construction and cloning paths.
The vote starts on 2026-xx-xx, ends on 2026-xx-xx, and requires 2/3 majority to be accepted.
After the RFC is implemented, this section should contain:
Links to external references, discussions, or RFCs.
Keep this updated with features that were discussed on the mail lists.
If there are major changes to the initial proposal, please include a short summary with a date or a link to the mailing list announcement here, as not everyone has access to the wikis' version history.