Arrays7 min readExamples run on PHP 8.5.10

array_unique()

Learn how PHP 8.4 array_unique() removes duplicate values, keeps the first key, compares values as strings by default, and where its flags and edge cases can surprise you.

Signature

array_unique(array $array, int $flags = SORT_STRING): array
Available since PHP 4.0.17.48.08.18.28.38.48.5All versions →

Purpose

array_unique() takes an array and returns a new array with duplicate values removed. The original array is not modified. It is the usual tool for cleaning a list of tags, ids or labels where the same value may appear several times.

The function keeps the first occurrence of each value, together with that element's original key. Later duplicates are dropped, and the remaining keys are not renumbered.

Signature

Parameters and defaults

  • $array: the input array. Both string and integer keys are accepted.
  • $flags: controls how values are compared. The default is SORT_STRING. The other values are SORT_REGULAR (compare normally without changing types), SORT_NUMERIC (compare numerically) and SORT_LOCALE_STRING (compare as strings using the current locale).

With the default flag, two elements count as equal when (string) $a === (string) $b. This is a string comparison, not a loose == comparison and not a strict === comparison.

Return value and failure cases

The function returns the filtered array. For ordinary scalar values it does not throw and does not return false. Passing something that is not an array raises a TypeError. Values that have no sensible string form, such as nested arrays or objects without __toString(), are a poor fit. The manual says plainly that the function is not intended for multidimensional arrays.

Example 1: keys are preserved

The first "green" keeps key a, and the first "red" keeps key 0. The second "green" and the second "red" are removed. The keys 0 and 1 remain, with no key 2, so the result is no longer a plain list. Wrap it in array_values() when you need keys 0, 1, 2... again.

Example
<?php
$flags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
$input = ["a" => "green", "red", "b" => "green", "blue", "red"];
$result = array_unique($input);
echo json_encode($result, $flags), "\n";
echo json_encode(array_values($result), $flags), "\n";
Output
{"a":"green","0":"red","1":"blue"}
["green","red","blue"]

Example 2: string comparison and flags

The default comparison turns values into strings. That is why 4 and "4" are duplicates, and why 1, "1", 1.0 and true all collapse into one value. Case matters: "a" and "A" stay distinct. The last two lines show that "1", "1.0" and "01" are different strings but the same number, so SORT_NUMERIC treats them as duplicates.

Example
<?php
$flags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
echo json_encode(array_unique([4, "4", "3", 4, 3, "3"]), $flags), "\n";
echo json_encode(array_unique([1, "1", 1.0, true, "a", "A"]), $flags), "\n";
echo json_encode(array_unique(["1", "1.0", "01", "2"]), $flags), "\n";
echo json_encode(array_unique(["1", "1.0", "01", "2"], SORT_NUMERIC), $flags), "\n";
Output
{"0":4,"2":"3"}
{"0":1,"4":"a","5":"A"}
["1","1.0","01","2"]
{"0":"1","3":"2"}

Example 3: normalizing before deduplicating

Because comparison is exact, near-duplicates such as " PHP" and "php " are not merged automatically. Normalize first with array_map(), then call array_unique(), then reindex.

Example
<?php
$flags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
$tags = [" PHP", "php ", "Arrays", "arrays", "Sorting"];
$clean = array_map(fn(string $tag): string => strtolower(trim($tag)), $tags);
$unique = array_values(array_unique($clean));
echo json_encode($unique, $flags), "\n";
Output
["php","arrays","sorting"]

Edge cases

  • Empty array: returns an empty array.
  • Falsy values: null, false and "" all become the empty string, so they count as duplicates of each other under the default flag.
  • Gaps in keys: the result may not be a list. json_encode() will then emit an object instead of an array, as in the first lines of examples 1 and 2.
  • SORT_REGULAR: the manual warns that with arrays mixing numeric and non-numeric strings, equal elements may not end up adjacent during the internal sort-then-compare step. Duplicates can then remain in the result. Prefer SORT_STRING when you want predictable behaviour.
  • Next appended index: since 7.2.0 with SORT_STRING, the result is built by adding unique elements to a new array. If the element with the largest integer key was removed, the index given to a later appended element can differ from what the original array would have produced. Do not rely on automatic indexes after filtering.

Common mistakes

  1. Expecting a reindexed list. Keys are preserved, so use array_values() if you need sequential keys, for example before encoding a JSON array or using [0] access.
  2. Expecting strict type comparison. 4 and "4" are treated as the same value by default.
  3. Forgetting normalization. Case differences and surrounding whitespace make strings distinct.
  4. Using it on rows of data. For arrays of arrays, build a key from the field you care about, such as an id, and deduplicate on that instead.
  5. Assuming the last duplicate wins. The first one is always kept.
  • array_count_values() counts how often each distinct value occurs, which helps when you need to know about duplicates and not just remove them.
  • array_values() reindexes the result.
  • array_flip() and array_keys() give another way to deduplicate simple string or integer lists.
  • in_array() checks whether a single value is already present.

Recap

array_unique() returns a new array without duplicate values. It compares values as strings by default, keeps the first matching element with its original key, and does not renumber keys. Choose flags deliberately, normalize your data first, and reindex with array_values() when you need a list.

Tested examples

Keys are preserved for the first occurrence
<?php
$flags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
$input = ["a" => "green", "red", "b" => "green", "blue", "red"];
$result = array_unique($input);
echo json_encode($result, $flags), "\n";
echo json_encode(array_values($result), $flags), "\n";
Output
{"a":"green","0":"red","1":"blue"}
["green","red","blue"]
String comparison, type juggling and flags
<?php
$flags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
echo json_encode(array_unique([4, "4", "3", 4, 3, "3"]), $flags), "\n";
echo json_encode(array_unique([1, "1", 1.0, true, "a", "A"]), $flags), "\n";
echo json_encode(array_unique(["1", "1.0", "01", "2"]), $flags), "\n";
echo json_encode(array_unique(["1", "1.0", "01", "2"], SORT_NUMERIC), $flags), "\n";
Output
{"0":4,"2":"3"}
{"0":1,"4":"a","5":"A"}
["1","1.0","01","2"]
{"0":"1","3":"2"}
Normalize tags before removing duplicates
<?php
$flags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
$tags = [" PHP", "php ", "Arrays", "arrays", "Sorting"];
$clean = array_map(fn(string $tag): string => strtolower(trim($tag)), $tags);
$unique = array_values(array_unique($clean));
echo json_encode($unique, $flags), "\n";
Output
["php","arrays","sorting"]