Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129980 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id 0121A1A00BC for ; Mon, 2 Feb 2026 18:00:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1770055260; bh=ZJv7oethSzcxBY680ao8G+9FtAydqGo9ITPbs10EyTo=; h=From:Date:Subject:To:From; b=PiDPDsNPmr2ib7sMyjcf8oHb7GLoc6INjlXTdpqQQk8HDTBtu+dJObZdxM/za4gKc huRkLmtVSQXu6TXWj/qsC3PtlaZCyvyoilOAYUFwV6ABbkHpGDozBEA6MwiVHfBJpP jcF46+u3dg1UucW4r8iFAWn8Px10vnAQU7AB8okwJDCDISgCETWi/1xk2jiLrqK0E7 WedaHPYNyK2Wfg+ulUh2EY+FjLIGPJ8mVxQSlyh503KNmbPCrhVqNiNUE8Njgtulqt mUe5vcE+82kIqRDNLeYPL345KSxd9xLtyUvudQbKKncpI98JTHgyLo6bnLSHegsqxM vQEA4bFvj9yqw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id DE492180083 for ; Mon, 2 Feb 2026 18:00:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_50, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS, FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from mail-ot1-f47.google.com (mail-ot1-f47.google.com [209.85.210.47]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 2 Feb 2026 18:00:59 +0000 (UTC) Received: by mail-ot1-f47.google.com with SMTP id 46e09a7af769-7d1890f7cefso3964378a34.3 for ; Mon, 02 Feb 2026 10:00:54 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1770055254; cv=none; d=google.com; s=arc-20240605; b=H/8tZLLfWvteK9uTBxxChgLT1Njo0LmkRX0wvvtGiS8ISzVY8BHc+OS3V2yJJ6P0/I hmtaB5pkXnudExg275yI+EUgw45euajfnfk2YKuhaKQe3u1YOfe2Ussy6ZdqZXNANMYH qIaxdTpOBNmB7OPiOxOU1oE9nwHytCk+zUR1m8FR/Ng7dXY3r5bDbIv+WYNLn7ce4Sbg 0JtzmVaFlGdSJ5K9mOlUm+aD+SyT19oA5XPx1J3v3AZ8rQBuKPpGmGOqZc/dQEEAjbCi +lIepCSD0aeSJGFh3AnOfqilBW/7Cbj9tvqWTZaTnXhXrY0AU1KPStbzM8aIowSAAVng dj8A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=7aF+/Hc9C8wNPW9jOUrV9dZoML7IEY4qG3X9x6XUYuU=; fh=5KvmJ5K5QBymFDNCdtgpPKEwgSxqOQnCzLzHVTYb8GE=; b=I5yZHM5o/cqmqta7/VXaRuQivKC3yv3dymQiNxRzXuoK5vaB7y3cHaHAQEpnIACnL2 2gn5sKEKeUIM6ZAAMd+C+ih5M3usmn/PlY2eQM76imTqMWpb7BNDTQ9evwH07oxyClIs Bqv9XWGqrxB/NOJm/MYvNlRZSJOn1ytuHqIpteHNfL/z4KZddHHtbAxWC1/K/32hGObG sg423ChFTrYtO7w29GdXGj/Kz6qJHRDd2trOs8oL8t/CXpe0J9PzidLgD3Ig23YieYan ZIF8l0GjUACNIgHHTBYq7VNzMKEMQOlJ5SghNktqAUp6nVbWeONqgJB6EhqgZV258xgp zfZA==; darn=lists.php.net ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770055254; x=1770660054; darn=lists.php.net; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=7aF+/Hc9C8wNPW9jOUrV9dZoML7IEY4qG3X9x6XUYuU=; b=PMzR9QY39cCTPtIH0khoBWlxWKa2qliNMZjvHLj6Q/Zr0Qe7n8bK7aSnd283+Mnsrk 3kHsd0PDGkKWaaxVEjuNe1mEGSbVu3XhAyF9FNSox2k7Wx5Z7r4PDQ7BeytmDAdDOPh1 JSy9rGFcnKXYUL/YaVbi6/NPqBfkVDZdbW8SJEtIXqkmbBNrETfH1LUxTCLMKeWDRKGg +PRJAsVmf6u/4hxOwvT8e3ikDI8fvBiN2Lhu9WI1e+eSeG7JFYwUWT6Fu0a5+UIysjEp L8OGL1M0h1YEUVCIv4tz3/WzS8cEDs+6Xb7p1OZBvrryYEA3cgaCa1W91jkQpD1nJ1k7 OxJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770055254; x=1770660054; h=to:subject:message-id:date:from:mime-version:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=7aF+/Hc9C8wNPW9jOUrV9dZoML7IEY4qG3X9x6XUYuU=; b=pgCX1/fA4nqhXAdnTRybqSM18euyBtVVOAix0Vne4PGZ0+xJVHZ78U9E/3b9H74y0P oEUgVTk81g60NsC9LlNcrmbzywYtDJBgP38y7F44i7dH2UAAWEaCRUitNof+KyHGJjrC PUfOV84YMGOeD22POv4zGsVujSq/JQFiAjlGfEysDCZhZ/D20771085nzeeToVcFgZ9y o4zwGZ/68HexJNt14S8sdZjcdWlxwTVILbB8UjlYodaGh5ZST1rqfhYiKsInRH9RM0h8 DNEhsfwwA0kBnnwDwgpXlGxJf0D4Kw2nMa4p9bU7MON8QA3rkQ+7ItH9mBX9bXdC4c2/ mvXw== X-Gm-Message-State: AOJu0YzsTn7rbnkk9EwXu0X9g83XvGQ9ueyRNVgMPZGqrLR23P275OQ7 lCR60mREWwat96z63u07m8kXpYzruwpuJi+IvQAhVR1STkmRJOMPsnRjzsVO12i+cQMtVil3PX0 szGfLrgo/ZKxKU89oxKTfwgniHLk1SayOKiJ8YQ4= X-Gm-Gg: AZuq6aJbTM6VE2lFjBGYT8Tngqeq2P/snQPYMLHZF7Hre1/JZKiMr6S2UvNbZC2UbKD xMg7lLAaxHnMNASDSY5QQs20z2Dg4orQ9sNQ5x9rPCL5QDBr4FPcEvJ/92jJn8+34eGheyh6Y2P 9m+Pz8vBte7rSJUxhVJmMLzNXMboMkIK5u6F1ob/1oD9CXHhJltkYTHP8DEpxrwotz99qrsdRyk cdrh3f/FEAHkas5oxfKlUxCr2bxjVHOPxz0mqqiDhTAuRMLM3sRRgiCQCJksWbYLe5hn+yxoYJu dQI5QfMRyqz/tTmn7iywIViO+IEeWsEf X-Received: by 2002:a05:6830:4488:b0:7d1:8b51:c88c with SMTP id 46e09a7af769-7d1a5356b58mr7527515a34.38.1770055253859; Mon, 02 Feb 2026 10:00:53 -0800 (PST) Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 Date: Mon, 2 Feb 2026 19:00:43 +0100 X-Gm-Features: AZwV_QjSqRjlJ5CmdL0JFR-OgTCbHl2WEVW2cYJXjFEnGfejh72sTURgujtsSJU Message-ID: Subject: [PHP-DEV] [IDEA for RFC] let the "new" operator fail when the __construct() function returns a value. To: internals@lists.php.net Content-Type: text/plain; charset="UTF-8" From: mirco.babin@gmail.com (Mirco Babin) 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