Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129087 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 507391A00BC for ; Wed, 5 Nov 2025 12:39:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1762346351; bh=xBqbPkeuTAVPQRNAEUC03kj5KozFhBN/GW2Fb0XFmiU=; h=Date:From:To:Cc:Subject:In-Reply-To:References:From; b=QP/wuiktPB93gVX4dES5BJILVsXG9mSdUGm1h1FImjWBQHPeuSte7mEl/K5VkxeRy G17kRk4xNt/rTscHGg4Ee8jxIG+2GflsmMNW2c5aOmJGNffxuXnzXvIAYPguivItR9 Ky/7UVlKfWGoO5194U8rbpXVQUTkK2pMOs+Wjsfco5cT1GFKR5G9Df4+IdukVTm0b8 7bvFZH2JhrM7zAoblgC+52qW7o6ylBxqq4OB4PcBFGX4Kmm+6Ft820b1ixe4J9GBrm T22uwMe1QLDGIAWgdt7Hw2B4k1HcO0skGyZUwOvA25s1P4FSYkEU1v1IGMFSn7dTl1 ePpYHgLenVyoQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 024AE180084 for ; Wed, 5 Nov 2025 12:39:10 +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=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from chrono.xqk7.com (chrono.xqk7.com [176.9.45.72]) (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 ; Wed, 5 Nov 2025 12:39:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bastelstu.be; s=mail20171119; t=1762346342; bh=WjEg+eDFNqVUxDu9xYoDP3XPOiO7U+vJhXQz/6X67EA=; h=MIME-Version:Date:From:To:Cc:Subject:In-Reply-To:References: Message-ID:Content-Type:from:to:cc:subject:message-id; b=oiyj89AkC5q7wcxxLX19LegMsMqAeJPDMBLpiBT69qtlSb0tU5vsF1Ge3j11JNAtR zXk/WGD9uf2oIgirO6wKhfdB0k9y+Cy3nK/VEYnSGGBdgU3/w6o0upiKyGGtR5Rqic n4/uY2uSM+Ddkp5FLOj01PISfKj7ihp2sAVts/Ra3wdP/hrptoI7P13BDVGUUVa2ZL F6UE2XbcztI385P/QRGliUF7GdwtT3MsLzjq31bJs2UXn5p8neNYQEKFtB9YKxR04W S9ZsX/+rZSct2ER5ymdaLOvjzyL2dQn/8a8iVEjmtd+8IxBauTdTdN5NjLOksBJ/tM 0i0rY/vLQONAQ== Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 Date: Wed, 05 Nov 2025 13:39:02 +0100 To: Arnaud Le Blanc Cc: Seifeddine Gmati , internals@lists.php.net Subject: Re: [PHP-DEV] [RFC][Discussion] use construct (Block Scoping) In-Reply-To: References: Message-ID: <4bf2e8023b934e73e0832c8dc3ddeb3c@bastelstu.be> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit From: tim@bastelstu.be (=?UTF-8?Q?Tim_D=C3=BCsterhus?=) Hi Am 2025-11-04 13:31, schrieb Arnaud Le Blanc: > The proposal relies on destructors or automatic closing of resources, > but > this should not be relied on when timing matters. In general, > destructors > should be avoided IMHO [4][5]. They are useful in languages with > stack-allocated variables because timing and order can be guaranteed, > but > not in heap-allocated languages with automatic GC. PHP > resources/objects > are heap-allocated, and its GC mechanism behavior/semantics is similar > to > Java's due to cycles: resource/objects are not guaranteed to be > closed/disposed of immediately, and the order in which this happens is > undefined. This is misrepresenting how PHP’s semantics around lifetimes work and using that as a strawman argument to build something that does not fit the existing semantics of PHP / the direction PHP is taking as of late. PHP’s main mechanism of managing lifetimes is reference counting and by that its semantics are much closer to those of languages that you call “stack allocated”. Specifically PHP's semantics around resources and objects match the semantics of `std::shared_ptr()` (C++) or `Rc` (Rust), which - like PHP - are languages that guarantee that destructors are predictably executed. Namely exactly when the reference count falls to zero. This is also documented and thus an explicit part of the semantics that PHP users rely on - and not just an implementation detail: https://www.php.net/manual/en/language.oop5.decon.php#language.oop5.decon.destructor. The file locking example using Seifeddine's PSL library from the RFC is a real-world use case that successfully relies on these semantics. It is true that the point in time when the reference count falls to zero is unpredictable in case of cycles, since this is dependent on the assistance of the cycle collector. Cycles however are a comparatively rare situation, particularly when dealing with a resource object. These situations are also easy to resolve using the same mechanism that one would use in C++ to deal with shared_ptr cycles, e.g. by including a WeakReference for one of the directions. > Here are some use-cases that Python's `with`, C#'s `using`, or Java's > `try-with` were designed to address, but are not addressed by this RFC: > > // Commit the transaction as soon as the block is left, or roll it back > if > an exception is thrown: > with ($db->beginTransaction() as $transaction) { > $transaction->execute(...); > $transaction->execute(...); > } > > If $transaction escapes, it's not committed at the end of the block. > Regardless, it's not possible to automatically rollback the transaction > in > case of exception. This is easily solved by making the “commit” operation explicit and not relying on exceptions for control flow. The suggested implicit commit is dangerous, since it might accidentally commit the transaction when undesired (e.g. when adding a guard clause with an early return). Here's an example: finalized = true; echo "COMMIT", PHP_EOL; } public function __destruct() { if (!$this->finalized) { echo "ROLLBACK", PHP_EOL; } } } use ($t = new Transaction()) { $t->commit(); } Nevertheless, this RFC acknowledges that use case as part of the “Future Scope” section, as Seifeddine also mentioned in a previous reply to Edmond: https://news-web.php.net/php.internals/129076 > // Close file descriptor as soon as the block is left: > with (get_fd() as $fd) { > // ... > } > > If $fd escapes, it's not closed at the end of the block. This may > affect > the program's behavior is various ways: > * The system's file descriptor limit may be reached before the GC > triggers > * If $fd was a socket, and the other side waits for closing, it may > hang > * If $fd has unflushed writes, readers will have an inconsistent view If $fd escapes and is nevertheless closed at the end of the block, this may affect the program's behavior in various ways: - Suddenly any operation on the file descriptor fails. PHP has gradually been moving towards “making illegal states unrepresentable”. With the migration from resources to objects and the removal of the associated `_close()` functions, PHP developers and static analysis tools can rely on the fact that having a reference to the object means that the reference will always be valid. This is also something that Kamil mentioned as a good thing in the RFC discussion for the PDO::disconnect() method: https://news-web.php.net/php.internals/128742 I'd like to note again that “The system's file descriptor limit may be reached before the GC triggers” is misrepresenting how lifetimes work in PHP. Unless the file descriptor somehow ends up as a part of a cycle, it will reliably be closed exactly when nothing holds a reference to it - i.e. when nothing is interesting in making use of the FD any longer. Being able to let resource objects escape is a feature, since this allows to reliably pass locks around without the resource suddenly getting unlocked. > Escaping/capturing is difficult to avoid, especially in large code > bases, > as it can not be checked with static analysis, typing, or avoided by > means > of API design. Sometimes it's even necessary, e.g. a file descriptor > may be > referenced by an I/O polling mechanism. This is true, but equally affects “not closing” and “forcibly closing” the resource. In case of forcibly closing, your I/O polling mechanism might suddenly see a dead file descriptor (or worse: a reassigned one) - and static analysis tools need to report every single method call as “might possibly throw an Exception”. >> Introducing a Disposable interface (similar to C#'s IDisposable) to >> allow > objects to define custom, explicit cleanup logic that is automatically > called by use. > > I'm in favor of introducing this immediately, for the reasons above, > and > […] I refer to Seifeddine's reply to Edmond: https://news-web.php.net/php.internals/129076 Best regards Tim Düsterhus