2

Consider

$foo = "abcdefg";

echo $foo[0]; //outputs a

So it seems like strings are like array of characters but then why

foreach($foo as $char)
{
echo $char;
}

does not work and gives following Warning ??

Warning: Invalid argument supplied for foreach() 
Mr Coder
  • 8,169
  • 5
  • 45
  • 74
  • The old notation (still working but deprecated) was `echo $foo{0};` I never understood why they changed it. – Jacco Sep 10 '11 at 13:00
  • @Jacco: It isn't deprecated ;) – NikiC Sep 10 '11 at 13:10
  • @NikiC: Are you triple sure? I was under that same impression. – Jon Sep 10 '11 at 13:11
  • @Jon: I am ;) http://codepad.viper-7.com/X0lgFz (It was deprecated a short time during 5.3 development. I don't know why they reverted it, maybe just an accident.) – NikiC Sep 10 '11 at 13:12
  • @NikiC: It turns out we are [not imagining things](http://stackoverflow.com/questions/885241/php-string-indexing): looks like this syntax was on its way to being deprecated in PHP 6, but the current doc page has no mention of that. Possibly they changed their mind? – Jon Sep 10 '11 at 13:19
  • @Jon Yes, in the sense that we (that is PHP and its community) don't want them to be used. But they are not officially deprecated, sadly :( I'm going to ping internals about getting them deprecated in 5.4 ;) – NikiC Sep 10 '11 at 13:25
  • 1
    @jacco I just checked it and its working and I will prefer {} over [] with string since it makes me think it as a array :) – Mr Coder Sep 10 '11 at 13:25
  • @NikiC, thanks! I will promptly change some of my code back : ) – Jacco Sep 10 '11 at 14:30
  • @Jacco Uhm, maybe we have a little misunderstanding here: Even though using curly braces is not deprecated, you should definitely not use them, as it is quite probable that they will get deprecated in later releases ;) – NikiC Sep 10 '11 at 15:12

4 Answers4

1

Adding string iteration support to foreach was discussed but declined. There were mainly two reasons for this decision:

  • It makes applications harder to debug. Usually you don't want to iterate over the characters of a string. You need that only very rarely. So if you do iterate over a string you probably just made a programming mistake - and PHP will tell you so. If string iteration were introduces this kind of error would be hard to catch.
  • What is a "character"? Should PHP iterate over each single byte? Should it iterate over characters (which can be multiple bytes)? If so, what should it do if it encounters a malformed multibyte sequence? And where does it get the charset from?

To solve both problems there was a proposal to introduce a TextIterator, which you pass a string and a charset. That way you can't accidentally iterate a string and the byte vs character problem doesn't exist. I'm not sure though what the state of the TextIterator is currently.

NikiC
  • 100,734
  • 37
  • 191
  • 225
  • TextIterator sounds like a great idea. :) – Herbert Sep 10 '11 at 13:30
  • it would be cool if PHP interpreter could have taken care of this inside foreach for us now it seems wired to not to think string as array of characters . – Mr Coder Sep 10 '11 at 13:42
  • You often need to interate by **graphemes** (user-visible characters), not by mere *code point* (programmer-visible character) let alone by uselessly stupid *code units* (computer-visible character). You can use regexes to step through a string a grapheme at a time using `\X`. – tchrist Sep 10 '11 at 19:30
  • @tchrist: Note though that PHP aint Perl. In PCRE `\X` matches only extended unicode sequences (i.e. a non-mark character followed by an arbitrary number of mark-characters), whereas Perl goes all the way of matching extended grapheme clusters. – NikiC Sep 10 '11 at 20:38
1

NikiC's answer covers why doing this directly is not possible.

If you want to iterate over a string as if it were an array, you can be explicit by using str_split:

foreach(str_split($foo) as $char) 
{ 
    echo $char; 
} 

Warning: str_split is not encoding-aware, so you will end up iterating over bytes and not over characters. Iterating over characters is a little more involved, as there is no equivalent multibyte split function. You can roll your own using the regex-enabled mb_split, look at the comments from PHP.net for ideas.

There are other answers here suggesting you should cast the string to an array, but I don't understand why that would work. The documentation is pretty explicit:

For any of the types: integer, float, string, boolean and resource, converting a value to an array results in an array with a single element with index zero and the value of the scalar which was converted. In other words, (array)$scalarValue is exactly the same as array($scalarValue).

And indeed, doing this does not work as suggested.

Jon
  • 428,835
  • 81
  • 738
  • 806
0

Even though their characters can be addressed using square brackets, strings aren't arrays. Emphasis mine:

Characters within strings may be accessed and modified by specifying the zero-based offset of the desired character after the string using square array brackets, as in $str[42]. Think of a string as an array of characters for this purpose.

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
-1

it is called "syntax sugar".

For example, in 5.4 you'll be able to do like this echo func()[0];
That doesn't mean that a function is really an array of charactes.
It's just a syntax.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345