Introduction
Currently, PHP requires a block body for catch clauses even when the caught
exception is not used. This results in unnecessary boilerplate code. This
RFC proposes allowing catch clauses without a body when the exception
variable is omitted.
Proposal
Allow the following syntax where the curly braces can be omitted when no
exception variable is specified and no handling is needed:
try {
// code that may throw
} catch (SomeError);
This would be equivalent to:
try {
// code that may throw
} catch (SomeError) {}
Motivation
Reduced Boilerplate: Eliminates unnecessary empty blocks when exceptions
only need to be caught and ignored.
Improved Readability: Makes the code more concise and focuses on the
important parts.
Backward Incompatible Changes
None. This is purely an additive change to the syntax.
Introduction
Currently, PHP requires a block body for catch clauses even when the caught exception is not used. This results in unnecessary boilerplate code. This RFC proposes allowing catch clauses without a body when the exception variable is omitted.
Proposal
Allow the following syntax where the curly braces can be omitted when no exception variable is specified and no handling is needed:
try {
// code that may throw
} catch (SomeError);This would be equivalent to:
try {
// code that may throw
} catch (SomeError) {}Motivation
Reduced Boilerplate: Eliminates unnecessary empty blocks when exceptions only need to be caught and ignored.
Improved Readability: Makes the code more concise and focuses on the important parts.Backward Incompatible Changes
None. This is purely an additive change to the syntax.
Hey Mihail,
Why would the catch (SomeError)
still be required if it isn’t used?
Cheers,
Nick
Hi, Nick!
It still would be required because we're catching this concrete exception.
Not catching all of throwables.
чт, 31 июл. 2025 г. в 10:43, Nick php@nicksdot.dev:
Introduction
Currently, PHP requires a block body for catch clauses even when the
caught exception is not used. This results in unnecessary boilerplate code.
This RFC proposes allowing catch clauses without a body when the exception
variable is omitted.Proposal
Allow the following syntax where the curly braces can be omitted when no
exception variable is specified and no handling is needed:try {
// code that may throw
} catch (SomeError);This would be equivalent to:
try {
// code that may throw
} catch (SomeError) {}Motivation
Reduced Boilerplate: Eliminates unnecessary empty blocks when exceptions
only need to be caught and ignored.
Improved Readability: Makes the code more concise and focuses on the
important parts.Backward Incompatible Changes
None. This is purely an additive change to the syntax.
Hey Mihail,
Why would the
catch (SomeError)
still be required if it isn’t used?Cheers,
Nick
Motivation
Reduced Boilerplate: Eliminates unnecessary empty blocks when exceptions only need to be caught and ignored.
Improved Readability: Makes the code more concise and focuses on the important parts.
Empty catch
blocks are a code-smell. If the try
block is not ready
to handle the exception, it should let the exception bubble up; not
silence it. I think we should not encourage this further.
Hey, Ayesh! Thank you for noticing an important point.
Of course, empty catch blocks are bad practice in most cases. But this
particular proposal is not intended to encourage these bad practices. I'm
just suggesting that you don't have to write an extra boiler plate at the
syntax level in situations where it's necessary.
чт, 31 июл. 2025 г. в 11:21, Ayesh Karunaratne ayesh@php.watch:
Motivation
Reduced Boilerplate: Eliminates unnecessary empty blocks when exceptions
only need to be caught and ignored.
Improved Readability: Makes the code more concise and focuses on the
important parts.Empty
catch
blocks are a code-smell. If thetry
block is not ready
to handle the exception, it should let the exception bubble up; not
silence it. I think we should not encourage this further.
Of course, empty catch blocks are bad practice in most cases. But this particular proposal is not intended to encourage these bad practices. I'm just suggesting that you don't have to write an extra boiler plate at the syntax level in situations where it's necessary.
From what I can tell, it's very rare to have empty catch blocks, and
even more being done rightfully. I'd be very suspicious if I came
across such code.
I think the extra boilerplate is actually a good thing, showing the
explicit intent to not catch the error. I get that the proposal is not
intended to encourage such a thing, but I agree with Ayesh: it would
definitely will.
Hello, Alexandre.
I've heard your concerns, but I don't think this proposal will encourage
other developers to ignore exceptions more often. Basically, even now,
nothing can stop a developer from ignoring exceptions. He can simply leave
the body of the capture block empty. And in this RFC is proposed just to
allow not to write extra brackets {}.
If we talk from the point of view of bad practices and applicability, then
the same nullsafe operator may encourage developers to check for null less
often. And this leads to problems, I personally observed this.
It seems to me that the issue of bad and good practices should be the
responsibility of developers. A programming language is just a tool. And
there are many ways in which it can be "badly" applied.
чт, 31 июл. 2025 г. в 11:51, Alexandre Daubois alex.daubois+php@gmail.com:
Of course, empty catch blocks are bad practice in most cases. But this
particular proposal is not intended to encourage these bad practices. I'm
just suggesting that you don't have to write an extra boiler plate at the
syntax level in situations where it's necessary.From what I can tell, it's very rare to have empty catch blocks, and
even more being done rightfully. I'd be very suspicious if I came
across such code.I think the extra boilerplate is actually a good thing, showing the
explicit intent to not catch the error. I get that the proposal is not
intended to encourage such a thing, but I agree with Ayesh: it would
definitely will.
Introduction
Currently, PHP requires a block body for catch clauses even when the
caught exception is not used. This results in unnecessary boilerplate code.
This RFC proposes allowing catch clauses without a body when the exception
variable is omitted.Proposal
Allow the following syntax where the curly braces can be omitted when no
exception variable is specified and no handling is needed:
Hey!
I even tried recently to code it. Looked really good and I thought about
publishing it and creating the RFC.
I have use-cases where I need to try to send a request to a server and
forget about an exception if so:
try { $client->post(...); }
If it fails I'm ok with it.
For sure, there are many pitfalls when you allow users to ignore any
exceptions and errors, but it's up to users, right?
About the proposal:
try {
// code that may throw
} catch (SomeError);
How can I catch AnotherError?
try {
// code that may throw
} catch (SomeError)
catch (AnotherError) { ... }
OR
try {
// code that may throw
} catch (AnotherError) { ... }
catch (SomeError);
What about "finally" construction?
try {
// code that may throw
} catch (SomeError)
finally {}
Should the error flow into the "finally" construction?
--
Best regards,
Dmitrii Derepko.
@xepozz
Hi, Dmitry
I've been thinking about all these problems. I can't say a definite
decision yet, but I think it will be possible to discuss specific solutions
if the community approves this proposal in principle.
At the moment, I was thinking about a similar syntaxis.:
try {
} catch (ErrorA) catch (ErrorB) {
// some handling
}
or with finally:
try {
} catch (Error) finally {
// ...
}
чт, 31 июл. 2025 г. в 11:33, Dmitry Derepko xepozzd@gmail.com:
On Thu, Jul 31, 2025 at 7:55 AM Mihail Liahimov 91liahim@gmail.com
wrote:Introduction
Currently, PHP requires a block body for catch clauses even when the
caught exception is not used. This results in unnecessary boilerplate code.
This RFC proposes allowing catch clauses without a body when the exception
variable is omitted.Proposal
Allow the following syntax where the curly braces can be omitted when no
exception variable is specified and no handling is needed:Hey!
I even tried recently to code it. Looked really good and I thought about
publishing it and creating the RFC.I have use-cases where I need to try to send a request to a server and
forget about an exception if so:try { $client->post(...); }
If it fails I'm ok with it.
For sure, there are many pitfalls when you allow users to ignore any
exceptions and errors, but it's up to users, right?About the proposal:
try {
// code that may throw
} catch (SomeError);How can I catch AnotherError?
try {
// code that may throw
} catch (SomeError)
catch (AnotherError) { ... }OR
try {
// code that may throw
} catch (AnotherError) { ... }
catch (SomeError);What about "finally" construction?
try {
// code that may throw
} catch (SomeError)
finally {}Should the error flow into the "finally" construction?
--
Best regards,
Dmitrii Derepko.
@xepozz
Introduction
Currently, PHP requires a block body for catch clauses even when the caught exception is not used. This results in unnecessary boilerplate code. This RFC proposes allowing catch clauses without a body when the exception variable is omitted.
Proposal
Allow the following syntax where the curly braces can be omitted when no exception variable is specified and no handling is needed:
try {
// code that may throw
} catch (SomeError);This would be equivalent to:
try {
// code that may throw
} catch (SomeError) {}Motivation
Reduced Boilerplate: Eliminates unnecessary empty blocks when exceptions only need to be caught and ignored.
Improved Readability: Makes the code more concise and focuses on the important parts.Backward Incompatible Changes
None. This is purely an additive change to the syntax.
I can see something like this being useful in niche applications. For example, I have a proxy generation class that creates something like this:
public function remoteCall() {
$this->operation = nameof($this->remoteCall(...));
$this->arguments = func_get_args()
;
throw new SpecialException();
}
This SpecialException gets caught to let me know the application has consumed the one-use proxy. Using it looks something like
rpc(fn(RemoteObject $o) => $o->remoteCall());
which just provides type-safe rpc at the expense of some boilerplate.
I also use empty exceptions to "jump" the stack when my framework knows there is nothing more to do until outside events happen. I think I could probably use fibers to do the same, but if the user is using a fiber library; there is no guarantee they'll play nice together. This is true with exceptions as well, but the user has direct control over exceptions (do not catch Throwable, for instance).
That being said, I'm doing niche things. Outside of this framework/SDK, I have not ever really used empty catches, and even in my case, my empty catches have lengthy comments describing why they are empty in case a user steps into it, so they can better understand how the framework works.
— Rob
Hi, Rob!
Good point! I also know one another case when empty catch block are useful.
When we want to avoid returning null values, we resort to using exceptions
so that the client code can somehow handle the absence of values.
For example:
if ($user->getName() !== null) {
$this->doSomethingWithUserName($user->getName());
}
We usually add an exception inside such getters if there is no value:
try {
$this->doSomethingWithUserName($user->getName());
} catch (UserNameIsNull);
This is useful when we need to "do nothing" when there is no value. In my
opinion, this code looks more declarative.
We can do something like this also with repositories:
try {
$post = $this->postRepository->get($postId);
// do something with post
} catch (PostNotFound);
But again, there is a fine line between situations where an empty body of a
catch block is reasonable and when it is not.
чт, 31 июл. 2025 г. в 12:13, Rob Landers rob@bottled.codes:
even in my case, my empty catches have lengthy comments describing why
they are empty in case a user steps into it, so they can better understand
how the framework works.— Rob
Interesting catch, but i have been thinking of a better approach of
catching errors without the try and catch block madness.
Here is my suggestion:
try (Exception $e) {
// define logic
}
if ($e) {
// execute code...
}
looks way more clean and structured, what do y'all think?
Just a suggestion though.
Hi, Rob!
Good point! I also know one another case when empty catch block are useful.
When we want to avoid returning null values, we resort to using exceptions
so that the client code can somehow handle the absence of values.
For example:if ($user->getName() !== null) {
$this->doSomethingWithUserName($user->getName());
}We usually add an exception inside such getters if there is no value:
try {
$this->doSomethingWithUserName($user->getName());
} catch (UserNameIsNull);This is useful when we need to "do nothing" when there is no value. In my
opinion, this code looks more declarative.We can do something like this also with repositories:
try {
$post = $this->postRepository->get($postId);// do something with post
} catch (PostNotFound);But again, there is a fine line between situations where an empty body of
a catch block is reasonable and when it is not.чт, 31 июл. 2025 г. в 12:13, Rob Landers rob@bottled.codes:
even in my case, my empty catches have lengthy comments describing why
they are empty in case a user steps into it, so they can better understand
how the framework works.— Rob
Hi, Rob!
When we want to avoid returning null values, we resort to using exceptions
so that the client code can somehow handle the absence of values.
For example:if ($user->getName() !== null) {
$this->doSomethingWithUserName($user->getName());
}We usually add an exception inside such getters if there is no value:
try {
$this->doSomethingWithUserName($user->getName());
} catch (UserNameIsNull);
There will be TypeError because "doSomethingWithUserName" should accept
strings.
Using exceptions to check types is rough practice because exceptions aren't
cheap. "if" is cheaper.
This is useful when we need to "do nothing" when there is no value. In my
opinion, this code looks more declarative.We can do something like this also with repositories:
try {
$post = $this->postRepository->get($postId);// do something with post
} catch (PostNotFound);
Instead of idents inside another block I'd prefer to use early returns:
try {
-- ...
-- ...
-- ...
-- ...
-- ...
} catch (...)
vs
try {
-- ...
} catch (...) {
-- return
}
...
...
...
...
Or even "if"
if (!...) {
-- return ...
}
...
...
...
...
--
Best regards,
Dmitrii Derepko.
@xepozz
my empty catches have lengthy comments describing why they are empty in
case a user steps into it, so they can better understand how the framework
works.— Rob
Agree. I prefer to describe why I've wrote it:
try { ... } catch (...) {
/**
- We don't care If it's broken, because we should go further.
*/
}
A few cases from my side:
$decoded = [];
try {
$decoded = json_decode($unknownData, asArray: true);
} catch (JsonException);
Almost the same as
try {
$decoded = json_decode($unknownData, asArray: true);
} catch (JsonException) {
$decoded = [];
}
try {
doSmth()
} catch (RaceConditionException $e) {
// ok, skip 'cause another worker did the same
}
--
Best regards,
Dmitrii Derepko.
@xepozz
Am 31.07.2025 um 09:10 schrieb Rob Landers rob@bottled.codes:
I can see something like this being useful in niche applications. For example, I have a proxy generation class that creates something like this:
public function remoteCall() {
$this->operation = nameof($this->remoteCall(...));
$this->arguments =func_get_args()
;
throw new SpecialException();
}This SpecialException gets caught to let me know the application has consumed the one-use proxy. Using it looks something like
rpc(fn(RemoteObject $o) => $o->remoteCall());
which just provides type-safe rpc at the expense of some boilerplate.
I also use empty exceptions to "jump" the stack when my framework knows there is nothing more to do until outside events happen. I think I could probably use fibers to do the same, but if the user is using a fiber library; there is no guarantee they'll play nice together. This is true with exceptions as well, but the user has direct control over exceptions (do not catch Throwable, for instance).
I'm not 100% sure I understood your examples but this smells like you are using exceptions for flow (or maybe state?) control which I'm not sure I would encourage.
Regards,
- Chris
Am 31.07.2025 um 09:10 schrieb Rob Landers rob@bottled.codes:
I can see something like this being useful in niche applications. For example, I have a proxy generation class that creates something like this:
public function remoteCall() {
$this->operation = nameof($this->remoteCall(...));
$this->arguments =func_get_args()
;
throw new SpecialException();
}This SpecialException gets caught to let me know the application has consumed the one-use proxy. Using it looks something like
rpc(fn(RemoteObject $o) => $o->remoteCall());
which just provides type-safe rpc at the expense of some boilerplate.
I also use empty exceptions to "jump" the stack when my framework knows there is nothing more to do until outside events happen. I think I could probably use fibers to do the same, but if the user is using a fiber library; there is no guarantee they'll play nice together. This is true with exceptions as well, but the user has direct control over exceptions (do not catch Throwable, for instance).
I'm not 100% sure I understood your examples but this smells like you are using exceptions for flow (or maybe state?) control which I'm not sure I would encourage.
Regards,
- Chris
It's explicitely to jump/unwind the stack -- PHP has no other way (other than suspending a fiber or yielding a generator) to jump/unwind the stack to a given point. Fibers are the superior way here, but even then, throwing from the fiber is still the best way to terminate it and force a GC of the stack there. This is basically using it as a longjmp (in C terms) which PHP doesn't have any other way to express. They're not used for flow control, or state. They merely force PHP to unwind the stack to a known place (all possible side-effects have already been done and it is either throw -- or wait for an external event, potentially forever -- which consumes memory and a thread).
— Rob
They're not used for flow control, or state. They merely force PHP to
unwind the stack to a known place
I don't understand the distinction here; you want to continue code at a
particular point (control flow), and unwind the stack (state management).
That doesn't mean your use case isn't valid, but it's like saying "it's
not a knife, it's merely a sharpened metallic implement used to cut things".
--
Rowan Tommins
[IMSoP]
They're not used for flow control, or state. They merely force PHP to
unwind the stack to a known placeI don't understand the distinction here; you want to continue code at a
particular point (control flow), and unwind the stack (state management).
Unconditionally, yes. This is more like a bailout of user code, not throwing the exception would enter an infinite loop or cause an error. So, it’s kind of a gray area between flow control and exceptional.
That doesn't mean your use case isn't valid, but it's like saying "it's
not a knife, it's merely a sharpened metallic implement used to cut things".--
Rowan Tommins
[IMSoP]
lol. Fair enough.
— Rob
Reduced Boilerplate: Eliminates unnecessary empty blocks when
exceptions only need to be caught and ignored.
Improved Readability: Makes the code more concise and focuses on the
important parts.
The "boilerplate" in question is a single saved byte - ";" instead of
"{}". Depending on keyboard layout one or the other might be slightly
easier to type. Readability is always subjective, but I think most PHP
programmers would quite easily read "{}" as "do nothing".
I suspect the real motivation here is that coding standards require
more boilerplate than the language in this case, such as a newline
between the opening and closing brace.
But PHP is not Python, where whitespace is enforced by the compiler; nor
is it Go, where a coding standard is part of the standard library; so
this is not the right place to change coding standards. Even if we add
the short-hand syntax, there is nothing to stop those coding standards
forbidding its use.
As others have said, good uses of empty catch blocks are rare -
generally, you want to at least log that the exception happened, and
where it was caught. And even those which are functionally empty often
benefit from a comment explaining why they're not doing anything, which
sits naturally between the braces.
If for some reason your project is commonly using completely empty catch
blocks, you can document where and why "catch(Foo){}" is allowed in your
local coding standard.
--
Rowan Tommins
[IMSoP]
On Thu, Jul 31, 2025 at 10:11 AM Rowan Tommins [IMSoP] imsop.php@rwec.co.uk
wrote:
Reduced Boilerplate: Eliminates unnecessary empty blocks when
exceptions only need to be caught and ignored.
Improved Readability: Makes the code more concise and focuses on the
important parts.The "boilerplate" in question is a single saved byte - ";" instead of
"{}". Depending on keyboard layout one or the other might be slightly
easier to type. Readability is always subjective, but I think most PHP
programmers would quite easily read "{}" as "do nothing".I suspect the real motivation here is that coding standards require
more boilerplate than the language in this case, such as a newline
between the opening and closing brace.But PHP is not Python, where whitespace is enforced by the compiler; nor
is it Go, where a coding standard is part of the standard library; so
this is not the right place to change coding standards. Even if we add
the short-hand syntax, there is nothing to stop those coding standards
forbidding its use.As others have said, good uses of empty catch blocks are rare -
generally, you want to at least log that the exception happened, and
where it was caught. And even those which are functionally empty often
benefit from a comment explaining why they're not doing anything, which
sits naturally between the braces.If for some reason your project is commonly using completely empty catch
blocks, you can document where and why "catch(Foo){}" is allowed in your
local coding standard.--
Rowan Tommins
[IMSoP]
When I read catch (Foo);
I read the intention of it being on purpose,
whereas catch (Foo) {}
I can easily interpret as "the developer forgot to
handle the error" or "I can't tell if this is a bug or not". This often
requires something like:
try {
// ...
} catch (Foo) {
// do nothing
}
Now the boilerplate has increased from {} vs ; to quite some extra, just to
ensure the intention. I don't know if omitting the body for this is the
solution, or if there's something else we can do like: ignore(Foo, Bar)
.
When I read the code I want the intention to be clear, and an empty body
just makes me doubt whether or not it is intended and/or correct. I do
agree that empty catches are usually a sign of trouble, but realistically
speaking we don't always have control over the situation due to legacy or
vendor code.
Just tossing some ideas out here:
$foo = try $this->doSomething() ignore (Foo, Bar);
ignore(Foo, Bar) {
$foo = $this->doSomething();
} catch (Throwable) {
// ....
} finally {
// ...
}
try ignore(Foo, Bar) {
$foo = $this->doSomething();
} catch (Throwable) {
// ...
} finally {
// ...
}
When I read
catch (Foo);
I read the intention of it being on purpose,
whereascatch (Foo) {}
I can easily interpret as "the developer forgot to
handle the error" or "I can't tell if this is a bug or not". This often
requires something like:try { // ... } catch (Foo) { // do nothing }
I much more prefer the long version and I'd rather see this in my code than
just a semicolon or empty braces. If the developer must leave the catch
block empty they better have a pretty good reason and they should clearly
explain that in the code comment.
Now the boilerplate has increased from {} vs ; to quite some extra, just to
ensure the intention. I don't know if omitting the body for this is the
solution, or if there's something else we can do like:ignore(Foo, Bar)
.
When I read the code I want the intention to be clear, and an empty body
just makes me doubt whether or not it is intended and/or correct. I do
agree that empty catches are usually a sign of trouble, but realistically
speaking we don't always have control over the situation due to legacy or
vendor code.Just tossing some ideas out here:
$foo = try $this->doSomething() ignore (Foo, Bar); ignore(Foo, Bar) { $foo = $this->doSomething(); } catch (Throwable) { // .... } finally { // ... } try ignore(Foo, Bar) { $foo = $this->doSomething(); } catch (Throwable) { // ... } finally { // ... }
I read that as catch all exceptions apart from these which should bubble up
to the next exception handler. It could be useful in its own too.
I would vote NO to the proposal of short syntax for empty catch, not only
because it's bad practice but also because it's one of the places where
being very explicit is a good thing. An empty catch should be an eyesore
and have a mandatory comment. It's akin to a door with a sign "don't open"
versus a sign with "don't open, angry lions inside".
When I read
catch (Foo);
I read the intention of it being on
purpose, whereascatch (Foo) {}
I can easily interpret as "the
developer forgot to handle the error" or "I can't tell if this is a
bug or not".
As I say, readability is always subjective, but I would just see ";" vs
"{}" as a style choice, no obvious difference in intention. If anything,
it would risk me misreading the code, because I'd be looking for the
braces and not finding them.
A similar argument was made for keeping "var" as an alias of "public",
to indicate ... something; I argued against that reasoning at the
time: https://externals.io/message/91618#91634
I don't think the language needs to allow multiple ways of writing
everything, just so that projects can have subtle conventions of when to
use which one.
Now the boilerplate has increased from {} vs ; to quite some extra,
just to ensure the intention. I don't know if omitting the body for
this is the solution, or if there's something else we can do like:
ignore(Foo, Bar)
. When I read the code I want the intention to be
clear, and an empty body just makes me doubt whether or not it is
intended and/or correct.
If the aim is to make the intention explicit, we need some syntax that
makes the intention explicit, not just different punctuation we hope
will become established as a convention.
$foo = try $this->doSomething() ignore (Foo, Bar);
I think an inline syntax like this would be a powerful feature, and a
potential replacement for the @ operator:
$fh = null;
$fh = try fopen($filePath, 'w') ignore (FileLockedException);
One challenge would be optimising it so that the exception didn't build
a full stack trace then immediately discard it - this was touched on in
Larry's thread a while back https://externals.io/message/127188
--
Rowan Tommins
[IMSoP]
Am 31.07.2025 um 13:16 schrieb Rowan Tommins [IMSoP] imsop.php@rwec.co.uk:
I think an inline syntax like this would be a powerful feature, and a potential replacement for the @ operator:
$fh = null;
$fh = try fopen($filePath, 'w') ignore (FileLockedException);
First of all: I'm wary because partial error handling seems dangerous to mel do I know all possible Exception types and which ones should abort and which ones should continue? Or will it encourage try ... ignore (Exception)? I have to admit that I'm also a sceptic of converting every possible info/warning/error to an Exception but that's a different topic ;-)
If we decide to add something like the above I would very much prefer the try ... ignore block to be an expression with value null on error, making the first line obsolete. One could still use
$lines = try file($filepath) ignore (FileLockedException) ?? [];
if another default value is preferred.
Regards,
- Chris
$fh = try fopen($filePath, 'w') ignore (FileLockedException);
First of all: I'm wary because partial error handling seems dangerous to mel do I know all possible Exception types and which ones should abort and which ones should continue?
That's kind of the point: it's for when you know how to handle some
specific cases, but want anything else to abort.
In this hypothetical example, the code is using an exclusive lock to
avoid two processes writing to the file; it wants to gracefully handle
the specific scenario of "some other process has the lock". If there's
some other error, like "invalid file path", that should not be suppressed.
But the current PHP I/O functions give no way to distinguish:
$fh = @fopen($filePath, 'w');
if ( $fh === false ) {
// probably something else had the lock; could also be an invalid
file path, or a catastrophic disk failure ¯_(ツ)_/¯
}
I have to admit that I'm also a sceptic of converting every possible info/warning/error to an Exception but that's a different topic
I didn't intend to imply that this would replace all Warnings. Think of
it more as replacing the "returns false on error" part of the fopen()
signature.
If we decide to add something like the above I would very much prefer the try ... ignore block to be an expression with value null on error, making the first line obsolete.
Good point, I agree.
--
Rowan Tommins
[IMSoP]
Am 31.07.2025 um 17:53 schrieb Rowan Tommins [IMSoP] imsop.php@rwec.co.uk:
$fh = try fopen($filePath, 'w') ignore (FileLockedException);
First of all: I'm wary because partial error handling seems dangerous to mel do I know all possible Exception types and which ones should abort and which ones should continue?
That's kind of the point: it's for when you know how to handle some specific cases, but want anything else to abort.
In this hypothetical example, the code is using an exclusive lock to avoid two processes writing to the file; it wants to gracefully handle the specific scenario of "some other process has the lock". If there's some other error, like "invalid file path", that should not be suppressed.
But the current PHP I/O functions give no way to distinguish:
$fh = @fopen($filePath, 'w');
if ( $fh === false ) {
// probably something else had the lock; could also be an invalid file path, or a catastrophic disk failure ¯_(ツ)_/¯
}
If you have to handle null afterwards (e.g. avoiding writing to invalid $fh) then the "ignore" version does not really help much IMHO
Realistically I think it would be something like
if ($fh = try fopen($filePath, 'w') ignore (FileLockedException)) {
...
} [else
...]
vs. currently
try {
$fh = try fopen($filePath, 'w');
...
} catch (FileLockedException) {
[...]
}
which does not seem much clearer to me.
I didn't intend to imply that this would replace all Warnings. Think of it more as replacing the "returns false on error" part of the
fopen()
signature.
... so you would replace false for (some) errors by Exceptions, that's what I meant. Plus having some stuff return false and some things throw Exceptions seems weird too, that's why I said "all" in the first place. But false/null vs. Exceptions is a different, much broader topic, let's skip that for now ;-)
Regards,
- Chris
If you have to handle null afterwards (e.g. avoiding writing to invalid $fh) then the "ignore" version does not really help much IMHO
In a simple case, yes, but you don't necessarily want the check directly
under the fopen. Maybe you want to try opening multiple files, and
succeed if at least one is unlocked; or try in a loop; or try in the
constructor of an object, and handle it being null in a later method.
It's still mostly syntax sugar (and maybe a hint to the compiler to
optimise), but it's saving more than the original proposal, even
skipping newlines:
$fh=null; try { $fh = fopen($filePath, 'w'); } catch
(FileLockedException) {}
$fh = try fopen($filePath, 'w') ignore (FileLockedException);
But, I'm not volunteering to write a formal proposal, let alone an
implementation; I'm just exploring what kinds of short-hand might be useful.
--
Rowan Tommins
[IMSoP]
Proposal
Allow the following syntax where the curly braces can be omitted when no exception variable is specified and no handling is needed:
try {
// code that may throw
} catch (SomeError);
Can you write out how this would interoperate with the finally keyword?
Hi!
At the moment, I can suggest this syntax:
try {
// do something
} catch (SomeIgnorableException) finally {
// do something
}
I also generally like the above idea with the keyword ignore.
чт, 31 июл. 2025 г. в 20:24, Casper Langemeijer langemeijer@php.net:
Proposal
Allow the following syntax where the curly braces can be omitted when no
exception variable is specified and no handling is needed:try {
// code that may throw
} catch (SomeError);Can you write out how this would interoperate with the finally keyword?
Hey Mihail
Am 06.08.25 um 13:34 schrieb Mihail Liahimov:
Hi!
At the moment, I can suggest this syntax:
try {
// do something
} catch (SomeIgnorableException) finally {
// do something
}
I find that ... challenging
When reading the code I now have to go to the end of the line to
understand that the second
// do something
does not belong to the try
but to the finally
...
And
try {
// break stuff
} catch (SomeIgnorableException)
finally {
// do something regardless
}
seems boken due to the missing }
But well....
We just have to adapt to something like this:
try {
// break stuff
}
catch (SomeIgnorableException)
catch (Some OtherIgnorableException)
finally {
// do something regardless
}
--
,,,
(o o)
+---------------------------------------------------------ooO-(_)-Ooo-+
| Andreas Heigl |
| mailto:andreas@heigl.org N 50°22'59.5" E 08°23'58" |
| https://andreas.heigl.org |
+---------------------------------------------------------------------+
| https://hei.gl/appointmentwithandreas |
+---------------------------------------------------------------------+
| GPG-Key: https://hei.gl/keyandreasheiglorg |
+---------------------------------------------------------------------+
Yeah, it seems to be problematic to use this syntax with finally blocks.
Perhaps the optional catch block should be allowed only at the very end,
but it sounds somehow doubtful.
ср, 6 авг. 2025 г. в 16:52, Andreas Heigl andreas@heigl.org:
Hey Mihail
Am 06.08.25 um 13:34 schrieb Mihail Liahimov:
Hi!
At the moment, I can suggest this syntax:
try {
// do something
} catch (SomeIgnorableException) finally {
// do something
}I find that ... challenging
When reading the code I now have to go to the end of the line to
understand that the second// do something
does not belong to the
try
but to thefinally
...And
try {
// break stuff
} catch (SomeIgnorableException)
finally {
// do something regardless
}seems boken due to the missing }
But well....
We just have to adapt to something like this:
try {
// break stuff
}
catch (SomeIgnorableException)
catch (Some OtherIgnorableException)
finally {
// do something regardless
}--
,,,
(o o)
+---------------------------------------------------------ooO-(_)-Ooo-+
| Andreas Heigl |
| mailto:andreas@heigl.org N 50°22'59.5" E 08°23'58" |
| https://andreas.heigl.org |
+---------------------------------------------------------------------+
| https://hei.gl/appointmentwithandreas |
+---------------------------------------------------------------------+
| GPG-Key: https://hei.gl/keyandreasheiglorg |
+---------------------------------------------------------------------+
Yeah, it seems to be problematic to use this syntax with finally blocks. Perhaps the optional catch block should be allowed only at the very end, but it sounds somehow doubtful.
ср, 6 авг. 2025 г. в 16:52, Andreas Heigl andreas@heigl.org:
Hey Mihail
Am 06.08.25 um 13:34 schrieb Mihail Liahimov:
Hi!
At the moment, I can suggest this syntax:
try {
// do something
} catch (SomeIgnorableException) finally {
// do something
}I find that ... challenging
When reading the code I now have to go to the end of the line to
understand that the second// do something
does not belong to the
try
but to thefinally
...And
try {
// break stuff
} catch (SomeIgnorableException)
finally {
// do something regardless
}seems boken due to the missing }
But well....
We just have to adapt to something like this:
try {
// break stuff
}
catch (SomeIgnorableException)
catch (Some OtherIgnorableException)
finally {
// do something regardless
}--
,,,
(o o)
+---------------------------------------------------------ooO-(_)-Ooo-+
| Andreas Heigl |
| mailto:andreas@heigl.org N 50°22'59.5" E 08°23'58" |
| https://andreas.heigl.org |
+---------------------------------------------------------------------+
| https://hei.gl/appointmentwithandreas |
+---------------------------------------------------------------------+
| GPG-Key: https://hei.gl/keyandreasheiglorg |
+---------------------------------------------------------------------+
What about instead of at the end, we do it at the beginning?
try ignore (SomeIgnorableException, OtherException) {
// break stuff
} catch(UnexpectedException) {
// fix stuff
} finally {
// do this anyway
}
Since ignore only can follow a try and any symbol other than a "{" is currently an error, I don't think we don't need to reserve "ignore" as a keyword.
It appears to be relatively easy to scan/read as well.
— Rob
Yeah, it seems to be problematic to use this syntax with finally blocks. Perhaps the optional catch block should be allowed only at the very end, but it sounds somehow doubtful.
ср, 6 авг. 2025 г. в 16:52, Andreas Heigl andreas@heigl.org:
Hey Mihail
Am 06.08.25 um 13:34 schrieb Mihail Liahimov:
Hi!
At the moment, I can suggest this syntax:
try {
// do something
} catch (SomeIgnorableException) finally {
// do something
}I find that ... challenging
When reading the code I now have to go to the end of the line to
understand that the second// do something
does not belong to the
try
but to thefinally
...And
try {
// break stuff
} catch (SomeIgnorableException)
finally {
// do something regardless
}seems boken due to the missing }
But well....
We just have to adapt to something like this:
try {
// break stuff
}
catch (SomeIgnorableException)
catch (Some OtherIgnorableException)
finally {
// do something regardless
}--
,,,
(o o)
+---------------------------------------------------------ooO-(_)-Ooo-+
| Andreas Heigl |
| mailto:andreas@heigl.org N 50°22'59.5" E 08°23'58" |
| https://andreas.heigl.org |
+---------------------------------------------------------------------+
| https://hei.gl/appointmentwithandreas |
+---------------------------------------------------------------------+
| GPG-Key: https://hei.gl/keyandreasheiglorg |
+---------------------------------------------------------------------+What about instead of at the end, we do it at the beginning?
try ignore (SomeIgnorableException, OtherException) {
// break stuff
} catch(UnexpectedException) {
// fix stuff
} finally {
// do this anyway
}Since ignore only can follow a try and any symbol other than a "{" is currently an error, I don't think we don't need to reserve "ignore" as a keyword.
It appears to be relatively easy to scan/read as well.
— Rob
Sorry, it should have read: "I don't think we need to reserve "ignore" as a keyword".
— Rob