Illegal use of string offset

php.internals

Curt Zirzow

22 years ago
I can't seem to find any discussion on this BC issue, so forgive me if this has already been discussed. Given the following; $a = 'a string'; /* E_ERROR Cannot use string offset as an array */ echo is_array($a['bar']['baz']); /* non error resolution */ echo isset($a['bar']['baz']) && is_array($a['bar']['baz']); I'm not sure, but the patch below does seem to make the E_ERROR get demoted to a E_WARNING, thus fixing it so execution simply doesn't stop when a string is referenced improperly. Or is it a *must* that php needs to stop in this case? Index: zend_execute.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute.c,v retrieving revision 1.643 diff -u -r1.643 zend_execute.c --- zend_execute.c 15 Apr 2004 21:32:34 -0000 1.643 +++ zend_execute.c 27 Apr 2004 02:39:52 -0000 @@ -898,7 +898,9 @@ zval ***retval = &T(result->u.var).var.ptr_ptr; if (!container_ptr) { - zend_error(E_ERROR, "Cannot use string offset as an array"); + *retval = &EG(uninitialized_zval_ptr); + zend_error(E_WARNING, "Cannot use string offset as an array"); + return; } container = *container_ptr; Curt
-- "I used to think I was indecisive, but now I'm not so sure."

Derick Rethans

22 years ago
On Tue, 27 Apr 2004, Curt Zirzow wrote:
> > I can't seem to find any discussion on this BC issue, so forgive me if > this has already been discussed. > > Given the following; > > $a = 'a string'; > > /* E_ERROR Cannot use string offset as an array */ > echo is_array($a['bar']['baz']); > > /* non error resolution */ > echo isset($a['bar']['baz']) && is_array($a['bar']['baz']); > > > I'm not sure, but the patch below does seem to make the E_ERROR > get demoted to a E_WARNING, thus fixing it so execution simply doesn't > stop when a string is referenced improperly. Or is it a *must* that php > needs to stop in this case?
I see no reason why PHP shouldn't stop in this case. You're definitely doing something wrong to create that E_ERROR. Derick

Andi Gutmans

22 years ago
I made this change back in December. I guess I could revert back but I think it makes sense to be strict here. What does the rest think? Andi At 03:49 AM 4/27/2004 +0000, Curt Zirzow wrote:

Derick Rethans

22 years ago
On Tue, 27 Apr 2004, Andi Gutmans wrote:
> I made this change back in December. > I guess I could revert back but I think it makes sense to be strict here. > What does the rest think?
Be strict. Derick

Magnus Maatta

22 years ago
On Tuesday 27 April 2004 09.51, Andi Gutmans wrote:
> I made this change back in December. > I guess I could revert back but I think it makes sense to be strict here. > What does the rest think?
Be strict /Magnus
-- Confession is good for the soul only in the sense that a tweed coat is good for dandruff. -- Peter de Vries

Christian Schneider

22 years ago
Andi Gutmans wrote:
> At 03:49 AM 4/27/2004 +0000, Curt Zirzow wrote: >> $a = 'a string'; >> /* E_ERROR Cannot use string offset as an array */ >> echo is_array($a['bar']['baz']); > > I made this change back in December. > I guess I could revert back but I think it makes sense to be strict here. > What does the rest think?
My feeling is that the is_*-functions should be forgiving as people *are* doing checks to ensure proper input values. To force a combination or isset and is_* seems to be the wrong thing to me. But I realize that the issue here happens because is_* are normal functions and the check is done beforehand. Nevertheless I'd prefer not to have to guard is_* with isset in my ideal PHP world :-) On one hand it's not that important to me though as it only happens under rare circumstances. On the other hand it leads to very subtle BC problems as you can hit it depending on user input in a form if you use nested arrays there. So I'm 50:50 on reverting. - Chris

Marcus Börger

22 years ago
Hello Andi, be strict marcus Tuesday, April 27, 2004, 9:51:35 AM, you wrote:

Christian Schneider

22 years ago
Andi Gutmans wrote:
> I made this change back in December. > I guess I could revert back but I think it makes sense to be strict here.
Reevaluating it I noted the following: $a = 'foo'; $a['bar']['qux'] = 42; # error $a = 42; $a['bar']['qux'] = 42; # warning $a = true; $a['bar']['qux'] = 42; # warning unset($a); $a['bar']['qux'] = 42; # works $a = null; $a['bar']['qux'] = 42; # works $a = false; $a['bar']['qux'] = 42; # works! On the other hand $a = 'foo'; $b = $a['bar']['qux']; # error $a = 42; $b = $a['bar']['qux']; # works $a = true; $b = $a['bar']['qux']; # works unset($a); $b = $a['bar']['qux']; # works $a = null; $b = $a['bar']['qux']; # works $a = false; $b = $a['bar']['qux']; # works Let me ask you one question: What it the *real* benefit of making it fail? Isn't a notice or warning enough safety? I think this should definitely be more orthogonal, i.e. work (with a notice or warning) in all cases to avoid WTF. [ $a = 'foo'; $a['bar'] = 42; has an even weirder behaviour: It results in the string '4oo'... ] - Chris

Marcus Börger

22 years ago
Hello Christian, thanks for the test Tuesday, April 27, 2004, 12:20:36 PM, you wrote:
> Andi Gutmans wrote: >> I made this change back in December. >> I guess I could revert back but I think it makes sense to be strict here.
> Reevaluating it I noted the following: > $a = 'foo'; $a['bar']['qux'] = 42; # error
> $a = 42; $a['bar']['qux'] = 42; # warning > $a = true; $a['bar']['qux'] = 42; # warning
> unset($a); $a['bar']['qux'] = 42; # works > $a = null; $a['bar']['qux'] = 42; # works > $a = false; $a['bar']['qux'] = 42; # works!
false should have the same behavior as other scalar values maybe null is discussable but then again it is a value like 0 of true or 42 just with a little specific meaning.
> On the other hand > $a = 'foo'; $b = $a['bar']['qux']; # error
> $a = 42; $b = $a['bar']['qux']; # works > $a = true; $b = $a['bar']['qux']; # works > unset($a); $b = $a['bar']['qux']; # works > $a = null; $b = $a['bar']['qux']; # works > $a = false; $b = $a['bar']['qux']; # works
Having these working without notice/wraning/error if it does without the assignment is a miserable inconsistency.
> Let me ask you one question: What it the *real* benefit of making it > fail? Isn't a notice or warning enough safety?
> I think this should definitely be more orthogonal, i.e. work (with a > notice or warning) in all cases to avoid WTF.
agreed
> [ $a = 'foo'; $a['bar'] = 42; has an even weirder behaviour: It results > in the string '4oo'... ]
That's a pretty. It is using 'bar' as a sting index to 'foo' and to do this it needs to convert 'bar' to an integer. The rest is obvious. I think we should make [] as string offset an E_STRICT or even E_ERROR because it confuses far too many people especially since we generally have autoconversions and it is not clear what the result of such expressions is without trying them.
-- Best regards, Marcus mailto:helly@php.net

Christian Schneider

22 years ago
Marcus Boerger wrote:
>>[ $a = 'foo'; $a['bar'] = 42; has an even weirder behaviour: It results >>in the string '4oo'... ] > > That's a pretty. It is using 'bar' as a sting index to 'foo' and to do > this it needs to convert 'bar' to an integer. The rest is obvious.
So you find it obvious that 42 is cast to string and the first character is used as replacement? Wasn't obvious to me before I tried it :-)
> I think we should make [] as string offset an E_STRICT or even E_ERROR > because it confuses far too many people especially since we generally
E_ERROR would be a big BC break I guess. E_STRICT sounds fine to me. - Chris

Marcus Börger

22 years ago
Hello Christian, Tuesday, April 27, 2004, 1:34:47 PM, you wrote:
> Marcus Boerger wrote: >>>[ $a = 'foo'; $a['bar'] = 42; has an even weirder behaviour: It results >>>in the string '4oo'... ] >> >> That's a pretty. It is using 'bar' as a sting index to 'foo' and to do >> this it needs to convert 'bar' to an integer. The rest is obvious.
> So you find it obvious that 42 is cast to string and the first character > is used as replacement? Wasn't obvious to me before I tried it :-)
That's what i meant it confuses far too many people and doesn't even make real sense. For example converting 42 into chr(42) and setting it would follow the same autoconversion logic. Hence a hint of kind E_STRICT would be very good. marcus

messju mohr

22 years ago
On Tue, Apr 27, 2004 at 02:16:43PM +0200, Marcus Boerger wrote:
> Hello Christian, > > Tuesday, April 27, 2004, 1:34:47 PM, you wrote: > > > Marcus Boerger wrote: > >>>[ $a = 'foo'; $a['bar'] = 42; has an even weirder behaviour: It results > >>>in the string '4oo'... ] > >> > >> That's a pretty. It is using 'bar' as a sting index to 'foo' and to do > >> this it needs to convert 'bar' to an integer. The rest is obvious. > > > So you find it obvious that 42 is cast to string and the first character > > is used as replacement? Wasn't obvious to me before I tried it :-) > > That's what i meant it confuses far too many people and doesn't even make > real sense. For example converting 42 into chr(42) and setting it would > follow the same autoconversion logic. Hence a hint of kind E_STRICT would > be very good.
I know I have no karma here, but anyway: If you want to give people a hinting they access their stuff in a wrong way *and* you want it in a consistent way: why not throw an E_STRICT (or maybe even an E_NOTICE) when accessing anything via [] that is not array? $a = null; $a['foo']; -> should give an E_STRICT (if not an E_NOTICE) $a = false; $a['foo']; -> should give an E_STRICT (if not an E_NOTICE) $a = "FOO"; $a['foo']; -> should give an E_STRICT (if not an E_NOTICE) $a = array(); $a['foo']; -> gives an E_NOTICE because of "undefined index 'foo'" $a = array('foo'=>'FOO'); $a['foo'] -> obviously okay just my few p. messju

Andi Gutmans

22 years ago
For BC purposes with PHP 3, NULL/False and unset creation of array does not emit a warning. I don't think we should change this. I do understand the argument against breaking BC with the $a = 'foo'; $a['bar']['qux'] = 42; code. I think it's probably best if I revert back to PHP 4 behavior and emit an E_WARNING. Andi At 12:20 PM 4/27/2004 +0200, Christian Schneider wrote:

Marcus Börger

22 years ago
Hello Andi, Tuesday, April 27, 2004, 3:15:47 PM, you wrote:
> For BC purposes with PHP 3, NULL/False and unset creation of array does not > emit a warning. I don't think we should change this.
It is time to forget BC with PHP 3. Nearly noone is using it now. marcus

Christian Schneider

22 years ago
Marcus Boerger wrote:
>>For BC purposes with PHP 3, NULL/False and unset creation of array does not >>emit a warning. I don't think we should change this. > > It is time to forget BC with PHP 3. Nearly noone is using it now.
PHP 4 doesn't issue a warning/notice either and I could imagine there is plenty of code out there which is 'missing' some array inits. - Chris

Edin Kadribasic

22 years ago
On Tuesday 27 April 2004 15:15, Andi Gutmans wrote:
> For BC purposes with PHP 3, NULL/False and unset creation of array does not > emit a warning. I don't think we should change this. > I do understand the argument against breaking BC with the $a = 'foo'; > $a['bar']['qux'] = 42; code. I think it's probably best if I revert back to > PHP 4 behavior and emit an E_WARNING.
+1 Edin

Andi Gutmans

22 years ago
At 04:00 PM 4/27/2004 +0200, Marcus Boerger wrote:
>Hello Andi, > >Tuesday, April 27, 2004, 3:15:47 PM, you wrote: > > > For BC purposes with PHP 3, NULL/False and unset creation of array does not > > emit a warning. I don't think we should change this. > >It is time to forget BC with PHP 3. Nearly noone is using it now.
It's not only BC. An empty variable == NULL and there are some other good situations (which I can't remember on the top of my head) where this needs to stay the way it is. It really doesn't matter and I suggest not to break such stuff because it could break millions of scripts. Andi