Subject: [IDEA for RFC] let the "new" operator fail when the __construct() function returns a value. Date: 2 february 2026, 19:00h (Europe/Amsterdam)
Hello Internals, The starting point of this idea is https://github.com/php/php-src/issues/21090 By the way, I urge everyone to try out "yield 1" from the BC impact chapter. That really demonstrates that the current "new" methodology is pointless. # Problem The "new" operator internally calls the __construct() function. However, the return value of the __construct() function is silently lost. This is very error-prone; I personally made a major security mistake with this when upgrading from Laravel 9 to Laravel 12. To prevent future problems, my proposal is to have the "new" operator explicitly issue warnings, and later have it explicitly abort when the __construct() function returns a value. A high-level overview of the "new" operator's operations. I haven't explored this in detail; it's about the overall picture. ```php // High level picture of the "new" operator. $newed = acquire_memory_and_initialize_object() if (function_exists($newed, '__construct')) { $newed->__construct(...); // NOTICE that a return value from the __construct() function is silently // discarded. } return $newed; ``` # My proposal Modify the "new" operator to the following. This will prevent a return value from being silently lost. Instead, a warning will be issued and later the "new" operator will throw a TypeError. ```php // High level picture of the adjusted "new" operator. $newed = acquire_memory_and_initialize_object() if (function_exists($newed, '__construct')) { $__constructReturnValue = $newed->__construct(...); if ($__constructReturnValue !== void) { // DEPRECATION: returning a value from the __construct() function // when called by the "new" operator is deprecated. // LATER: throw new TypeError('the __construct() function must not // return a value when called by the "new" operator.'); } } return $newed; ``` # BC impact Yes, there can be BC impact. If the __construct() function is also used as a regular function. For example, ```php class SomeTheoreticalExample { public $uniqueId; public function __construct(bool $returnSomeValue) { static $uniqueId = 0; $this->uniqueId = $uniqueId; $uniqueId++; if ($returnSomeValue) { // return some pointless value. Pointless, because it is // silently discarded by the "new" operator. return 'abc'; // return 1; // return 1.23; // return null; // return true; // return false; // return ['a', 'b', 'c']; // return [6 => 'six', 7 => 'seven', 67 => 'six seven']; // return ['a' => 'a', 'b' => 'b', 'c' => 'c', 0 => 'Zero']; // return SomeEnum::Spades; // return function() {}; // return fn($a) => $a; // return new DateTimeImmutable(); // return fopen('php://memory', 'w+'); // return $this; // return &$this; // return new SomeTheoreticalExample(false); // Laravel 12 controller specific, of course this is very // very wrong. It will NEVER redirect, and the flow // continues to reach the (unauthorized) controller function. // return redirect()->route('login'); // This is a very terrible case. Try it out yourself and // watch the returned $newed->uniqueId. // Spoiler alert: it won't be 0. // yield 1; } } } // Before the RFC TypeError fact: nothing. // After the RFC fact: will fail. $newed = new SomeTheoreticalExample(true); // Before the RFC TypeError fact: nothing. // After the RFC fact: never called, because of the previous statement failure. $someReasonToCall__ConstructAgain = $newed->__construct(true); ``` # RFC I've been asked to follow the RFC process. And I've been told that the rejected PHP RFC Make constructors and destructors return void ( https://wiki.php.net/rfc/make_ctor_ret_void ) rejects my proposal. However, my proposal is explicitly about the "new" operator and not about return types. It does, however, concern return values. I am very very reluctant to follow the RFC process myself: * It would take up a lot of my free time. I would write the RFC first in Dutch, my native language, and then translate it into English. This is because I speak and write English, but don't understand all the nuances of (American/Australian/British/Canadian/Irish/Nigerian/...) English. * While I do have some knowledge of C and the php-src codebase, writing a PR to implement the RFC would take up a significant amount of my free time. * The True Async RFC has demonstrated that the author of an RFC must have a certain degree of trustworthiness. And I, as a passerby, have not established any trustworthiness. * The voting process of an RFC is highly uncertain and can lead to rejection. The whole process could ultimately be a complete waste of my time. Anyone who would like to create an RFC for this, please go ahead. Yours sincerely, Mirco Babin
