21

Everyone here should know the 'or' statemens, usually glued to an die() command:

$foo = bar() or die('Error: bar function return false.');

The most of the times we see something like:

mysql_query('SELECT ...') or die('Error in during the query');

However, i cant understand how exactly that 'or' statement works.

I would like to throw a new exception instead of die(), but:

try{
    $foo = bar() or throw new Exception('We have a problem here');

Doesnt work, and neither

$foo = bar() or function(){ throw new Exception('We have a problem here'); }

The only way i found to do that is this horrible thought:

function ThrowMe($mess, $code){
    throw new Exception($mess, $code);
}
try{
    $foo = bar() or ThrowMe('We have a problem in here', 666);
}catch(Exception $e){
    echo $e->getMessage();
}

But there is a way to throw a new exception directly after the 'or' statement?

Or this kind of structure is mandatory (i dont liek the ThrowMe function at all):

try{
    $foo = bar();
    if(!$foo){
        throw new Exception('We have a problem in here');
    }
}catch(Exception $e){
    echo $e->getMessage();
}

Edit: what i want is really to avoid the use of an if() check every potential dangerous operation i do, for example:

#The echo $e->getMessage(); is just an example, in real life this have no sense!
try{
    $foo = bar();
    if(!$foo){
        throw new Exception('Problems with bar()');
    }
    $aa = bb($foo);
    if(!$aa){
        throw new Exception('Problems with bb()');
    }
    //...and so on!
}catch(Exception $e){
    echo $e->getMessage();
}

#But i relly prefer to use something like:

try{
    $foo = bar() or throw new Exception('Problems with bar()');
    $aa = bb($foo) or throw new Exception('Problems with bb()');
    //...and so on!
}catch(Exception $e){
    echo $e->getMessage();
}

#Actually, the only way i figured out is:

try{
    $foo = bar() or throw new ThrowMe('Problems with bar()', 1);
    $aa = bb($foo) or throw new ThrowMe('Problems with bb()', 2);
    //...and so on!
}catch(Exception $e){
    echo $e->getMessage();
}

#But i'll love to thro the exception directly instead of trick it with ThrowMe function.
Strae
  • 18,807
  • 29
  • 92
  • 131

7 Answers7

36

or is just a logical operator, and it's analogous to ||.

The common trick of

mysql_query() or die();

could just as well be written

mysql_query() || die();

What happens here is the "logical or" operator (whichever you choose) is trying to determine if either operand evaluates to TRUE. This means the operands must be expressions that can be cast as a boolean.

So, the reason

bar() or throw new Exception();

is illegal, is because

(boolean)throw new Exception();

is also illegal. In essence, the process of throwing an exception doesn't generate a return value for the operator to check.

But calling a function does generate a return value for the operator to check (no explicit return value will result int the function returning NULL which casts as FALSE) which is why it works for you when you wrap exception throwing in a function.

NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
Peter Bailey
  • 105,256
  • 31
  • 182
  • 206
  • 4
    `or` is not analogous to `||`. The former has lower precedence than assignment and comparison. The latter has higher. This is a very important distinction because `$f = one() or two()` works very differently from `$f = one() || two()`. http://us3.php.net/manual/en/language.operators.precedence.php – Explosion Pills Jul 12 '11 at 00:15
  • 3
    Yes it is. "Analogous" doesn't mean "identical". That being said, your clarification is welcome :D – Peter Bailey Jul 12 '11 at 15:36
  • 1
    The error the bad syntax invokes is "Parse error: syntax error, unexpected T_THROW" – Jeff Clemens Jun 05 '14 at 19:50
3

I've simply defined the function toss for this.

function toss(Exception $exception): void
{
    throw $exception;
}

Because the file/line/stack information is captured when the exception is constructed (new) not thrown (throw) this doesn't interfere with the call stack.

So you can just do this.

something() or toss(new Exception('something failed'));
Dan Lugg
  • 20,192
  • 19
  • 110
  • 174
2

Why don't bar() and bb() throw the exceptions? In PHP Exceptions bubble up, so there's no need to throw the exception in the function/method where you call bar()/bb(). These exceptions may be thrown by bar()/bb(). In case you want to throw another exception, you can simply do:

function foo() {
    try {
        $bar = bar();
    } catch (BarException) {
        throw new FooException;
    }
}
Ionuț G. Stan
  • 176,118
  • 18
  • 189
  • 202
  • Yes man, youre right, but what about, for example, the database functions? mysql_query()/pg_query()? For these i must use or the if() check, or the ThrowMe horrible function.. i just want to know if is possible doing id direclty without ThrowMe() – Strae Jul 31 '09 at 08:28
  • 1
    @DaNieL: You could use PDO for DB access which can throw exceptions itself. – Tom Haigh Jul 31 '09 at 08:35
  • 1
    Well, it's not possible. I've tried it myself some time ago and no chance. PHP is a useful tool, but it also has one of the most stupid parsers and interpreters in the world. – Ionuț G. Stan Jul 31 '09 at 08:39
  • Anyway, if you strive to abstract your application, you shouldn't have that many calls to `mysql_query()` or whatever. You should build your own layer of utilities on top of PHP so that you can mask all its idiosyncrasies. – Ionuț G. Stan Jul 31 '09 at 08:41
  • @Tom: Sorry, tryed PDO a lot and i dont ahve a good consideration of it, this is an example of the motivation: http://stackoverflow.com/questions/833510/php-pdobindparam-data-types-how-does-it-work Im building up my 'lite, small and fast' PDO interpretation ;) @lonut: so we have another thing to add in the php6 whishlist? – Strae Jul 31 '09 at 08:53
  • @DaNieL, there would be lots of things for the PHP6 wish list, but I don't actually see the internals considering that many of them. At this time on the internals mailing list is discussed an RFC which proposes the replacement of errors with exceptions in built-in functions/classes. And it's very unlikely that it will get accepted. – Ionuț G. Stan Jul 31 '09 at 09:02
2

A solution I found that can replace "or die()" everywhere is to wrap the throw with a anonymous function that gets called immediately by call_user_func:

call_user_func(function(){
    throw new Exception("ERROR");
});

You can see that it works by executing this on a dummy script:

false or call_user_func(function(){throw new Exception("ERROR");});
1

I think you want to use something like the last structure, although there's really no point in using exceptions for that:

$foo = bar();
if(!$foo){
    echo 'We have a problem in here';
}

Per comment - I don't think you can do that in a single line (i.e. without the if(!$foo) check), and I agree that the exception throwing method is pretty horrible. Personally, I prefer the explicitness of:

$foo = bar();
if(!$foo){
    throw new Exception('We have a problem in here');
}

but that's a personal preference. If you want the single-line thing, I think you'll have to go with your exception-throwing function option.

I guess this limitation is probably down to PHP's dynamic-typing stuff, it can cast the results of a function call to a conditional, but not the results of a throw.

Dominic Rodger
  • 97,747
  • 36
  • 197
  • 212
  • No, i dont want to. The echo is just for example, in real life never echo the error message or code but handle them differently. What i want is exactly avoiding the if(!$foo) check every time. – Strae Jul 31 '09 at 08:11
1

Here's a single-line solution without the extra function:

if (!($foo = bar())) throw new Exception('We have a problem here');
James
  • 11
  • 1
1

You can also create a custom exception class and use it's static constructor method instead of throw new Exception() construction.

Exception class:

class CustomException extends Exception {
  static public function doThrow($message = "", $code = 0, Exception $previous = null) {
    throw new Exception($message, $code, $previous);
  }
}

Usage:

try {

  $foo = bar() or CustomException::doThrow('Problems with bar()');
  $aa = bb($foo) or CustomException::doThrow('Problems with bb()');

} catch(Exception $e){
  echo $e->getMessage();
}

Note

If you are using PHP 7 and higher - you can rename static method doThrow() to simply throw(), since in PHP 7 and higher it's allowed to use reserved keywords as method names.

Andrey Rudenko
  • 1,271
  • 20
  • 34