Hi,
Ran into this exact issue just the other day. In the pre-5.4 days, to get the first element of a returned array I would use current(). I still think that's correct and shouldn't raise a digital eyebrow. On Sep 23, 2011 8:30 PM, "Etienne Kneuss" <col...@php.net> wrote: > 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 >