The UTF-8 sorted array doesn't work with foreach in PHP

Viewed 106

Only the collator (UTF-8 sorted array) works without foreach and with only one value in an array.

But I am using foreach and multiple values in an array.

Here is the code:

<select name="courses">

<?php 

  $list_courses = 
  array(
      array("course" => "Management",
            "value"  => "course1",
            "emoji"  => "test1"),
      array("course" => "Éducation Physique",
            "value"  => "course2",
            "emoji"  => "test2"),
      array("course" => "Électrotechnique",
            "value"  => "course3",
            "emoji"  => "test3"),
      array("course" => "Géographie",
            "value"  => "course4",
            "emoji"  => "test4"),

  );

  $coll = new Collator('fr_FR');
  $coll->sort($list_courses);

  foreach ($list_courses as $key => $value)
  {
    echo ('<option value="' . "$value[value]" . '" data-icon="' . "$value[emoji]" . '">' . "$value[course]" . '</option>');
  }

?>
</select>
<label for="courses">Cours</label>

With collator, it is still the same order, but with foreach, then here is the actual behaviour in the output:

Management
Géographie
Éducation Physique
Électromécanique
1 Answers

Collator::sort works on an array of strings - if you're passing it a multi-dimensional array then the output is going to be undefined.

You can work round this by re-indexing your array into a key->value structure instead, and then making a slight change to your loop:

// Re-index array to key=>value
$list_courses = array_column($list_courses, 'course', 'value');

// Sort by values (note asort, to maintain keys)
$coll = new Collator('fr_FR');
$coll->asort($list_courses);

foreach ($list_courses as $key => $value) {
  echo '<option value="' . $key . '">' . $value . '</option>';
}

If your arrays are more complicated than this, you'll need to use a native sorting function like uasort, and make use of the Collator to do the actual comparison:

$collator = new Collator('fr_FR');

uasort($list_courses, function ($a, $b) use($collator) {
    return $collator->compare($a['course'], $b['course']);
});

foreach ($list_courses as $value) {
    echo '<option value="' . $value['value'] . '" data-icon="' . $value['emoji'] . '">' . $value['course'] . '</option>', PHP_EOL;
}

Here, we deal with the array objects in their entirety, so there's no need to re-index.

Related