March 7, 2012

What's wrong with this php foreach code? (merged array)

Question by Mouse Hello

$db = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);

            $items = 'SELECT items FROM menus';
            $itemLink = 'SELECT itemLink FROM menus';

            $itemQuery = $db->query($items);
            $linkQuery = $db->query($itemLink);

            $fetchItem = $itemQuery->fetch(PDO::FETCH_ASSOC);
            $fetchLink = $linkQuery->fetch(PDO::FETCH_ASSOC);

            $merged = array_merge($fetchItem,$fetchLink);

            foreach($merged as $key=>$value){
                echo "${key} =>  ${value} <br />";
            }

This is what it looks like in the database:

items   |itemLink
----------------------
Kill Bill|Kill Bill link
Preman  |Preman link

So, the expected output, or at least what I thought must be this:

    items => Kill Bill
    items => Preman
    itemLink => Kill Bill Link 
    itemLink => Preman Link

But the resulted output from the code is this:

items => Kill Bill
itemLink => Kill Bill Link 

It’s missing the other items and itemLink

So, how do I achieve the output that I want?

Answer by Sirko

        $fetchItem = $itemQuery->fetch(PDO::FETCH_ASSOC);
        $fetchLink = $linkQuery->fetch(PDO::FETCH_ASSOC);

This only fetches the first row of each resultset. You need fetchAll:

        $fetchItem = $itemQuery->fetchAll(PDO::FETCH_ASSOC);
        $fetchLink = $linkQuery->fetchAll(PDO::FETCH_ASSOC);

and adjust the rest of your code.

        foreach($merged as $entry) {
          foreach( $entry as $key => $value ) {
            echo "${key} =>  ${value} <br />";
          }
        }

EDIT:
The call of fetch only retrieved the first row of the resultset, whereas fetchAll parses the complete resultset into an Array. So the Objects look like this afterwards:

Array(
  [0] => { 'items' => 'Kill Bill' },
  [1] => { 'items' => 'Preman' }
)
Array(
  [0] => { 'itemLink' => 'Kill Bill' },
  [1] => { 'itemLink' => 'Preman' }
)

array_merge concatenate both arrays to the following:

Array(
  [0] => { 'items' => 'Kill Bill' },
  [1] => { 'items' => 'Preman' },
  [2] => { 'itemLink' => 'Kill Bill' },
  [3] => { 'itemLink' => 'Preman' }
)

So we now have a two dimensional array. To traverse the values we need first to select each $entry, which is done in the outer foreach and can afterwards access the key/value structure in the inner foreach.

As pointed out in the other comment: If you want to preserve the connection between itemsand itemLink, you should change the query in the first place to

SELECT items, itemLink FROM menus

Answer by Starx

You can use simple array_combine() function to do what you are trying to do now.

$merged = array_combine($fetchItem, $fetchLink);

This will make all the item from $fetchItem as keys to the item from $fetchLink.

Author: Nabin Nepal (Starx)

Hello, I am Nabin Nepal and you can call me Starx. This is my blog where write about my life and my involvements. I am a Software Developer, A Cyclist and a Realist. I hope you will find my blog interesting. Follow me on Google+

...

Please fill the form - I will response as fast as I can!