Search in Arrays
Searching an array answers questions such as: Does this value exist? Where is it? Which elements match a condition? Is this key present? PHP provides a dedicated function for each question.
| Question | Function | Returns |
|---|---|---|
| Does a value exist? | in_array($value, $array, true) | bool |
| Which key holds a value? | array_search($value, $array, true) | First key, or false |
| Which keys hold a value (all of them)? | array_keys($array, $value, true) | Array of keys |
| Does a key exist? | array_key_exists($key, $array) / isset($array[$key]) | bool |
| Which elements match a condition? | array_filter($array, $callback) | Array of matches |
| First element matching a condition? | array_find() (PHP 8.4+) | Value or null |
| Key of the first match? | array_find_key() (PHP 8.4+) | Key or null |
| Does any / every element match? | array_any() / array_all() (PHP 8.4+) | bool |
| Which strings match a pattern? | preg_grep($pattern, $array) | Array of matches |
in_array() — Does the Value Exist?
Syntax
in_array(mixed $needle, array $haystack, bool $strict = false): bool
Example
<?php
$fruits = ['Mango', 'Banana', 'Guava'];
var_dump(in_array('Banana', $fruits, true));
var_dump(in_array('banana', $fruits, true));
var_dump(in_array('Apple', $fruits, true));
Output
bool(true)
bool(false)
bool(false)
The search is case-sensitive: 'banana' does not match 'Banana'.
Always Use Strict Mode
Without the third argument, in_array() compares with == (loose comparison):
<?php
$allowedIds = [1, 2, 3];
var_dump(in_array('1', $allowedIds));
var_dump(in_array('1', $allowedIds, true));
var_dump(in_array(null, [0, 1]));
var_dump(in_array(null, [0, 1], true));
Output
bool(true)
bool(false)
bool(true)
bool(false)
- The string
'1'loosely equals the integer1, but strictly it does not. null == 0istrue, so a loose search fornullfinds0.
Loose matches can let invalid input pass validation. Pass true as the third argument unless you deliberately want type juggling — and make sure the value's type matches the array's (for example, cast form input with (int) before searching a list of integer IDs).
array_search() — Where Is the Value?
<?php
$queue = ['ORD-11', 'ORD-12', 'ORD-13'];
$position = array_search('ORD-11', $queue, true);
var_dump($position);
$missing = array_search('ORD-99', $queue, true);
var_dump($missing);
if ($position !== false) {
echo "ORD-11 is number " . ($position + 1) . " in the queue\n";
}
Output
int(0)
bool(false)
ORD-11 is number 1 in the queue
array_search() returns the key of the first match, or false. Because a valid key can be 0 (falsy), always check with !== false. Writing if ($position) would treat the first element as "not found".
All Matching Keys: array_keys()
<?php
$ratings = ['Asha' => 5, 'Bala' => 3, 'Charu' => 5, 'Dev' => 4];
$fiveStars = array_keys($ratings, 5, true);
echo "Five-star reviewers: " . implode(', ', $fiveStars) . "\n";
Output
Five-star reviewers: Asha, Charu
With a second argument, array_keys() returns every key whose value matches — not just the first.
Searching for Keys
<?php
$prices = ['Pen' => 20, 'Notebook' => 60, 'Gift Card' => null];
var_dump(array_key_exists('Notebook', $prices));
var_dump(isset($prices['Gift Card']));
var_dump(array_key_exists('Gift Card', $prices));
var_dump(isset($prices['Lamp']));
Output
bool(true)
bool(false)
bool(true)
bool(false)
array_key_exists()reports whether the key exists, even if its value isnull.isset()returnsfalsefornullvalues. It also works for nested paths (isset($a['x']['y'])).
Searching Records
Data often comes as a list of records. Two common approaches:
Using array_column() + array_search()
<?php
$users = [
['id' => 7, 'email' => 'asha@example.com'],
['id' => 9, 'email' => 'bala@example.com'],
['id' => 12, 'email' => 'charu@example.com'],
];
$index = array_search('bala@example.com', array_column($users, 'email'), true);
if ($index !== false) {
echo "Found user #{$users[$index]['id']}\n";
}
Output
Found user #9
array_column() builds a list of emails with the same positions as $users, so the index found in it can be used to read the full record. (This assumes $users is a list with keys 0, 1, 2, ….)
Using array_filter() for All Matches
<?php
$products = [
['name' => 'Gel Pen', 'category' => 'Stationery', 'price' => 20],
['name' => 'Desk Lamp', 'category' => 'Home', 'price' => 1299],
['name' => 'Notebook', 'category' => 'Stationery', 'price' => 60],
];
$stationery = array_filter($products, fn(array $p): bool => $p['category'] === 'Stationery');
echo implode(', ', array_column($stationery, 'name')) . "\n";
Output
Gel Pen, Notebook
array_filter() returns every matching record, preserving keys.
PHP 8.4: array_find(), array_find_key(), array_any(), array_all()
PHP 8.4 added functions that search with a callback and stop as soon as the answer is known:
<?php
$products = [
['name' => 'Gel Pen', 'price' => 20, 'stock' => 100],
['name' => 'Desk Lamp', 'price' => 1299, 'stock' => 0],
['name' => 'Backpack', 'price' => 899, 'stock' => 4],
];
$soldOut = array_find($products, fn(array $p): bool => $p['stock'] === 0);
$soldOutKey = array_find_key($products, fn(array $p): bool => $p['stock'] === 0);
var_dump($soldOut['name'], $soldOutKey);
var_dump(array_any($products, fn(array $p): bool => $p['price'] > 1000));
var_dump(array_all($products, fn(array $p): bool => $p['stock'] > 0));
var_dump(array_find($products, fn(array $p): bool => $p['price'] > 5000));
Output
string(9) "Desk Lamp"
int(1)
bool(true)
bool(false)
NULL
| Function | Returns |
|---|---|
array_find() | The first value for which the callback returns true, or null |
array_find_key() | The key of that value, or null |
array_any() | true if at least one element matches |
array_all() | true if every element matches |
The callback receives the value and the key. These functions replace common loops with break, and they stop at the first decisive element. On PHP versions before 8.4, use a foreach loop with break or return.
Pattern Searches: preg_grep()
<?php
$fruits = ['Mango', 'Guava', 'Grapes', 'Apple'];
print_r(preg_grep('/^g/i', $fruits));
Output
Array
(
[1] => Guava
[2] => Grapes
)
preg_grep() returns elements matching a regular expression, preserving keys. Here, ^g means "starts with g", and the i modifier makes it case-insensitive. See the PHP RegEx section.
Case-Insensitive Value Search
<?php
$tags = ['PHP', 'MySQL', 'Laravel'];
$search = 'mysql';
$found = in_array(mb_strtolower($search), array_map('mb_strtolower', $tags), true);
var_dump($found);
Output
bool(true)
Lowercasing both the search term and the array makes the comparison case-insensitive. When this lookup happens often, store the lowercase version once instead of converting on every search.
Fast Lookups With Keys
in_array() and array_search() check elements one by one, so their time grows with the array size. Checking a key with isset() takes about the same time no matter how big the array is. For repeated lookups, flip the list into keys once:
<?php
$blockedDomains = array_flip(['spam.com', 'fake.org', 'temp-mail.net']);
$emails = ['asha@gocourse.in', 'spammer@spam.com', 'bala@fake.org', 'charu@gmail.com'];
foreach ($emails as $email) {
$domain = strtolower(substr(strrchr($email, '@'), 1));
$status = isset($blockedDomains[$domain]) ? 'blocked' : 'allowed';
echo "$email: $status\n";
}
Output
asha@gocourse.in: allowed
spammer@spam.com: blocked
bala@fake.org: blocked
charu@gmail.com: allowed
How It Works
array_flip()turns['spam.com', 'fake.org', ...]into['spam.com' => 0, 'fake.org' => 1, ...].strrchr($email, '@')returns the part from the last@;substr(..., 1)removes the@.isset($blockedDomains[$domain])checks the domain as a key — very fast even with thousands of blocked domains.
For a list of 10 items, the difference is negligible. For large lists checked many times (for example, inside a loop over thousands of records), key lookups are dramatically faster.
Common Mistakes
Loose in_array() / array_search()
Effect: Numeric strings match integers, and null matches 0 or '', so invalid input can pass checks.
Fix: Pass true for strict comparison.
Checking array_search() With if ($key)
Effect: A match at key 0 looks like "not found".
Fix: if ($key !== false).
Searching Values When You Need Keys (or the Reverse)
Effect: in_array('Pen', $prices) searches prices, not product names.
Fix: Use array_key_exists() / isset() for keys and in_array() for values.
Repeated in_array() on Large Arrays
Effect: Slow code inside loops.
Fix: Flip the array once and use isset().
Using isset() When null Is a Valid Value
Effect: Existing keys with null values are reported as missing.
Fix: Use array_key_exists().
Best Practices
- Use strict comparison in
in_array(),array_search(), andarray_keys(). - Compare
array_search()results with!== false. - Use
array_find(),array_any(), andarray_all()(PHP 8.4+) for condition-based searches. - Use key lookups (
isset()on a flipped array) for frequent membership checks. - Search in the database (
WHERE) when the data comes from a query, instead of loading everything into PHP.
Official reference: https://www.php.net/manual/en/function.in-array.php