On Fri, Sep 23, 2011 at 14:06, Daniel K. 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:


and a call like:

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 !=
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_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:

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 =
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);

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

Etienne Kneuss

Search Discussions

Discussion Posts


Follow ups

Related Discussions

Discussion Navigation
viewthread | post
posts ‹ prev | 2 of 15 | next ›
Discussion Overview
groupphp-internals @
postedSep 23, '11 at 12:06p
activeOct 7, '11 at 6:51p



site design / logo © 2022 Grokbase