Hi,

On Fri, Sep 23, 2011 at 14:06, Daniel K. <d...@uw.no> wrote:
> When a built-in function is defined with ZEND_SEND_PREFER_REF, PHP will
> issue a strict warning if you use an assignment expression as the parameter.
>
> As an example, current() show this behaviour.
>
> current() has this arginfo defined:
>
> ZEND_BEGIN_ARG_INFO(arginfo_current, ZEND_SEND_PREFER_REF)
>    ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, arg)
> ZEND_END_ARG_INFO()
>
> and a call like:
>
> <?php
> current($foo = array("bar"));
> ?>
>
> Presents you with:
>
> PHP Strict Standards:  Only variables should be passed by reference in
> %s on line %d
>
>
> I think it is wrong to warn about this, because, to me, the _PREFER_
> part of ZEND_SEND_PREFER_REF, conveys that we should prefer to pass by
> reference, if possible, and not care otherwise.
>
> The below patch implements the not care part that was missing until now.
>
>
> This is done by having the lexer mark the result variable of the
> assignment expression as not passable by reference, and changing the
> function zend_do_pass_param() to ignore the marked variables when
> considering if a parameter could be passed by reference or not.
>
> I have run make test, before and after, with no regressions. The only
> test affected was the one I sent earlier to specifically test for this bug.
>
> I am, however, not sure if this is the right approach to solve the
> problem, in which case, I hope to at least have put one of you on the
> right track to the _real_ solution, and to have made you interested in
> fixing it properly.

The patch looks strange to me, why would you only consider stuff like
foo($a = 2) ? what about passing any other expressions:
foo(array(..)), foo(funcNotReturningARef()) etc... ?

To me it makes not much sense to distinguish different non-ref
expressions in that regard, they should all be handled the same.
Whether we want the actual error on some of our functions  like
current()/end() etc.. is another question, but that should be fixed at
a totally different level.

>
> The patch is for php-5.3.8
>
>
> Daniel K.
>
> diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
> index c325a7e..df30d3d 100644
> --- a/Zend/zend_compile.c
> +++ b/Zend/zend_compile.c
> @@ -2096,7 +2096,7 @@ void zend_do_pass_param(znode *param, zend_uchar
> op, int offset TSRMLS_DC) /* {{
>
>        if (function_ptr) {
>                if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) {
> -                       if (param->op_type & (IS_VAR|IS_CV)) {
> +                       if (param->op_type & (IS_VAR|IS_CV) && 
> param->u.EA.type !=
> ZEND_PARSED_EXPR_NO_PASS_BY_REF) {
>                                send_by_reference = 1;
>                                if (op == ZEND_SEND_VAR && 
> zend_is_function_or_method_call(param)) {
>                                        /* Method call */
> diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
> index 15f24df..475f976 100644
> --- a/Zend/zend_compile.h
> +++ b/Zend/zend_compile.h
> @@ -650,6 +650,7 @@ int zendlex(znode *zendlval TSRMLS_DC);
>  #define ZEND_PARSED_VARIABLE                   (1<<4)
>  #define ZEND_PARSED_REFERENCE_VARIABLE (1<<5)
>  #define ZEND_PARSED_NEW                                        (1<<6)
> +#define ZEND_PARSED_EXPR_NO_PASS_BY_REF        (1<<7)
>
>
>  /* unset types */
> diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
> index 1753e97..666b9e2 100644
> --- a/Zend/zend_language_parser.y
> +++ b/Zend/zend_language_parser.y
> @@ -578,7 +578,7 @@ non_empty_for_expr:
>
>  expr_without_variable:
>                T_LIST '(' { zend_do_list_init(TSRMLS_C); } assignment_list 
> ')' '='
> expr { zend_do_list_end(&$$, &$7 TSRMLS_CC); }
> -       |       variable '=' expr               { 
> zend_check_writable_variable(&$1);
> zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); }
> +       |       variable '=' expr               { 
> zend_check_writable_variable(&$1);
> zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); $$.u.EA.type =
> ZEND_PARSED_EXPR_NO_PASS_BY_REF; }
>        |       variable '=' '&' variable { zend_check_writable_variable(&$1);
> zend_do_end_variable_parse(&$4, BP_VAR_W, 1 TSRMLS_CC);
> zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC);
> zend_do_assign_ref(&$$, &$1, &$4 TSRMLS_CC); }
>        |       variable '=' '&' T_NEW class_name_reference {
> zend_error(E_DEPRECATED, "Assigning the return value of new by reference
> is deprecated");  zend_check_writable_variable(&$1);
> zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4,
> &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4, &$7
> TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);
> zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $3.u.EA.type =
> ZEND_PARSED_NEW; zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); }
>        |       T_NEW class_name_reference { 
> zend_do_extended_fcall_begin(TSRMLS_C);
> zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments {
> zend_do_end_new_object(&$$, &$1, &$4 TSRMLS_CC);
> zend_do_extended_fcall_end(TSRMLS_C);}
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>



-- 
Etienne Kneuss
http://www.colder.ch

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to