# Illegal use of string offset

- Thread: https://externals.io/message/9575
- Original archive: https://news-web.php.net/php.internals/9575
- Started by Curt Zirzow on 2004-04-27T03:49:00+00:00
- Messages: 10
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #9575 — Curt Zirzow — 2004-04-27T03:49:00+00:00

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

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."

---

## #9576 — Derick Rethans — 2004-04-27T06:37:18+00:00

URL: https://externals.io/message/9575#9576 · In reply to: #9575

>
> 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

---

## #9577 — Andi Gutmans — 2004-04-27T07:51:35+00:00

URL: https://externals.io/message/9575#9577 · In reply to: #9575

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:

>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."

---

## #9580 — Christian Schneider — 2004-04-27T09:09:29+00:00

URL: https://externals.io/message/9575#9580 · In reply to: #9577

Andi Gutmans wrote:
> At 03:49 AM 4/27/2004 +0000, Curt Zirzow 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?

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

---

## #9581 — Marcus Boerger — 2004-04-27T09:16:03+00:00

URL: https://externals.io/message/9575#9581 · In reply to: #9577

Hello Andi,

be strict

marcus

Tuesday, April 27, 2004, 9:51:35 AM, you 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?

> Andi

> At 03:49 AM 4/27/2004 +0000, Curt Zirzow wrote:

> > […]

---

## #9582 — Christian Schneider — 2004-04-27T10:20:36+00:00

URL: https://externals.io/message/9575#9582 · In reply to: #9577

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

---

## #9583 — Marcus Boerger — 2004-04-27T11:25:07+00:00

URL: https://externals.io/message/9575#9583 · In reply to: #9582

Hello Christian,

thanks for the test

Tuesday, April 27, 2004, 12:20:36 PM, you wrote:

> Andi Gutmans wrote:
> > […]

> 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

---

## #9584 — Christian Schneider — 2004-04-27T11:34:47+00:00

URL: https://externals.io/message/9575#9584 · In reply to: #9583

Marcus Boerger wrote:
> > […]
> 
> 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

---

## #9585 — Marcus Boerger — 2004-04-27T12:16:43+00:00

URL: https://externals.io/message/9575#9585 · In reply to: #9584

Hello Christian,

Tuesday, April 27, 2004, 1:34:47 PM, you wrote:

> Marcus Boerger wrote:
> > […]

> 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

---

## #9586 — messju mohr — 2004-04-27T12:42:05+00:00

URL: https://externals.io/message/9575#9586 · In reply to: #9585

> Hello Christian,
> 
> Tuesday, April 27, 2004, 1:34:47 PM, you wrote:
> 
> > […]
> 
> > […]
> 
> 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
 
> marcus
