Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129089 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 506651A00BC for ; Wed, 5 Nov 2025 16:17:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1762359448; bh=5wpcjpRXmh0bFAlr/aHj/r/yBhGF/x94Z3CRy4mpHgg=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=CP9Z90tW5/uWAsURYNUneLta5avPqbU8KGFfbVIMNP+BHhZuU/dDWu77SfKc1/sFJ 7djHkmMTlfv4HrRJp5rGr9Yo1Yg6EBUr3Ekwsvdw20GrKIZibeIq14d+cTFbLBV449 b47rW/LS5bI47Pa3jbg1q/S2WMwLV239XwUw0M750hov7Ijr+GSaKNxPc7w6EbG1uh +Fl5sliLAqF8FAhhUJc8QkAcs8aAk+SJWQlGi0o/wxf8ckztU3/le9CKcWrs6VtQeO j9k2wuiN8Gk4IgDr2v0HIGznESPtSl2GJkhkcHqG4zw8yk+0sKcmJwYk01tkCYX8CR CeSvIfLriUthQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 1104F180086 for ; Wed, 5 Nov 2025 16:17:27 +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.2 required=5.0 tests=BAYES_40,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-ej1-f53.google.com (mail-ej1-f53.google.com [209.85.218.53]) (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 16:17:26 +0000 (UTC) Received: by mail-ej1-f53.google.com with SMTP id a640c23a62f3a-b7200568b13so452741466b.1 for ; Wed, 05 Nov 2025 08:17:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1762359440; x=1762964240; darn=lists.php.net; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=5wpcjpRXmh0bFAlr/aHj/r/yBhGF/x94Z3CRy4mpHgg=; b=ayY6UrH2XpgLXHBl2wX433XS3AaQo0212VCxUaghnUMpVeAKlxp1tS60Ml9dXPhPwM I6ZFPR9c2V/SUsEJF7y6tzQsEMOqsCvhapvRPzWO5cVEHTC7ZkpcyeGv9xL9wK9SS2CP 1gtr1B8YA4V+7Rxc+cRo1J/YX83UF0YkDQ6PZajtIEwaKwf5yNZoseSSm5ej8OBC40pw 4AG8lrwmej6zz/r4p5V5oRrmfyIom9NlCAFre62ETYkQvuzGNzxS0974Lo6cc9ThIlMY oRQMOzQj8wzOQWwT108FUg1to+3IGM5emQcaqcZ+SwG4ZX2csT1cId1uNAg6VGSMUzyU 6LLQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1762359440; x=1762964240; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=5wpcjpRXmh0bFAlr/aHj/r/yBhGF/x94Z3CRy4mpHgg=; b=BZIR2rLJtaLz7krikiPp6kWf0+tdcZMK7GufwRS79344iXtNWmS+kB1qjo5CJl1wUt kBfPu0WvJAnEjVWu+DXaRfSPgaiDn1fzjvGU823a0UUBG6tk2PVSZIl/LmEcTGMaXt6F 4Yah3S1reUiFYgnecvYRHoNWzTQGFgU4Zs7ntTQb9XbDVlHPl9WKU0Sh/m+TAYu61VfL HiPpg2GTZTu8o84IPpk2enxFdj+tIyT6UPbVaEcDzaEcXF8YI/1Ht1R/+TAEk+8oS03I BAfGuneg0thkQC4EvsMyT0/FBkCu9hjoS5CA2kDWt/kXbgeJQTDNvuETPBkBXct7/63E FLog== X-Forwarded-Encrypted: i=1; AJvYcCXSzf8++vS8vd+sv8IDBDwhTTJASH0pgritVUuHbD/dhP6Yv99kkapJkwgj+2CPWTO+P+AELhxG57s=@lists.php.net X-Gm-Message-State: AOJu0YydqDzdIjNrVty/G6C9pEnxMKsf+/dmgnEMLmD/h/zIXjfBZDvd CCWsdszBiDcldQIa6FLvDILwyxuyxD9awEmB+acu5orEekOsJxQ799T+FjrJZNKsh2Q4GpE/Pdt s7Yy8snwKDY43OwiN9lmouQxyT+QY3Fs= X-Gm-Gg: ASbGncsfDT5GtA424u5k41ymjxqMJjJSpzNDwdbT6YvpSJ6H5OPedn/JlaBDuwbuFP/ V8X4IkqS/78dDRbBrRapk2lMbbHNrCKP183pT1a1PQI+97ncvQYjz5HMU2z/XgrkJrD+mCPyf/3 lgos1AiQ4of++QLuvSjBmCQsylDqPbOYU+0Xwi7OTrCY1xYZPbbhnYu/sv4OZebC06Ht/LOZXPP 1AaNkP2x+ADVvAzFm6wbbedoW4Vh5GEgwY4WfCEKfrMuTYZ2OczcjwtTIqE X-Google-Smtp-Source: AGHT+IFPSuUVC8T6PJw0hiGFOlAKzko3Kf+r+e5JcGO8yjB6QziCnzIaLwt9Vjd8h1WWmOaTLbynni0VybZRgA2+jRM= X-Received: by 2002:a17:907:60ca:b0:b30:c9d5:3adc with SMTP id a640c23a62f3a-b726560f837mr331511966b.49.1762359440321; Wed, 05 Nov 2025 08:17:20 -0800 (PST) Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 References: <4bf2e8023b934e73e0832c8dc3ddeb3c@bastelstu.be> In-Reply-To: <4bf2e8023b934e73e0832c8dc3ddeb3c@bastelstu.be> Date: Wed, 5 Nov 2025 17:17:06 +0100 X-Gm-Features: AWmQ_bnSgA9oGAeD4-OtqXFPV2P2yrKCSM66T9TDVPCWcSzli0OPEEChbD3F24Y Message-ID: Subject: Re: [PHP-DEV] [RFC][Discussion] use construct (Block Scoping) To: =?UTF-8?Q?Tim_D=C3=BCsterhus?= Cc: Seifeddine Gmati , internals@lists.php.net Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable From: arnaud.lb@gmail.com (Arnaud Le Blanc) Hi, On Wed, Nov 5, 2025 at 1:39=E2=80=AFPM Tim D=C3=BCsterhus wrote: > PHP has gradually been moving towards =E2=80=9Cmaking illegal states > unrepresentable=E2=80=9D. With the migration from resources to objects an= d 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'm all for making illegal states unrepresentable, and I'm glad that PHP goes in this direction. But I don't think this is achievable or desirable for objects that represent external resources like files or connection to servers, which is what with() and similar mechanisms target. These resources can become invalid or operations on them can fail for reasons that are external to the program state. Removing close() methods will not achieve the goal of ensuring that these resources are always valid. > 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. This will also happen due to external factors, for example if the disk becomes full. Having a File object that can not be closed doesn't ensure that operations on it will not throw. Regarding `use()`, there are two alternatives, with different outcomes: 1. use() doesn't forcibly close resources: If a resource escapes despite the intent of the programmer, the program may appear to work normally for a while until the leak causes it to fail 2. use() forcibly closes resources: If a resource escapes despite the intent of the programmer, the program may fail faster if it attempts to use the resource again The second alternative seems better to me: * If a mistake was made, the program will stop earlier and will not successfully interact with a resource that was supposed to be closed (which could have unwanted results) * Troubleshooting will be easier than chasing a resource leak > Being able to let resource objects escape is a feature, since this > allows to reliably pass locks around without the resource suddenly > getting unlocked. Would you utilize `use()` to lock a file in cases where the lock is supposed to outlive the `use()` block? Making objects invalid to detect bugs can also be a feature: We could make a LockedFile object invalid once it's unlocked, therefore preventing accidental access to the file while it's 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 =E2=80=9Cnot closing=E2=80=9D and =E2= =80=9Cforcibly closing=E2=80=9D > the resource. In case of forcibly closing, your I/O polling mechanism > might suddenly see a dead file descriptor (or worse: a reassigned one) - The reassigned case can not happen in PHP as we don't use raw file descriptor numbers. > and static analysis tools need to report every single method call as > =E2=80=9Cmight possibly throw an Exception=E2=80=9D. This is the case even if we removed every possible way to close a file descriptor > PHP=E2=80=99s main mechanism of managing lifetimes is reference counting = and by > that its semantics are much closer to those of languages that you call > =E2=80=9Cstack allocated=E2=80=9D. Specifically PHP's semantics around re= sources 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. I don't think that `use()` is an upgrade, if it means that I have to think about refcounts, track reference cycles, and carefully add WeakReferences. This seems like too low level considerations to have when programming in a high level language. This is not better than the problems it tries to fix. The fact we had to introduce a cycle collector, and that most projects don't disable it, shows that cycles exist in practice. The fact that they exist or can be introduced is enough that thinking of PHP's GC mechanism as something closer to a tracing GC is easier and safer, in general. A resource doesn't have to be part of a cycle, it only needs to be referenced by one. I don't agree that it's easy to resolve or to avoid cycles. There are no tools to discover or prevent them, and they don't show up in CI. They can be introduced at any time, so a program employing `use()` that works as expected today may break later due to an unrelated change. And it doesn't always depend on the application's own code, sometimes this happens due to a library. But cycles are not the only issue: Variables can be captured, accidentally or not (e.g. by a logger/tracer/cache/library/eventloop), without the knowledge of the programmer, increasing their refcount and extending their lifetime. Best Regards, Arnaud