# Using `throw` with expr or expr logic

- Thread: https://externals.io/message/15301
- Original archive: https://news-web.php.net/php.internals/15301
- Started by Sara Golemon on 2005-03-07T22:13:30+00:00
- Messages: 4
- RFC: throw expression (Implemented (PHP 8.0)) — https://externals.io/rfc/throw_expression.md
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #15301 — Sara Golemon — 2005-03-07T22:13:30+00:00

URL: https://externals.io/message/15301#15301

A user was asking about why he could perform statements such as:

$db = mysql_connect('localhost') or die('Unable to connect to database
server');

But not:

$db = new mysqli('localhost') or throw('Unable to connect to database
server');

The short answer, obviously, is that throw just doesn't behave that way.
Like echo(), it simply doesn't have a return value to give.

Then again.... neither do `die()` or `exit()`, yet they pretend to return
one....

I've tried out the patch below with `make test` and it doesn't complain of
anything.  Can a ZendHead take a look and ridicule or otherwise comment?

-Sara


Index: Zend/zend_compile.h
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.h,v
retrieving revision 1.302
diff -u -r1.302 zend_compile.h
--- Zend/zend_compile.h 11 Feb 2005 22:26:45 -0000 1.302
+++ Zend/zend_compile.h 7 Mar 2005 22:08:49 -0000
@@ -396,7 +396,7 @@
 void zend_do_try(znode *try_token TSRMLS_DC);
 void zend_do_begin_catch(znode *try_token, znode *catch_class, znode
*catch_var, zend_bool first_catch TSRMLS_DC);
 void zend_do_end_catch(znode *try_token TSRMLS_DC);
-void zend_do_throw(znode *expr TSRMLS_DC);
+void zend_do_throw(znode *result, znode *expr TSRMLS_DC);

 ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table,
zend_bool compile_time);
 ZEND_API zend_class_entry *do_bind_class(zend_op *opline, HashTable
*class_table, zend_bool compile_time TSRMLS_DC);
Index: Zend/zend_compile.c
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.c,v
retrieving revision 1.614
diff -u -r1.614 zend_compile.c
--- Zend/zend_compile.c 6 Mar 2005 16:22:02 -0000 1.614
+++ Zend/zend_compile.c 7 Mar 2005 22:08:49 -0000
@@ -1670,7 +1670,7 @@
  CG(active_op_array)->opcodes[try_token->u.opline_num].extended_value =
get_next_op_number(CG(active_op_array));
 }

-void zend_do_throw(znode *expr TSRMLS_DC)
+void zend_do_throw(znode *result, znode *expr TSRMLS_DC)
 {
  zend_op *opline;

@@ -1678,6 +1678,10 @@
  opline->opcode = ZEND_THROW;
  opline->op1 = *expr;
  SET_UNUSED(opline->op2);
+
+ result->op_type = IS_CONST;
+ result->u.constant.type = IS_BOOL;
+ result->u.constant.value.lval = 1;
 }

 ZEND_API void function_add_ref(zend_function *function)
Index: Zend/zend_language_parser.y
===================================================================
RCS file: /repository/ZendEngine2/zend_language_parser.y,v
retrieving revision 1.155
diff -u -r1.155 zend_language_parser.y
--- Zend/zend_language_parser.y 11 Feb 2005 22:26:45 -0000 1.155
+++ Zend/zend_language_parser.y 7 Mar 2005 22:08:49 -0000
@@ -110,7 +110,7 @@
 %token `T_RETURN` 
 %token `T_TRY` 
 %token `T_CATCH` 
-%token `T_THROW` 
+%right `T_THROW` 
 %token `T_USE` 
 %token `T_GLOBAL` 
 %right `T_STATIC` T_ABSTRACT `T_FINAL` T_PRIVATE `T_PROTECTED` T_PUBLIC
@@ -225,7 +225,6 @@
   `T_VARIABLE` ')' { zend_do_begin_catch(&$1, &$9, &$11, 1 TSRMLS_CC); }
   '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
   additional_catches { zend_do_mark_last_catch(&$7, &$18 TSRMLS_CC); }
- | `T_THROW` expr ';' { zend_do_throw(&$2 TSRMLS_CC); }
 ;


@@ -614,6 +613,7 @@
  | `T_ARRAY` '(' array_pair_list ')' { $$ = $3; }
  | '`' encaps_list '`'  { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); }
  | `T_PRINT` expr  { zend_do_print(&$$, &$2 TSRMLS_CC); }
+ | `T_THROW` expr  { zend_do_throw(&$$, &$2 TSRMLS_CC); }
 ;

 function_call

---

## #15302 — Marcus Boerger — 2005-03-07T22:39:39+00:00

URL: https://externals.io/message/15301#15302 · In reply to: #15301

Hello Sara,

  patch looks correct anyway Andi or Zeev is needed here

Monday, March 7, 2005, 11:13:30 PM, you wrote:

> A user was asking about why he could perform statements such as:

> $db = mysql_connect('localhost') or die('Unable to connect to database
> server');

> But not:

> $db = new mysqli('localhost') or throw('Unable to connect to database
> server');

> The short answer, obviously, is that throw just doesn't behave that way.
> Like echo(), it simply doesn't have a return value to give.

> Then again.... neither do `die()` or `exit()`, yet they pretend to return
> one....

> I've tried out the patch below with `make test` and it doesn't complain of
> anything.  Can a ZendHead take a look and ridicule or otherwise comment?

> -Sara


> Index: Zend/zend_compile.h
> ===================================================================
> RCS file: /repository/ZendEngine2/zend_compile.h,v
> retrieving revision 1.302
> diff -u -r1.302 zend_compile.h
> --- Zend/zend_compile.h 11 Feb 2005 22:26:45 -0000 1.302
> +++ Zend/zend_compile.h 7 Mar 2005 22:08:49 -0000
> @@ -396,7 +396,7 @@
>  void zend_do_try(znode *try_token TSRMLS_DC);
>  void zend_do_begin_catch(znode *try_token, znode *catch_class, znode
> *catch_var, zend_bool first_catch TSRMLS_DC);
>  void zend_do_end_catch(znode *try_token TSRMLS_DC);
> -void zend_do_throw(znode *expr TSRMLS_DC);
> +void zend_do_throw(znode *result, znode *expr TSRMLS_DC);

>  ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table,
> zend_bool compile_time);
>  ZEND_API zend_class_entry *do_bind_class(zend_op *opline, HashTable
> *class_table, zend_bool compile_time TSRMLS_DC);
> Index: Zend/zend_compile.c
> ===================================================================
> RCS file: /repository/ZendEngine2/zend_compile.c,v
> retrieving revision 1.614
> diff -u -r1.614 zend_compile.c
> --- Zend/zend_compile.c 6 Mar 2005 16:22:02 -0000 1.614
> +++ Zend/zend_compile.c 7 Mar 2005 22:08:49 -0000
> @@ -1670,7 +1670,7 @@
>   CG(active_op_array)->opcodes[try_token->u.opline_num].extended_value =
> get_next_op_number(CG(active_op_array));
>  }

> -void zend_do_throw(znode *expr TSRMLS_DC)
> +void zend_do_throw(znode *result, znode *expr TSRMLS_DC)
>  {
>   zend_op *opline;

> @@ -1678,6 +1678,10 @@
>   opline->opcode = ZEND_THROW;
>   opline->op1 = *expr;
>   SET_UNUSED(opline->op2);
> +
> + result->op_type = IS_CONST;
> + result->u.constant.type = IS_BOOL;
> + result->u.constant.value.lval = 1;
>  }

>  ZEND_API void function_add_ref(zend_function *function)
> Index: Zend/zend_language_parser.y
> ===================================================================
> RCS file: /repository/ZendEngine2/zend_language_parser.y,v
> retrieving revision 1.155
> diff -u -r1.155 zend_language_parser.y
> --- Zend/zend_language_parser.y 11 Feb 2005 22:26:45 -0000 1.155
> +++ Zend/zend_language_parser.y 7 Mar 2005 22:08:49 -0000
> @@ -110,7 +110,7 @@
>  %token `T_RETURN` 
>  %token `T_TRY` 
>  %token `T_CATCH` 
> -%token `T_THROW` 
> +%right `T_THROW` 
>  %token `T_USE` 
>  %token `T_GLOBAL` 
>  %right `T_STATIC` T_ABSTRACT `T_FINAL` T_PRIVATE `T_PROTECTED` T_PUBLIC
> @@ -225,7 +225,6 @@
>    `T_VARIABLE` ')' { zend_do_begin_catch(&$1, &$9, &$11, 1 TSRMLS_CC); }
>    '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
>    additional_catches { zend_do_mark_last_catch(&$7, &$18 TSRMLS_CC); }
> - | `T_THROW` expr ';' { zend_do_throw(&$2 TSRMLS_CC); }
>  ;


> @@ -614,6 +613,7 @@
>   | `T_ARRAY` '(' array_pair_list ')' { $$ = $3; }
>   | '`' encaps_list '`'  { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); }
>   | `T_PRINT` expr  { zend_do_print(&$$, &$2 TSRMLS_CC); }
> + | `T_THROW` expr  { zend_do_throw(&$$, &$2 TSRMLS_CC); }
>  ;

>  function_call




-- 
Best regards,
 Marcus                            mailto:helly@php.net

---

## #15303 — Andi Gutmans — 2005-03-08T02:38:56+00:00

URL: https://externals.io/message/15301#15303 · In reply to: #15301

Hey Sara,

Nothing to ridicule but there's a good reason that currently throw is a 
statement. It has to do with us not being able to clean up properly when 
we're within an expression as far as memory leaks, reference counting and 
other locks are concerned.
Theoretically your patch could be applied as it's not the worst thing 
(there are other existing situations where such edge cases could be 
triggered) but I think it's better to keep the current state. I'd also have 
to check if there aren't actually real additional problems (misbehaviors) 
that could occur.
I must say that I am debating with myself on this issue as syntactically 
it's nice but I'm worried of the implications. It requires some thorough 
analysis.

Andi

At 02:13 PM 3/7/2005 -0800, Sara Golemon wrote:
>A user was asking about why he could perform statements such as:
>
>$db = mysql_connect('localhost') or die('Unable to connect to database
>server');
>
>But not:
>
>$db = new mysqli('localhost') or throw('Unable to connect to database
>server');
>
>The short answer, obviously, is that throw just doesn't behave that way.
>Like echo(), it simply doesn't have a return value to give.
>
>Then again.... neither do `die()` or `exit()`, yet they pretend to return
>one....
>
>I've tried out the patch below with `make test` and it doesn't complain of
>anything.  Can a ZendHead take a look and ridicule or otherwise comment?
>
>-Sara
>
>
>Index: Zend/zend_compile.h
>===================================================================
>RCS file: /repository/ZendEngine2/zend_compile.h,v
>retrieving revision 1.302
>diff -u -r1.302 zend_compile.h
>--- Zend/zend_compile.h 11 Feb 2005 22:26:45 -0000 1.302
>+++ Zend/zend_compile.h 7 Mar 2005 22:08:49 -0000
>@@ -396,7 +396,7 @@
>  void zend_do_try(znode *try_token TSRMLS_DC);
>  void zend_do_begin_catch(znode *try_token, znode *catch_class, znode
>*catch_var, zend_bool first_catch TSRMLS_DC);
>  void zend_do_end_catch(znode *try_token TSRMLS_DC);
>-void zend_do_throw(znode *expr TSRMLS_DC);
>+void zend_do_throw(znode *result, znode *expr TSRMLS_DC);
>
>  ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table,
>zend_bool compile_time);
>  ZEND_API zend_class_entry *do_bind_class(zend_op *opline, HashTable
>*class_table, zend_bool compile_time TSRMLS_DC);
>Index: Zend/zend_compile.c
>===================================================================
>RCS file: /repository/ZendEngine2/zend_compile.c,v
>retrieving revision 1.614
>diff -u -r1.614 zend_compile.c
>--- Zend/zend_compile.c 6 Mar 2005 16:22:02 -0000 1.614
>+++ Zend/zend_compile.c 7 Mar 2005 22:08:49 -0000
>@@ -1670,7 +1670,7 @@
>   CG(active_op_array)->opcodes[try_token->u.opline_num].extended_value =
>get_next_op_number(CG(active_op_array));
>  }
>
>-void zend_do_throw(znode *expr TSRMLS_DC)
>+void zend_do_throw(znode *result, znode *expr TSRMLS_DC)
>  {
>   zend_op *opline;
>
>@@ -1678,6 +1678,10 @@
>   opline->opcode = ZEND_THROW;
>   opline->op1 = *expr;
>   SET_UNUSED(opline->op2);
>+
>+ result->op_type = IS_CONST;
>+ result->u.constant.type = IS_BOOL;
>+ result->u.constant.value.lval = 1;
>  }
>
>  ZEND_API void function_add_ref(zend_function *function)
>Index: Zend/zend_language_parser.y
>===================================================================
>RCS file: /repository/ZendEngine2/zend_language_parser.y,v
>retrieving revision 1.155
>diff -u -r1.155 zend_language_parser.y
>--- Zend/zend_language_parser.y 11 Feb 2005 22:26:45 -0000 1.155
>+++ Zend/zend_language_parser.y 7 Mar 2005 22:08:49 -0000
>@@ -110,7 +110,7 @@
>  %token `T_RETURN` 
>  %token `T_TRY` 
>  %token `T_CATCH` 
>-%token `T_THROW` 
>+%right `T_THROW` 
>  %token `T_USE` 
>  %token `T_GLOBAL` 
>  %right `T_STATIC` T_ABSTRACT `T_FINAL` T_PRIVATE `T_PROTECTED` T_PUBLIC
>@@ -225,7 +225,6 @@
>    `T_VARIABLE` ')' { zend_do_begin_catch(&$1, &$9, &$11, 1 TSRMLS_CC); }
>    '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
>    additional_catches { zend_do_mark_last_catch(&$7, &$18 TSRMLS_CC); }
>- | `T_THROW` expr ';' { zend_do_throw(&$2 TSRMLS_CC); }
>  ;
>
>
>@@ -614,6 +613,7 @@
>   | `T_ARRAY` '(' array_pair_list ')' { $$ = $3; }
>   | '`' encaps_list '`'  { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); }
>   | `T_PRINT` expr  { zend_do_print(&$$, &$2 TSRMLS_CC); }
>+ | `T_THROW` expr  { zend_do_throw(&$$, &$2 TSRMLS_CC); }
>  ;
>
>  function_call

---

## #15304 — Sara Golemon — 2005-03-08T04:57:15+00:00

URL: https://externals.io/message/15301#15304 · In reply to: #15303

> Nothing to ridicule but there's a good reason that currently throw is a 
> statement. It has to do with us not being able to clean up properly when 
> we're within an expression as far as memory leaks, reference counting and 
> other locks are concerned.
>
Ah, that makes perfect sense.  With `exit()`/die() the request is ending so 
any mess can be cleaned up and tossed out.  With a throw, there's every 
liklihood that execution is going to continue.

> Theoretically your patch could be applied as it's not the worst thing 
> (there are other existing situations where such edge cases could be 
> triggered) but I think it's better to keep the current state. I'd also 
> have to check if there aren't actually real additional problems 
> (misbehaviors) that could occur.
>
I wouldn't doubt that there are real showstoppers hiding behind that 
behavior.  Probably surmountable ones, but not as trivial as they first 
appeared when I was looking at it.

> I must say that I am debating with myself on this issue as syntactically 
> it's nice but I'm worried of the implications. It requires some thorough 
> analysis.
>
Agreed.  Syntacticly it'd be nice if throw were consistent in this regard, 
but it absolutely needs to be approached cautiously.

-Sara
