Deprecation of the Error Control Operator (@ symbol)

php.internals

Junade Ali

10 years ago
Hi all; I am looking to submit an RFC in order to remove the error suppression operator in PHP, namely the @ symbol. I am happy to implement this, although it is merely a concept so far. My reasons for looking to do this are: - the error suppression operator leads to developers being lazy about wrapping things in issets, try/catch blocks or not handling errors correctly - this leads to painful debugging for developers working on projects with high technical debt - it's slow (though admittedly not that much slower) - careless error suppression can be reduced by forcing developers to learn about how to properly handle errors - when the @ symbol is used to prepend database queries, when there is a genuine error, it can cause the rest of the script to run successfully causing data integrity issues. If developers were forced to handle errors correctly this would be less of an issue. - lastly, this operator can lead to scripts dying due to a fatal error without any explanation of why, leading to painful debugging; all because a developer was too lazy to wrap a variable in an isset. Aside from doing this, there are a number of alternatives: re-engineering the behaviour of the error suppression operator and potentially bringing into the scope of a function (e.g. silence()); this said, I still feel this would contain similar issues as it wouldn't address the underlying issues of lazy error suppression. Lastly, I recognise this will be a big change to PHP; but I feel it is necessary to enhance the quality of PHP error handling. Let's not forget that PHP managed to successfully deprecate the MySQL library. Looking forward to hearing your thoughts. Thanks

Mark Baker

10 years ago
On 31/12/2015 14:52, Junade Ali wrote:
> I am looking to submit an RFC in order to remove the error suppression > operator in PHP, namely the @ symbol.
While few and far between, there are still valid use cases for the suppression operator, for example when using curl
-- Mark Baker _________ |. \ \-3 |_J_/ PHP | || | __ | || |m| |m| I LOVE PHP

Dennis Birkholz

10 years ago
Hi all, Am 31.12.2015 um 15:52 schrieb Junade Ali:
> I am looking to submit an RFC in order to remove the error suppression > operator in PHP, namely the @ symbol.
before you can deprecate the @ operator, there is a lot of work to do beforehand. A lot of functions print warnings when they fail (in addition to returning false). All these warnings have to be removed and put into the matching error()/errno() functions. Before that there is no way to remove the @ operator. Otherwise you have to disable error reporting for warnings and that would be far worse than usage of @ currently is. Greets Dennis

Patrick ALLAERT

10 years ago
Le jeu. 31 déc. 2015 à 16:42, Dennis Birkholz <php@dennis.birkholz.biz> a écrit :
> Hi all, > > Am 31.12.2015 um 15:52 schrieb Junade Ali: > > I am looking to submit an RFC in order to remove the error suppression > > operator in PHP, namely the @ symbol. > > before you can deprecate the @ operator, there is a lot of work to do > beforehand. A lot of functions print warnings when they fail (in > addition to returning false). All these warnings have to be removed and > put into the matching error()/errno() functions. Before that there is no > way to remove the @ operator. Otherwise you have to disable error > reporting for warnings and that would be far worse than usage of @ > currently is. > > Greets > Dennis >
As Dennis said, there is a huge work to be done before that, not that it shouldn't prevent you from doing that RFC, but this one should therefor contains a list of all prerequisites and possibly links to all RFCs yours would depend on. Cheers, Patrick

Stas Malyshev

10 years ago
Hi!
> I am looking to submit an RFC in order to remove the error suppression > operator in PHP, namely the @ symbol.
I don't think it is a good idea, currently, for the following reasons: 1. A lot of functions produce error messages which may not be important in specific scenario, and the users should retain control over if they want them or not. Checking does not solve the problem, because a) it's a lot of unnecessary boilerplate code and b) the fact that you checked doesn't mean the situation is the same when you use what you checked - and race conditions are hard to debug. For some functions, you may not be even able to predict when they may output error messages - such as ones relaying them from third-party library. Of course, better way to handle them would be to return error status and use error reporting function, or have structured exception handling (or both) but it's not the case for many existing functions. 2. There are scenarios where @ saves a bunch of boilerplate code - simplest example: @$counts[$item]++; vs. if(!isset($counts[$item])) { $counts[$item] = 1; } else { $counts[$item]++; } Now imagine you have to write 20 of those - which is easier to write *and* read? Of course, one could argue the notice maybe should not be produced - but it is.
> Aside from doing this, there are a number of alternatives: re-engineering > the behaviour of the error suppression operator and potentially bringing > into the scope of a function (e.g. silence()); this said, I still feel this > would contain similar issues as it wouldn't address the underlying issues > of lazy error suppression.
I don't see how that would achieve anything but making it more verbose. The inherent problem is that some error reporting is unneeded in some contexts, while welcome in others. That's the problem that needs solving, the syntax is secondary to it.
> Lastly, I recognise this will be a big change to PHP; but I feel it is > necessary to enhance the quality of PHP error handling. Let's not forget > that PHP managed to successfully deprecate the MySQL library.
PHP did not just remove mysql library, it replaced it with better alternative. Which was well in place when the talk of the removal started. I agree that PHP error system could use a lot of improvement - in fact, it already started with move to exceptions and other changes - but it has to go much further before we could afford to remove @. I would say it definitely should not happen anywhere in 7.x line.
-- Stas Malyshev smalyshev@gmail.com

Bishop Bettini

10 years ago
On Thu, Dec 31, 2015 at 4:10 PM, Stanislav Malyshev <smalyshev@gmail.com> wrote:
> > The inherent problem is that some error reporting is unneeded in some > contexts, while welcome in others. That's the problem that needs > solving, the syntax is secondary to it. >
That hits the nail on the head. When triggered errors are unneeded, @ works beautifully. When they're needed, use a helper like from my third-party library <https://github.com/haldayne/fox/blob/master/src/CaptureErrors.php> to capture them: use Haldayne\Fox\CaptureErrors; $copy = new CaptureErrors(function ($a, $b) { return copy($a, $b); }); $okay = $copy('foo.txt', 'bar.txt'); if (! $okay) { throw new RuntimeException($copy->getCapturedErrors()->pop()->get('message')); } I am -1 on removing @ for 7.x series. But, I would be in favor of all changes that remove unnecessary error messages or add functionality to better work with error messages. In my mind, those are requisite steps before removing @. Thanks, bishop

Andrew Faulds

10 years ago
Hi Bishop, Bishop Bettini wrote:
> I am -1 on removing @ for 7.x series. But, I would be in favor of all > changes that remove unnecessary error messages or add functionality to > better work with error messages. In my mind, those are requisite steps > before removing @.
I agree here. It'd be nice if we could somehow catch errors in the same way we can with exception, but we don't have this just now. Problem is a I can't think of a non-messy way to make this work, at least not without going through every PHP extension and adding an identifier for different errors. One improvement, though, might be an @ equivalent that only silences a certain level of error. It's still too broad, but it's nonetheless better than the silence-all we have now. Thanks.
-- Andrea Faulds https://ajf.me/

Aaron Piotrowski

10 years ago
Hi Bishop,
> On Dec 31, 2015, at 3:48 PM, Bishop Bettini <bishop@php.net> wrote: > > I am -1 on removing @ for 7.x series. But, I would be in favor of all > changes that remove unnecessary error messages or add functionality to > better work with error messages. In my mind, those are requisite steps > before removing @. >
I am also very much in agreement with this. There are many conditions where a warning or other error is raised with no way to test for the condition that will trigger the error. Before the @ can be removed, either these errors need to be removed or they need to become an exception that can be caught. For example, I have the following code for writing to a non-blocking stream (assume $resource is a stream socket resource and $data is a string): // Error reporting suppressed since fwrite() emits E_WARNING if the pipe is broken or the buffer is full. $written = @fwrite($resource, $data); if (false === $written) { $message = 'Failed to write to stream.'; if ($error = error_get_last()) { $message .= sprintf(' Errno: %d; %s', $error['type'], $error['message']); } throw new FailureException($message); } There is no way of knowing if the stream buffer is full before calling fwrite(), resulting in a warning and 0 being returned. IMO, just 0 should be returned without issuing a warning. Aaron Piotrowski https://trowski.com @trowski2002

Sara Golemon

10 years ago
On Thu, Dec 31, 2015 at 1:10 PM, Stanislav Malyshev <smalyshev@gmail.com> wrote:
> I don't think it is a good idea, currently, for the following reasons: >
[::snip::] It terrifies me to say this, but I completely agree with Stas. ;) I can't personally remember the last time I used @ in any production code, but my one-offs are replete with them. It's a quintessentially PHP feature in its pragmatism. Okay, I'll put the thesaurus down. -Sara

Rasmus Lerdorf

10 years ago
On 01/04/2016 07:22 PM, Sara Golemon wrote:
> On Thu, Dec 31, 2015 at 1:10 PM, Stanislav Malyshev <smalyshev@gmail.com> wrote: >> I don't think it is a good idea, currently, for the following reasons: >> > [::snip::] > > It terrifies me to say this, but I completely agree with Stas. ;) > > I can't personally remember the last time I used @ in any production > code, but my one-offs are replete with them. It's a quintessentially > PHP feature in its pragmatism. > > Okay, I'll put the thesaurus down.
I'd be quite sad to see @ disappear as well. It was one of PHP's earliest features and its roots date back to mid-80's DOS batch files (before 1/3 of this list were born I would guess) -Rasmus

Zeev Suraski

10 years ago
> -----Original Message----- > From: Rasmus Lerdorf [mailto:rasmus@lerdorf.com] > Sent: Tuesday, January 05, 2016 7:28 AM > To: Sara Golemon; Stanislav Malyshev > Cc: Junade Ali; PHP internals > Subject: Re: [PHP-DEV] Deprecation of the Error Control Operator (@ > symbol) > > On 01/04/2016 07:22 PM, Sara Golemon wrote: > > On Thu, Dec 31, 2015 at 1:10 PM, Stanislav Malyshev > <smalyshev@gmail.com> wrote: > >> I don't think it is a good idea, currently, for the following reasons: > >> > > [::snip::] > > > > It terrifies me to say this, but I completely agree with Stas. ;) > > > > I can't personally remember the last time I used @ in any production > > code, but my one-offs are replete with them. It's a quintessentially > > PHP feature in its pragmatism. > > > > Okay, I'll put the thesaurus down. > > I'd be quite sad to see @ disappear as well. It was one of PHP's earliest > features and its roots date back to mid-80's DOS batch files (before 1/3 > of > this list were born I would guess)
Same here. Zeev

Sara Golemon

10 years ago
On Thu, Dec 31, 2015 at 6:52 AM, Junade Ali <mjsa@junade.com> wrote:
> I am looking to submit an RFC in order to remove the error suppression > operator in PHP, namely the @ symbol. >
Forwarding a suggestion twitter/@Beryllium9: How about a global "disable error suppression" setting? That way a project lead could enforce it for their codebase (and guarantee that devs "aren't lazy"), but PHP doesn't lose its pragmatism? -Sara

Sara Golemon

10 years ago
On Mon, Jan 4, 2016 at 9:45 PM, Sara Golemon <pollita@php.net> wrote:
> On Thu, Dec 31, 2015 at 6:52 AM, Junade Ali <mjsa@junade.com> wrote: >> I am looking to submit an RFC in order to remove the error suppression >> operator in PHP, namely the @ symbol. >> > Forwarding a suggestion twitter/@Beryllium9: > > How about a global "disable error suppression" setting? That way a > project lead could enforce it for their codebase (and guarantee that > devs "aren't lazy"), but PHP doesn't lose its pragmatism? >
And to add to that, we have mechanisms to allow settings to be dialed one way but not another, so this could be made so that you can always re-enable suppressed errors, but you can never re-hide them. (open_basedir does something similar) -Sara

Dustin Wheeler

10 years ago
Hi, chiming in from the side, On Tue, Jan 5, 2016 at 12:45 AM, Sara Golemon <pollita@php.net> wrote:
> Forwarding a suggestion twitter/@Beryllium9: > > How about a global "disable error suppression" setting? That way a > project lead could enforce it for their codebase (and guarantee that > devs "aren't lazy"), but PHP doesn't lose its pragmatism? >
I think this is an excellent compromise worth discussion and can vouch for usage of this suggestion in our environment, today. I maintain a shared hosting environment of sorts and have many different developer groups working in that environment. This is the sort of configuration we would take advantage of immediately. Thanks twitter/@Beryllium9 (wherever you are!) + Sara,
-- Dustin Wheeler | Software Developer NC State University m: mdwheele@ncsu.edu | w: 5-9786 "If you don't know where you're going, it's easy to iteratively not get there."

Michael Heap

10 years ago
Sounds like the xdebug.scream or the Scream PECL extension ( https://pecl.php.net/package/scream) to me. +1 for baking this functionality into core On Tue, Jan 5, 2016 at 5:45 AM, Sara Golemon <pollita@php.net> wrote:

Derick Rethans

10 years ago
On Tue, 5 Jan 2016, Michael Heap wrote:
> > On Tue, Jan 5, 2016 at 5:45 AM, Sara Golemon <pollita@php.net> wrote: > > > On Thu, Dec 31, 2015 at 6:52 AM, Junade Ali <mjsa@junade.com> wrote: > > > I am looking to submit an RFC in order to remove the error suppression > > > operator in PHP, namely the @ symbol. > > > > > Forwarding a suggestion twitter/@Beryllium9: > > > > How about a global "disable error suppression" setting? That way a > > project lead could enforce it for their codebase (and guarantee that > > devs "aren't lazy"), but PHP doesn't lose its pragmatism?
> Sounds like the xdebug.scream or the Scream PECL extension ( > https://pecl.php.net/package/scream) to me. > > +1 for baking this functionality into core
That's going to mean an INI setting.. that hosters could abuse. Having an INI setting like this as part of core is IMO not a great idea. cheers, Derick
-- http://derickrethans.nl | http://xdebug.org Like Xdebug? Consider a donation: http://xdebug.org/donate.php twitter: @derickr and @xdebug Posted with an email client that doesn't mangle email: alpine

Zeev Suraski

10 years ago
> -----Original Message----- > From: Derick Rethans [mailto:derick@php.net] > Sent: Tuesday, January 05, 2016 12:57 PM > To: Michael Heap > Cc: Sara Golemon; Junade Ali; PHP internals > Subject: Re: [PHP-DEV] Deprecation of the Error Control Operator (@ > symbol) > > On Tue, 5 Jan 2016, Michael Heap wrote: > > > > > On Tue, Jan 5, 2016 at 5:45 AM, Sara Golemon <pollita@php.net> wrote: > > > > > On Thu, Dec 31, 2015 at 6:52 AM, Junade Ali <mjsa@junade.com> wrote: > > > > I am looking to submit an RFC in order to remove the error > > > > suppression operator in PHP, namely the @ symbol. > > > > > > > Forwarding a suggestion twitter/@Beryllium9: > > > > > > How about a global "disable error suppression" setting? That way a > > > project lead could enforce it for their codebase (and guarantee that > > > devs "aren't lazy"), but PHP doesn't lose its pragmatism? > > > Sounds like the xdebug.scream or the Scream PECL extension ( > > https://pecl.php.net/package/scream) to me. > > > > +1 for baking this functionality into core > > That's going to mean an INI setting.. that hosters could abuse. Having
an INI
> setting like this as part of core is IMO not a great idea.
I agree. Perhaps through a declare() statement instead? We could easily make it file-based, so that the declare() statement only affects the local file, or we could make it global for the entire request. Zeev

Grzegorz Zdanowski

10 years ago
>> -----Original Message----- >> From: Derick Rethans [mailto:derick@php.net] >> Sent: Tuesday, January 05, 2016 12:57 PM >> To: Michael Heap >> Cc: Sara Golemon; Junade Ali; PHP internals >> Subject: Re: [PHP-DEV] Deprecation of the Error Control Operator (@ >> symbol) >> >> On Tue, 5 Jan 2016, Michael Heap wrote: >> >> > >> > On Tue, Jan 5, 2016 at 5:45 AM, Sara Golemon <pollita@php.net> wrote: >> > >> > > On Thu, Dec 31, 2015 at 6:52 AM, Junade Ali <mjsa@junade.com> wrote: >> > > > I am looking to submit an RFC in order to remove the error >> > > > suppression operator in PHP, namely the @ symbol. >> > > > >> > > Forwarding a suggestion twitter/@Beryllium9: >> > > >> > > How about a global "disable error suppression" setting? That way a >> > > project lead could enforce it for their codebase (and guarantee that >> > > devs "aren't lazy"), but PHP doesn't lose its pragmatism? >> >> > Sounds like the xdebug.scream or the Scream PECL extension ( >> > https://pecl.php.net/package/scream) to me. >> > >> > +1 for baking this functionality into core >> >> That's going to mean an INI setting.. that hosters could abuse. Having > an INI >> setting like this as part of core is IMO not a great idea. > > I agree. Perhaps through a declare() statement instead? We could easily > make it file-based, so that the declare() statement only affects the local > file, or we could make it global for the entire request. > > Zeev > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php >
I can't agree more - it's a pain such thing as @ exists. However we have a bigger issue here - a lot PHP function returns false AND raises E_WARNING. fopen, fwrite, fread, stream_select.... a lot of them which I use daily. Before deprecating @ operator I think we should make a RFC which cover unified setting to convert all E_* to exceptions (like PhpWarningException). I know it's just a temporary solution, because exception should be more specific, but it's a huge amount of work to replace all errors and warnings with proper exceptions. Of course it's possible to convert all errors and warnings to exceptions using set_error_handler(), but it will be next boilerplate code for all apps.
-- Cheers, Grzegorz Zdanowski.

Rowan Collins

10 years ago
Grzegorz Zdanowski wrote on 05/01/2016 12:27:
> Before deprecating @ operator I think we should make a RFC which cover > unified setting to convert all E_* to exceptions (like > PhpWarningException). I know it's just a temporary solution, because > exception should be more specific, but it's a huge amount of work to > replace all errors and warnings with proper exceptions.
This is definitely not the solution. I've seen this suggested a few times over the years, and every time people seem to miss a vital point: Warnings are not, in general, a fatal situation. A useful rule of thumb I heard for "should I throw an exception?" is "would I be happy to use a die() statement?" Even if you don't accept that, the main purpose of an exception is to force the code down a different path. (I've seen lots of discussions about exceptions being great because they have stack traces, but have never understood why any other mechanism couldn't also have those). In a few places, like the file-handle API, the Warning is accompanied by an invalid return value (usually false) and probably should be an exception - the code will definitely need to follow a different path, and dying would often be better than proceeding with an invalid handle (which will probably end up fatal later). But in many cases, an E_WARNING (or an E_NOTICE) really is just a warning - most code *doesn't* want to go down an alternative path, but it might want to log a message. In a few cases, code does want to go down a different path, and currently has to use the "error handler" infrastructure. In other cases, code wants to never log the message, and currently has to use the @ operator. The main problem, in my opinion, with the current system of "errors" (better called "messages") is that they provide only two pieces of identifying information: an integer representing severity, from a small list; and a string which may have placeholders, may change between versions, and does not come from a documented list. This means you can say "suppress everything with E_NOTICE severity" but not "suppress all array-assignment warnings"; and you can set up an error handler to convert everything into exceptions, but a handler to convert all file-handle warnings into exceptions would have to pattern-match every message string to identify them. The only way out of this that I can see is to replace the current string-based internal message APIs with something that forces the extension developer to pre-define a set of codes, and provide the substitution parameters for the error directly. This could then allow more information to be exposed to userland, and more granular stacking of handlers and configuration to mask off different types based on their codes. Regards,
-- Rowan Collins [IMSoP]

Sara Golemon

10 years ago
On Tue, Jan 5, 2016 at 3:57 AM, Zeev Suraski <zeev@zend.com> wrote:
>> From: Derick Rethans [mailto:derick@php.net] >> That's going to mean an INI setting.. that hosters could abuse. >> Having an INI setting like this as part of core is IMO not a great idea. >
I honestly don't understand why that's a bad idea. There are a LOT of settings that hosters could abuse, but as a general rule they don't, because it breaks client apps and clients leave. A hoster could just as easily install XDebug and turn that setting on. Are they doing that? Or are you, Derick Rethans, suggesting that installing XDebug is a bad idea? ;)
> I agree. Perhaps through a declare() statement instead? We could easily > make it file-based, so that the declare() statement only affects the local > file, or we could make it global for the entire request. >
Eh, feels very tomato-tomato to me. Trading in a line in php.ini/.htaccess/index.php for a line in index.php. Ultimately I'm the wrong person to defend this since I don't personally have a need for it, I was just trying to offer compromises. For context, I do believe the person suggesting it was thinking in terms of "Finding that fatal error that's been supressed." -Sara

Derick Rethans

10 years ago
On Tue, 5 Jan 2016, Sara Golemon wrote:
> On Tue, Jan 5, 2016 at 3:57 AM, Zeev Suraski <zeev@zend.com> wrote: > > >> From: Derick Rethans [mailto:derick@php.net] > >> That's going to mean an INI setting.. that hosters could abuse. > >> Having an INI setting like this as part of core is IMO not a great idea. > > > I honestly don't understand why that's a bad idea. There are a LOT of > settings that hosters could abuse, but as a general rule they don't, > because it breaks client apps and clients leave. > > A hoster could just as easily install XDebug and turn that setting on. > Are they doing that? > > Or are you, Derick Rethans, suggesting that installing XDebug is a bad idea? ;)
On a production environment, certainly not a good idea. cheers, Derick

Andrew Faulds

10 years ago
Hi Sara, Sara Golemon wrote:
> On Thu, Dec 31, 2015 at 6:52 AM, Junade Ali <mjsa@junade.com> wrote: >> I am looking to submit an RFC in order to remove the error suppression >> operator in PHP, namely the @ symbol. >> > Forwarding a suggestion twitter/@Beryllium9: > > How about a global "disable error suppression" setting? That way a > project lead could enforce it for their codebase (and guarantee that > devs "aren't lazy"), but PHP doesn't lose its pragmatism?
I don't think that would work out too well. Remember that many projects have error handles which convert all errors to exceptions: if you disable @ in those projects, wouldn't their code break? Thanks.
-- Andrea Faulds https://ajf.me/

Sara Golemon

10 years ago
On Tue, Jan 5, 2016 at 9:37 AM, Andrea Faulds <ajf@ajf.me> wrote:
>> How about a global "disable error suppression" setting? That way a >> project lead could enforce it for their codebase (and guarantee that >> devs "aren't lazy"), but PHP doesn't lose its pragmatism? > > I don't think that would work out too well. Remember that many projects have > error handles which convert all errors to exceptions: if you disable @ in > those projects, wouldn't their code break? >
Nope. Supressed errors already reach custom error handlers: https://3v4l.org/TG8aA -Sara

Ferenc Kovacs

10 years ago
On Tue, Jan 5, 2016 at 6:53 PM, Sara Golemon <pollita@php.net> wrote:
> On Tue, Jan 5, 2016 at 9:37 AM, Andrea Faulds <ajf@ajf.me> wrote: > >> How about a global "disable error suppression" setting? That way a > >> project lead could enforce it for their codebase (and guarantee that > >> devs "aren't lazy"), but PHP doesn't lose its pragmatism? > > > > I don't think that would work out too well. Remember that many projects > have > > error handles which convert all errors to exceptions: if you disable @ in > > those projects, wouldn't their code break? > > > Nope. > Supressed errors already reach custom error handlers: > https://3v4l.org/TG8aA >
sure and most projects check the error_reporting() level against the $errno like in the manual: if (!(error_reporting() & $errno)) { // This error code is not included in error_reporting return; } @ changes the error_reporting() level for that particular call, so those custom error handler won't throw exceptions for the suppressed errors but when you remove/nop @ their code would throwing stuff left and right.
-- Ferenc Kovács @Tyr43l - http://tyrael.hu

Sara Golemon

10 years ago
On Tue, Jan 5, 2016 at 10:09 AM, Ferenc Kovacs <tyra3l@gmail.com> wrote:
>> > I don't think that would work out too well. Remember that many projects >> > have >> > error handles which convert all errors to exceptions: if you disable @ >> > in >> > those projects, wouldn't their code break? >> > >> Nope. >> Supressed errors already reach custom error handlers: >> https://3v4l.org/TG8aA > > sure and most projects check the error_reporting() level against the $errno > like in the manual: > if (!(error_reporting() & $errno)) { > // This error code is not included in error_reporting > return; > } > > @ changes the error_reporting() level for that particular call, so those > custom error handler won't throw exceptions for the suppressed errors but > when you remove/nop @ their code would throwing stuff left and right. >
Today I learned... Okay, def a problem (for a specific set of circumstances). And one which makes me more amenable to Ze'ev declare() suggestion (on a per-request bases, not per-file) as anyone modifying a project's codebase for testing can also modify it to suppress those exceptions as needed and/or just not enable the custom error handler. -Sara

Aaron Piotrowski

10 years ago
> On Jan 5, 2016, at 12:22 PM, Sara Golemon <pollita@php.net> wrote: > > On Tue, Jan 5, 2016 at 10:09 AM, Ferenc Kovacs <tyra3l@gmail.com> wrote: >>>> I don't think that would work out too well. Remember that many projects >>>> have >>>> error handles which convert all errors to exceptions: if you disable @ >>>> in >>>> those projects, wouldn't their code break? >>>> >>> Nope. >>> Supressed errors already reach custom error handlers: >>> https://3v4l.org/TG8aA >> >> sure and most projects check the error_reporting() level against the $errno >> like in the manual: >> if (!(error_reporting() & $errno)) { >> // This error code is not included in error_reporting >> return; >> } >> >> @ changes the error_reporting() level for that particular call, so those >> custom error handler won't throw exceptions for the suppressed errors but >> when you remove/nop @ their code would throwing stuff left and right. >> > Today I learned... Okay, def a problem (for a specific set of > circumstances). And one which makes me more amenable to Ze'ev > declare() suggestion (on a per-request bases, not per-file) as anyone > modifying a project's codebase for testing can also modify it to > suppress those exceptions as needed and/or just not enable the custom > error handler. >
Exactly. There’s no need for a new ini setting, since an error handler can be written that ignores the current error level and throws an exception or does whatever the coder wants. Abuse is the only real problem with the @ operator. Coders use it in place of proper state or error checking. However, there are legitimate uses such as with fwrite, fopen, stream_select, etc. that Grzegorz Zdanowski and I pointed out. Before anything can be done with the @ operator, changes will need to be made to remove warnings for conditions that the code has no way of checking prior to calling these functions. Setting a custom error handler before calling these functions and removing the error handler afterwards is a clunky solution. Any proposal to remove the @ operator needs to address how functions issuing unavoidable warnings will be changed. Aaron Piotrowski https://trowski.com @trowski2002

Sara Golemon

10 years ago
On Tue, Jan 5, 2016 at 12:24 PM, Aaron Piotrowski <aaron@icicle.io> wrote:
> Before anything can be done with the @ operator, changes will need to > be made to remove warnings for conditions that the code has no way of > checking prior to calling these functions. >
I'd include pragmatism in that calculus. fopen() can technically be safely called, but only by adding a lot of boilerplate that makes code ugly. An @ suppression is perfectly reasonable provided the return value is sanity checked. -Sara

Derick Rethans

10 years ago
On Tue, 5 Jan 2016, Sara Golemon wrote:
> On Tue, Jan 5, 2016 at 12:24 PM, Aaron Piotrowski <aaron@icicle.io> wrote: > > > Before anything can be done with the @ operator, changes will need > > to be made to remove warnings for conditions that the code has no > > way of checking prior to calling these functions. > > > I'd include pragmatism in that calculus. fopen() can technically be > safely called, but only by adding a lot of boilerplate that makes code > ugly.
And susceptible to race conditions. cheers, Derick

Rowan Collins

10 years ago
Ferenc Kovacs wrote on 05/01/2016 18:09:
> sure and most projects check the error_reporting() level against the $errno > like in the manual: > if (!(error_reporting() & $errno)) { > // This error code is not included in error_reporting > return; > } > > @ changes the error_reporting() level for that particular call, so those > custom error handler won't throw exceptions for the suppressed errors but > when you remove/nop @ their code would throwing stuff left and right.
I'm lost - how does this validate the claim that building scream mode into core would lead to problems? We already have an ini setting which can change the error_reporting level, so any error handler relying on that is *already* subject to different behaviour in different environments. Any codebase which wants to ignore the settings of the environment would surely already omit that boilerplate, and thus be unaffected by the presence or functionality of the @ operator. Regards,
-- Rowan Collins [IMSoP]

Sara Golemon

10 years ago
On Tue, Jan 5, 2016 at 11:40 AM, Rowan Collins <rowan.collins@gmail.com> wrote:
>> @ changes the error_reporting() level for that particular call, so those >> custom error handler won't throw exceptions for the suppressed errors but >> when you remove/nop @ their code would throwing stuff left and right. > > > I'm lost - how does this validate the claim that building scream mode into > core would lead to problems? We already have an ini setting which can change > the error_reporting level, so any error handler relying on that is *already* > subject to different behaviour in different environments. Any codebase which > wants to ignore the settings of the environment would surely already omit > that boilerplate, and thus be unaffected by the presence or functionality of > the @ operator. >
Because no matter how high your error_reporting is set (globally, per-dir, or ini-set) the @ suppression operator temporarily resets it to zero. In psuedo-code the following two blocks are equivalent: @foo(); if (ini_get('scream')) { $old_reporting = error_reporting(0); } foo(); if (ini_get('scream')) { error_reporting($old_reporting); } So the argument being made is that being able to disable @ suppression means ignoring whatever value the developer/admin has set for error_reporting. -Sara (not taking a stand on whether that's a compelling argument, just clarifying it)

Rowan Collins

10 years ago
On 05/01/2016 19:55, Sara Golemon wrote:
> So the argument being made is that being able to disable @ suppression > means ignoring whatever value the developer/admin has set for > error_reporting.
Sure, that's what the setting would mean; just as setting error_reporting means ignoring somebody else's value of error_reporting. I don't see how that's an untintended consequence, or what it's got to do with choosing between declare() and ini_set(). Or maybe I'm just mudding multiple sub-threads now? Regards,
-- Rowan Collins [IMSoP]

Dan Ackroyd

10 years ago
On 31 December 2015 at 14:52, Junade Ali <mjsa@junade.com> wrote:
> Hi all; > > I am looking to submit an RFC in order to remove the error suppression > operator in PHP, namely the @ symbol. >
Hi Junade, TL:DR - I think just deprecating the silence operator without having a plan for something better is not going to happen. The below summarizes/repeats what has been said already, and suggests an alternative. ------ So, the problem with the silence operator isn't that it exists, it's that it silences all errors. @foo(); bar(); This silences all warnings/errors raise by the function 'foo'. Which is bad because the programmer probably only meant to silence a specific error or warning. Converting all the internal warnings and errors to exceptions without doing anything else is probably not a great idea. Say that foo has two error conditions which get changed to be two exceptions FileException and DNSException. The code would now look like: try { foo(); } catch (FileException $fe) { // This is not an error in this situation, execution can continue. } catch (DNSException $ne) { // This is not an error in this situation, execution can continue. } bar(); That is pretty horrific even with just two exceptions. In actual code, it would be even worse when there are multiple lines that need errors supprssing. To make it be acceptable, I think what is needed is somthing like the ability to supprress individual exceptions on a single line. // If FileException, NetworkException are thrown inside 'foo', // they are automatically // caught and execution continues to call bar() foo() suppress FileException, NetworkException; bar(); That would allow people to ignore specific exceptions without having a huge amount of boilerplate code that makes the actual code illegible. Possibly a more powerful technique would be needed, e.g.being able to specific an exception handler on a line by line basis.* // Execute function foo and if any exception is // raised, call the callable 'fooCallException' foo() raise 'fooRaiseException'; bar(); public function fooRaiseException(\Throwable $t) { if ($t instanceof FileException || $t instanceof NetworkException) { // This is not an error in this situation, execution can continue. return; } // Other exceptions are not acceptable. // Propagation of the exception should continue as normal. throw $t } The benefits of doing it like this are: * Any unexpected exceptions are not silenced. This avoids the problem of all errors being silenced when the programmer thought only a single one would be suppressed. * It would allow users to debug their code. Even if an error is suppressed by the raise callable for a line of code, it would still be userland code that can be stepped through with a debugger, and so you can see the exception inside the 'raise' function. * It leaves the code in a readable state, which having lots of try/catch blocks does not. * It allows separate modules to have their own way of handling errors, whereas set_error_handler is a per application setting. As I said at the start, I think we need to have more powerful error handling in place before deprecating the silence operator. If anyone wants to progress this RFC, what I think needs to happen is: * Work on something like the above 'raise' or 'suppress' exceptions so that there is an alternative to the internal warnings. * Work on a plan on how to migrate all internal errors/warnings to individual exceptions. The current way of using set_error_handler to convert warnings/errors into generic exceptions isn't good enough. People need file operations to raise a more specific 'FileException', to allow catching of individual types of error. I don't think it would be feasible to just have a massive BC break on this...so a cunning migration plan would be needed. * Figure out if the silence operator is then no longer needed when those two are done. Obviously the removal of the silence operator could only be done at a major version, however adding the individual 'raise' handling or allowing users to convert internal warnings/errors to specific exceptions could be done at minor versions, and probably should be, if you want to be able to plan to remove the silence operator for PHP 8/9. cheers Dan * This would be similar to Pythons 'temporarily suppressing warnings' but instead on a line-by-line basis rather than function basis. https://docs.python.org/2/library/warnings.html

Ryan Pallas

10 years ago
Hi Dan, On Wed, Jan 6, 2016 at 10:12 AM, Dan Ackroyd <danack@basereality.com> wrote:
> > > // If FileException, NetworkException are thrown inside 'foo', > // they are automatically > // caught and execution continues to call bar() > foo() suppress FileException, NetworkException; > bar(); > >
> That would allow people to ignore specific exceptions without having a > huge amount of boilerplate code that makes the actual code illegible. >
I like this suggestion a lot, it keeps the expected suppressions with the call that will be suppressing.
> Possibly a more powerful technique would be needed, e.g.being able to > specific an exception handler on a line by line basis.* > > > // Execute function foo and if any exception is > // raised, call the callable 'fooCallException' > foo() raise 'fooRaiseException'; > bar(); > > public function fooRaiseException(\Throwable $t) > { > if ($t instanceof FileException || > $t instanceof NetworkException) { > // This is not an error in this situation, execution can continue. > return; > } > > // Other exceptions are not acceptable. > // Propagation of the exception should continue as normal. > throw $t > } > >
I'm not sure I like this, because of a few things, it puts the suppressed exceptions in a separate location from the call getting suppressed. Also, having the function name as a string will make it harder to find in an IDE since go to definition won't work (and since functions aren't first class citizens as in javascript, we can't pass a raw name AFAIK) and admittedly this reasoning doesn't count, IDE makers can update their IDE to have go to definition work on strings after a raise keyword (however, this will get complicated if ANY callable works, IE ['class','method'] and 'class::method'). Its basically moving the boilerplate you didn't like into a function not connected to the call and allows accidental control flow changes. Think if I do "foo() raises 'fooRaiseException'" everywhere I call foo, but then in one place I need to suppress FileException and somewhere else I don't want to. Someone comes along and changes the fooRaiseException function and now the place where we need to know about FileException we no longer do. This is caused by 2 things: the "handler" for the exceptions isn't tied to the location where the exceptions happen, and "Find Usages" in an IDE will not find strings referencing the function (especially if built programmatically), again this second one is not valid because we shouldn't make decisions based on what IDEs support but what's best for the language. However I think its important to know the number of changes which will be required in IDEs to make the feature usable for the average developer (especially if someone from PHPStorm, NetBeans or ZendStudio came along and said it would be impossible to support a specific new feature in a usable way). The benefits of doing it like this are:
> > * Any unexpected exceptions are not silenced. This avoids the problem > of all errors being silenced when the programmer thought only a single > one would be suppressed. > > * It would allow users to debug their code. Even if an error is > suppressed by the raise callable for a line of code, it would still be > userland code that can be stepped through with a debugger, and so you > can see the exception inside the 'raise' function. > > * It leaves the code in a readable state, which having lots of > try/catch blocks does not. > > * It allows separate modules to have their own way of handling > errors, whereas set_error_handler is a per application setting. >
And what is the benefit of having either of these options being part of the language (IIUC, this would mean changes to the parser, lexer, compiler and run time) when it could be implemented in userland? function tryAndSuppress(callable $func, array $args = [], array $suppress = []) { try { $ret = call_user_func_array($func, $args); } catch (Throwable $e) { foreach ($suppress as $type) { if ($e instanceof $type) { return; } } throw $e; } return $ret; } $fh = tryAndSuppress('fopen', ['/path/to/some/file.ext', 'r'], ['FileNotFoundException']);
> > As I said at the start, I think we need to have more powerful error > handling in place before deprecating the silence operator. If anyone > wants to progress this RFC, what I think needs to happen is: > > * Work on something like the above 'raise' or 'suppress' exceptions so > that there is an alternative to the internal warnings. > > * Work on a plan on how to migrate all internal errors/warnings to > individual exceptions. The current way of using set_error_handler to > convert warnings/errors into generic exceptions isn't good enough. > People need file operations to raise a more specific 'FileException', > to allow catching of individual types of error. I don't think it would > be feasible to just have a massive BC break on this...so a cunning > migration plan would be needed. >
Agree with this 100%. While I think errors suck and should all be turned into exceptions, I also think the exceptions used need to be meaningful. ~ Ryan

Dan Ackroyd

10 years ago
On 6 January 2016 at 18:55, Ryan Pallas <derokorian@gmail.com> wrote:
> Hi Dan, >
> having the function name as a string will make it harder to find in an IDE > since go to definition won't work (and since functions aren't first class > citizens as in javascript, we can't pass a raw name AFAIK)
Yes, this is a limition of PHP currently. As it does keep coming up I think this is something that needs to be addressed, but would need to be done in a separate RFC. For this particular case, I don't think it should be a problem. The IDE should be able to know that the handler is a callable as that is the only thing that would be allowed there.
> And what is the benefit of having either of these options being part of the language
Er......I don't think implementing it in userland like you sugggest is workable. It would mean calling code would look like: tryAndSuppress('mkdir', ['/path/to/some', 0755, true], ['IOException']); $fh = tryAndSuppress('fopen', ['/path/to/some/file.ext', 'r'], ['FileNotFoundException']); for almost all code, which looks horrible, and breaks all static analysis tools.
> in one place I need to suppress FileException and somewhere > else I don't want to.
If/when I write this up as an RFC, I'm going to suggest having two built-in functions that make it easy and safe to do the normal things that code does over and over again; convert a generic exception type to a more specific one, and suppress certain exceptions. See below for outline implementations of those two functions.
> Someone comes along and changes the fooRaiseException > function and now the place where we need to know about FileException we no > longer do.
I know what you mean, but the same is true of all code that is not called directly. For example in routing for HTTP applications, the routes are setup and then called dynamically. Yes, if someone changes what the code does in the callable, then what the application does changes. Additionally with the 'suppress' and 'convert' function below, then most people shouldn't need need to use custom functions. But also, in general, I think it's a mistake to limit the power of a programming langauge to make in universally safe to use. At least to some extent, if a feature can never be misused, then it's probably not powerful enough. Stuff needs to be safe to use by default, but if people want to do crazy stuff, we shouldn't delibrately stop them aka “You can't give her that!' she screamed. 'It's not safe!' IT'S A SWORD, said the Hogfather. THEY'RE NOT MEANT TO BE SAFE. 'She's a child!' shouted Crumley. IT'S EDUCATIONAL. 'What if she cuts herself?' THAT WILL BE AN IMPORTANT LESSON.” ― Terry Pratchett, Hogfather cheers Dan This is some example code, that uses the suppress and convert functions below to suppress any IOException raised by mkdir, and then convert and IOException generated by file_put_contents into a SavingDataException function saveData($directoryName, $data) { // If the directory already exists, that is mkdir($directoryName, 0755, true) raise suppress("IOException"); // Actually write the data. Failure to save gets converted // into a SavingDataException file_put_contents($directoryName."/foo.txt", $data) raise convert("SavingDataException", "IOException"); } // Returns a closure that suppresses any exception that matches // the listed types. function suppress(...$suppressedExceptions) { $fn = function (\Throwable $t) use ($suppressedExceptions) { foreach ($suppressedExceptions as $suppressedException) { if (is_a($t, $suppressedException) === true) { return; } } throw $t; }; return $fn; } // Returns a closure that converts all exceptions that are listed // into a new exception of the type '$newException'Type with the previous // exception set as the 'previous exception'. function convert($newExceptionType, ...$exceptionTypes) { $fn = function (\Throwable $t) use ($exceptionTypes) { foreach ($exceptionTypes as $exceptionType) { if (is_a($t, $exceptionType)) { throw new $newExceptionType( $t->getMessge(), $t->getCode(), $t ); } } throw $t; }; return $fn; }

Rowan Collins

10 years ago
Dan Ackroyd wrote on 06/01/2016 17:12:
> Work on a plan on how to migrate all internal errors/warnings to > individual exceptions. The current way of using set_error_handler to > convert warnings/errors into generic exceptions isn't good enough.
Again, you're focussing exclusively on that sub-set of warnings which are actually errors in disguise. I think it would be perfectly reasonable to implement a new file handling API, which behaves like modern PHP (objects, exceptions, etc) rather than being a thin wrapper for C (which is why fopen() does what it does). There'd then be no particular need to "suppress" any exceptions thrown from that, because if the handle is invalid, you actually need to do something different in the catch clause. In the current C-based API, the "catch" is the "if ( $fh === false )"; the warning is actually superfluous, hence the desire to suppress it. But this doesn't actually present a solution to the dozens of other warnings and notices. It doesn't do anything to help Stas's example for instance: @$counts[$item]++; This is not something which should ever throw an exception, however easy that exception was to discard. On the other hand, the "suppress" operator might be usable in conjunction with categorised warnings; e.g. $counts[$item]++ suppress ET_ARRAY_NOSUCHKEY; I would also contend that a correctly thrown exception should never be something you want to just suppress - at the very least, you want to log it, and probably you want to skip or add some logic. For instance, this makes no sense to me: $db = new PDO($dsn) suppress PDO_Exception; // oops, now I have to check if $db instanceof PDO, rather than just jumping to catch/finally @ doesn't suppress exceptions, nor does it stop fatal errors being fatal; nor should its replacement. Regards,
-- Rowan Collins [IMSoP]

Dan Ackroyd

10 years ago
On 8 January 2016 at 15:48, Rowan Collins <rowan.collins@gmail.com> wrote:
> > It doesn't do anything to help Stas's example for instance: > > @$counts[$item]++;
I think that that code is bogus since the release of PHP 7, which made it trivial to not use the error suppression for this case, while still writing code that doesn't take up multiple lines. $counts[$item] ?? $counts[$item] = 1 ?? $counts[$item]++; Yes - it's a few more characters but it has another benefit:
> This is not something which should ever throw an exception,
Oh yes, it definitely should: $item = new StdClass; @$counts[$item] = "This is a bad use of error suppression."; There is no insertion, because arrays don't support object keys. The operation completly failed and so there should be an exception. Currently that code fails silently.
> I think it would be perfectly reasonable to implement a new file handling API, which behaves like > modern PHP (objects, exceptions, etc) rather than being a thin wrapper for C > > I would also contend that a correctly thrown exception should never be > something you want to just suppress
I very much look forward to seeing your proposal for this file handling API, which is both easy to use, and never throws exceptions which people will want to discard. cheers Dan

Rowan Collins

10 years ago
Dan Ackroyd wrote on 08/01/2016 16:26:
> On 8 January 2016 at 15:48, Rowan Collins <rowan.collins@gmail.com> wrote: >> It doesn't do anything to help Stas's example for instance: >> >> @$counts[$item]++; > I think that that code is bogus since the release of PHP 7, which made > it trivial to not use the error suppression for this case, while still > writing code that doesn't take up multiple lines. > > $counts[$item] ?? $counts[$item] = 1 ?? $counts[$item]++;
It's a matter of code style; to me, that's still just noise. If I know that $counts is being used as a "hash" (arbitrary keys, defined on demand) and not a "struct" (pre-defined keys, accessed dynamically) then the first version does exactly what I want it to, and I see no advantage in making it more complex.
>> This is not something which should ever throw an exception, > Oh yes, it definitely should: > > $item = new StdClass; > @$counts[$item] = "This is a bad use of error suppression."; > > There is no insertion, because arrays don't support object keys. The > operation completly failed and so there should be an exception. > Currently that code fails silently.
OK, fine, let me reword that: the warning "undefined index 'foo'" should never be thrown as an exception. I am absolutely not saying that there aren't cases where we should be throwing Exceptions (or Errors, now they exist) rather than Warnings, just that there are also cases where warnings are non-fatal, and have nothing in common with Exceptions. The point of the example is not that the @ operator is perfect here, it's that sometimes, the ability to suppress specific warnings as "I know and don't care" is useful. I just wanted to get people away from the example of fopen() which frankly should never be raising a warning in the first place.
> I very much look forward to seeing your proposal for this file > handling API, which is both easy to use, and never throws exceptions > which people will want to discard.
I detect sarcasm here, and would like to hear a non-sarcastic version of your point. Can you give an example of an operation where it would be reasonable to throw an exception, but also reasonable (and common enough to affect the design of the API) to completely ignore that exception and carry on? If an operation has fatally failed (such as trying to open a non-existent file for reading), people will want to have code handling that failure, so suppressing the exception would be counter-productive; if an operation has encountered an unexpected but non-fatal condition, it should signal that with something other than an exception (for instance, returning a success boolean or status flag). Regards,
-- Rowan Collins [IMSoP]

Dan Ackroyd

10 years ago
On 8 January 2016 at 16:51, Rowan Collins <rowan.collins@gmail.com> wrote:
> I detect sarcasm here, and would like to hear a non-sarcastic version of > your point.
You're suggesting that we solve a problem in a way that pretty much every other attempt to do has failed. I'm not going to be able to point to a single reason why attempting that solution is not going to work, as the problem comes from the result of many small problems, none of which are a complete show stopper individually. But what you're doing is saying "Why don't we solve it like this? I can't see how difficult it could be". It's a tactic that has(, even if you didn't mean to,) a tendency to shut down a particular conversation until another branch of the conversation has been pursued. I do encourage you to try to attempt to make that API - it's only by encountering all of the small problems that you can realise that although they are not perfect, exceptions allow much nicer APIs than error checking. Or alternatively you might prove me wrong! and we end up with a much better solution!
> if an operation has encountered an unexpected but non-fatal condition, > it should signal that with something other than an exception (for > instance, returning a success boolean or status flag).
This is a big bit of the problem. Having to remember to check for errors make the api difficult to use. If you ever forget to check for an error condition, then you have a bug in your code. And people are not perfect, so people forget stuff....which is a bad start. And it gets really annoying when there are multiple error states e.g. for mkdir the operation can fail because: * The directory already exists. * The program doesn't have permission to create the directory. * You're trying to create a sub-directory of a directory that doesn't exist and forgot to set the '$parent = true' flag. So, now the programmer needs to be able to query what type of error happened. But worse than that, what happens when there is a new error condition is added to any function? All code that was written before the new error condition was added needs to be updated to check for the new error condition. Exceptions don't have these problems. If you forget to try/catch an exception it bubble up and fatals your program, which is much better than continuing in an unknown error state. Individual error conditions can throw separate sub-types of exceptions, that indicate exactly what error condition occured, which is a very convenient way of allowing people to declare "These are the type of errors I can handle, all others I can't". If an new exception can be thrown from a function, then all existing programs continue to work as before. Again, if that new error condition is met, an exception is thrown, rather than blindly continuing in an error condition. Aka with exceptions, people writing code can say "These are the exceptions I can handle, all other error conditions are errors", whereas the logic is reversed for checking errors where it is a case of a user saying "These are the error conditions that need to fatal, all others are fine".
> Can you give an example of an operation where it would be > reasonable to throw an exception, but also reasonable (and common enough > to affect the design of the API) to completely ignore that exception and > carry on?
mkdir is a great example of something that has multiple error conditions. If you're trying to create a uniquely named directory, then the failure to create it is an error. If you want to just ensure a directory exists before putting a uniquely named file inside that directory, then the failure to create the directory through mkdir is not an error condition. As I said, this is not a water-tight argument against what you're suggesting. But saying it's "perfectly reasonable to implement" something in a way that every other attempt has failed....and not giving any details of how it would actually work, is not a fantastic contribution to a discussion. cheers Dan

Rowan Collins

10 years ago
Dan Ackroyd wrote on 08/01/2016 18:44:
> You're suggesting that we solve a problem in a way that pretty much > every other attempt to do has failed.
I'm not sure where you got the idea that I was suggesting anything of the sort.
> it's only by > encountering all of the small problems that you can realise that > although they are not perfect, exceptions allow much nicer APIs than > error checking.
I think you've completely misread what I said; here it is for reference:
> I think it would be perfectly reasonable to implement a new file > handling API, which behaves like modern PHP (objects, exceptions, etc)
I am advocating *for* the use of exceptions *in that particular case*. What I was saying, however, is that the question of how fopen() should signal failure is not the same question as how PHP should signal warnings. Since this discussion was about warnings, I was trying to move the discussion away from its focus on one set of APIs.
> If you forget to try/catch an exception it bubble up and fatals your > program, which is much better than continuing in an unknown error > state.
You're preaching to the choir here - I know exceptions are absolutely the right thing in many cases, and use them lots in my own code. I also know that they are not suited to every situation, and that "if you don't tell me otherwise, I will halt your program" is sometimes massive overkill. I think we're just talking completely at cross-purposes here; I'm not entirely sure what you thought I was advocating, but what I was actually saying is really simple: Exceptions are not the right solution to all the places that PHP currently has warnings, so a simplified catch statement ("suppress Exception") is not the right replacement for the @ operator. Regards,
-- Rowan Collins [IMSoP]

Stas Malyshev

10 years ago
Hi!
> $counts[$item] ?? $counts[$item] = 1 ?? $counts[$item]++;
This looks completely unreadable and I do not think it works: https://3v4l.org/PlAHH Seems to leave $counts as 1 always. But even if it didn't, I would never pass that on code review - it is very hard to understand what's going on and it is incredibly easy to break it. Doing such stuff is definitely not the solution, if you hate @, then if() is way better, at least it's clear.
> $item = new StdClass; > @$counts[$item] = "This is a bad use of error suppression."; > > There is no insertion, because arrays don't support object keys. The > operation completly failed and so there should be an exception.
No, there should not. If somebody tries to count garbage, I just don't want to count it. I don't care about it, it's garbage.
> Currently that code fails silently.
And that is exactly what I want it to do. Sometimes silent failure is *good*, I don't want to know about every little thing that could go wrong, I just want what's right to be done. Of course, your intent may be the opposite - but that's exactly the point, there's more than one use case.
-- Stas Malyshev smalyshev@gmail.com

Ryan Pallas

10 years ago
On Fri, Jan 8, 2016 at 11:21 AM, Stanislav Malyshev <smalyshev@gmail.com> wrote:
> Hi! > > > $counts[$item] ?? $counts[$item] = 1 ?? $counts[$item]++; > > This looks completely unreadable and I do not think it works: > https://3v4l.org/PlAHH > Seems to leave $counts as 1 always. But even if it didn't, I would never > pass that on code review - it is very hard to understand what's going on > and it is incredibly easy to break it. Doing such stuff is definitely > not the solution, if you hate @, then if() is way better, at least it's > clear. > > > $item = new StdClass; > > @$counts[$item] = "This is a bad use of error suppression."; > > > > There is no insertion, because arrays don't support object keys. The > > operation completly failed and so there should be an exception. > > No, there should not. If somebody tries to count garbage, I just don't > want to count it. I don't care about it, it's garbage.
I agree with Dan on this one. Trying to use an invalid type as a key should produce something. Your argument that its garbage and you don't care may be valid for a specific use case, but it may also be a bug in another case. IE: it wasn't supposed to be an object, and the wrong variable was used, but tracking down that error if nothing is produced when doing something defined as invalid will be hard. If you don't want to count garbage, then you should use if() if (!is_garbage($key)) @$count[$key]++;

Rowan Collins

10 years ago
Ryan Pallas wrote on 08/01/2016 18:29:
> I agree with Dan on this one. Trying to use an invalid type as a key > should produce something. Your argument that its garbage and you don't > care may be valid for a specific use case, but it may also be a bug in > another case
But that has nothing to do with using exceptions rather than some other mechanism. I am completely in favour of making warnings better categorised, and easier to handle, but exceptions are not the way to do that. It's a case of seeing nails because you're holding a hammer - exceptions exist, so people want to use them everywhere. Regards,
-- Rowan Collins [IMSoP]

Stas Malyshev

10 years ago
Hi!
> when doing something defined as invalid will be hard. If you don't want > to count garbage, then you should use if() > > if (!is_garbage($key)) @$count[$key]++;
And if you want to check, just do: if (is_garbage($key)) { throw Exception("Garbage!"); } Except in this case you know what's going on and when the exception is thrown and can do what you like, instead of your code just blowing up randomly with no warning. Or, alternatively, having to check for an exception each time you do an array access.
-- Stas Malyshev smalyshev@gmail.com

Dan Ackroyd

10 years ago
On 8 January 2016 at 18:21, Stanislav Malyshev <smalyshev@gmail.com> wrote:
> Hi!
> This looks completely unreadable and I do not think it works: > https://3v4l.org/PlAHH > Seems to leave $counts as 1 always. But even if it didn't, I would never > pass that on code review - it is very hard to understand what's going on > and it is incredibly easy to break it.
Apologies, it should be: $counts[$item] = ($counts[$item] ?? 0) + 1; Which both works, and to me, is more readable than the @ version, as it doesn't rely on the person reading it knowing what the magic behaviour PHP has when using an array that has not been set.
> it is very hard to understand what's going on > and it is incredibly easy to break it.
You've had many years getting used to the current way of doing things. At some point you should try to get used to new features.
> And that is exactly what I want it to do. Sometimes silent failure is > *good*, I don't want to know about every little thing that could go > wrong, I just want what's right to be done. > Of course, your intent may be the opposite - but that's exactly the > point, there's more than one use case.
Yes, yes, totally agreed. Sometimes you just want to be able to tell the computer, "I know what I'm doing, don't nag" which is why the @ is great, even though what it does might still use some improvement. cheers Dan

Rowan Collins

10 years ago
Dan Ackroyd wrote on 08/01/2016 18:36:
> Apologies, it should be: > > $counts[$item] = ($counts[$item] ?? 0) + 1; > > Which both works, and to me, is more readable than the @ version
As with the file-manipulation functions, I think you're focussing too much on the specific example and not on the general principle. If we go through every single Notice and Warning discussing its implications, when you might want to suppress it, when it should be considered fatal, etc, we'll be here forever. If there is even one Notice or Warning which is - subjectively - (a) useful, and (b) non-fatal if ignored, then "turn everything into an exception" is not a complete solution. Regards,
-- Rowan Collins [IMSoP]