Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:107630 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 82097 invoked from network); 22 Oct 2019 15:52:59 -0000 Received: from unknown (HELO php-smtp3.php.net) (208.43.231.12) by pb1.pair.com with SMTP; 22 Oct 2019 15:52:59 -0000 Received: from php-smtp3.php.net (localhost [127.0.0.1]) by php-smtp3.php.net (Postfix) with ESMTP id BC4092CB34B for ; Tue, 22 Oct 2019 06:38:53 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp3.php.net X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,HTML_MESSAGE,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS3215 2.6.0.0/16 X-Spam-Virus: No Received: from mail-io1-xd2d.google.com (mail-io1-xd2d.google.com [IPv6:2607:f8b0:4864:20::d2d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp3.php.net (Postfix) with ESMTPS for ; Tue, 22 Oct 2019 06:38:53 -0700 (PDT) Received: by mail-io1-xd2d.google.com with SMTP id u8so20406414iom.5 for ; Tue, 22 Oct 2019 06:38:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=b8B4SCqrHYc4Ci5keiCyBMdkwzd0aIe1AqX/m3eTzvI=; b=Q/8UMKaQ/vHfoV3Yn36i5njT/FfQ+C6sscLJ7GgUicsYMNCP2dTAPY4KQhjWfQSS+n 0iK7G079WRiJsF+nGWNIDZjEIUrDMVCgqT86sZIx/YFWweS6t4w3n5ZnWhqly6F2rsTa HUL1wGhuFHmNB1zYVXfKju0ohS9oKtdFyVlAte3wYZS2g3KLl4pv0WCXBqQV5u5px1jm aaiLTxsSJdtOwsrhjThva7h3NhNH+CWhqTj+yjvoinraiYwj921mUiuuam10vwiOowu5 Lh6TE/rxytbrqIS++Zy6DQdBCN9B7sUgZydMArt3zW8NI/redfw1lKj00uoTvRtcgZXX IyYg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=b8B4SCqrHYc4Ci5keiCyBMdkwzd0aIe1AqX/m3eTzvI=; b=shqtyTqKNFE6HvnEjhvkukYi3DMO6tsxiBJB+uwRHSmhpdV2xBnIxaglDyXg6l731R z5v81TVuNXdI4LPmE/5pP3EOp1OTDctSluU4bbv2akEiodQ6XATa3MLlN69zDg94aLKr lj93MlhzGwWGeu/GOWWDSNlyUrGZoJ0C8W6n9NvNxxyO+BFq0JlzwSxIVPOZzgYaPuZ1 Cv1ApxEBdQ74oeCBDvP2TEuUl1NXI0S3CWyNWf7NDCb7ARp1ltq57ytPrNzIv0+DIcnA CCY5lU5SZQxqM2cJppP6BEC6jUAK22ArI1fqnI6pf30BKUDDUO8W1qvjQQhs5sOkrN4q +jXQ== X-Gm-Message-State: APjAAAX+BZUzMthzgxTS4tdx4KG8lhk4oPafx7iPz5YWKU/nuAAk3Mle bGsWcOP+Zbc4CLB9hM9260bKppnLy0QzxmAe76w= X-Google-Smtp-Source: APXvYqx9JSGc3X1F64kxNiAxiMe1Sytjxi2WwmDt3qAky/HfTvV5WfNO+gQ4s9/YNZg+uNkjTs1GDJr2xeITk7/ff08= X-Received: by 2002:a6b:f216:: with SMTP id q22mr3529937ioh.36.1571751532494; Tue, 22 Oct 2019 06:38:52 -0700 (PDT) MIME-Version: 1.0 References: <6fa02cb5-b474-4b36-4e0f-89679475e250@gmail.com> <9c1795d1-a069-f1b5-686c-7d53e39e1033@gmail.com> In-Reply-To: <9c1795d1-a069-f1b5-686c-7d53e39e1033@gmail.com> Date: Tue, 22 Oct 2019 15:38:39 +0200 Message-ID: To: Rowan Tommins , mike@newclarity.net Cc: PHP internals Content-Type: multipart/alternative; boundary="000000000000c505f705957feb25" X-Envelope-From: Subject: Re: [PHP-DEV] Reclassifying some PHP functions warning as exceptions From: benjamin.morel@gmail.com (Benjamin Morel) --000000000000c505f705957feb25 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable @Mike, > Then about a year ago I started using Go, and Go's approach to error > handling just clicked for me. Go's philosophy is to handle the error as > soon as you one is aware of it and to only ever handle it once. Since I > have been using that strategy I have become very happy with my error > handling, and I now (attempt) to use the same strategy in my PHP code. > So what I am hoping for is that PHP recognizes there are two strategies > for error handling =E2=80=94 1. Throwing exceptions vs. 2. Returning erro= r values =E2=80=94 > and that PHP 8.0 and behind will respect programmers and allow them to > embrace the strategy they feel is best for their use-case. I do see some value in the way Go handles errors (i.e. forcing you to deal with them), especially the *expected* ones; the issue, if I'm not mistaken, is how you deal with *unexpected* errors. AFAICS, this forces you to either return it to the caller (which may not expect this error), or wrap it in a more specific error that's part of your function's contract, which is pretty much what you do with exception chaining. I don't have a hands-on experience with Go, though, so I may have missed something. Please do correct me if/where needed. @Rowan, You've backed that up with exactly one example function, and immediately > concede a case where you might want a non-exception flow. Here are a > handful more examples off the top of my head: > * Attempt to atomically lock and open file, returning either a file > handle or a "could not lock" status. > * Attempt to read from a file, terminate loop when the file handle > reaches EOF. > * Attempt to delete file, ignore if it doesn't exist. > All of these are candidates for returning false, or an error code, or an > object in a particular status. They could be handled with exceptions, > but that would force common patterns to use exceptions for flow control, > which is generally seen as a "bad smell". I used this one function as an example, but I'm happy to apply my point of view to other examples if you wish. I'll take yours above, in reverse order= : *- Attempt to delete file, ignore if it doesn't exist:* unlink($file): bool; // true if the file was deleted, false if it didn't exist; exception on other errors As I see it, the only safe-to-ignore error is "the file does not exist" (non-exceptional error), as the outcome is the same whatever the return value: the file does not exist (anymore). Any other error should, IMO, be treated as exceptional and throw. *- Attempt to read from a file, terminate loop when the file handle reaches EOF:* I think the current API is already quite good at that, it just needs a bit of polish in the way it handles errors: while (! feof($fp)) $block =3D fread($fp, 4096); feof($fp): bool; // true if EOF, false if not; exception on error fread($fp): string; // the data, empty string if EOF (non-exceptional); exception on error I don't see much value in doing something like: for (;;) { $result =3D fread($fp, 4096); if ($result->isEOF) break; if ($result->error) { // ... } $block =3D $result->data; } *- Attempt to atomically lock and open file, returning either a file handle or a "could not lock" status:* fopen_and_lock($fp); // true if lock was acquired, false if not; exception on error This one is trickier, as the outcome is roughly the same (the file was open) but maybe the lock failed to acquire. I can't say if I would return bool, or void and an exception on failure-to-acquire. Don't get me wrong, I respect your points of view, they are perfectly valid, and as such I'm not trying to push exceptions over anything else; but I don't personally see them as bad at all, they're actually quite convenient if used properly. I do see some value in returning errors, too, but with the strong caveat expressed below, that may severely affect inexperienced, or, should I say it, lazy developers. I like the exception model, breaking the program flow by default if unhandled. This makes an app much more reliable *by default* IMHO. Therefore I do like the original proposal, even if I can hardly imagine it overcome the usual resistance here. This proposal would be as good under the form of a new API though, but in this case the naming should be changed to clearly differentiate both APIs. I wish you luck, @David, anyway. =E2=80=94 Benjamin On Mon, 21 Oct 2019 at 23:59, Rowan Tommins wrote= : > On 21/10/2019 21:38, Benjamin Morel wrote: > > Sure, you can do without exceptions. I think what you're suggesting is > > similar to Go's error handling. But PHP at some point decided in > > favour of exceptions, so it would be logical to pursue in that directio= n. > > > I didn't say "do without exceptions", I said "use exceptions when > they're the right tool, and other tools at other times". > > > > I would classify most, if not all, filesystem-related functions as > > mostly "yes, do stop execution by default when something fails". So > > this is, as well, in favour of exceptions. > > > You've backed that up with exactly one example function, and immediately > concede a case where you might want a non-exception flow. Here are a > handful more examples off the top of my head: > > * Attempt to atomically lock and open file, returning either a file > handle or a "could not lock" status. > * Attempt to read from a file, terminate loop when the file handle > reaches EOF. > * Attempt to delete file, ignore if it doesn't exist. > > All of these are candidates for returning false, or an error code, or an > object in a particular status. They could be handled with exceptions, > but that would force common patterns to use exceptions for flow control, > which is generally seen as a "bad smell". > > > > Handling each and every error manually by using the return value > > requires a lot of discipline, which could be a very steep learning > > curve for PHP developers used to a fast prototyping language. > > > Again, I am not saying that every function should have a complex > error-handling system. It may well be sensible to have a function for > "open file, I don't expect anything to go wrong" which throws an > exception, and a separate one for "try to open file, and report the > result without ever triggering an exception". That's the point of > designing a new API, to work out what the use cases are, and cater for > them in a clean way. > > > Regards, > > -- > Rowan Tommins (n=C3=A9 Collins) > [IMSoP] > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > > --000000000000c505f705957feb25--