3

I want to avoid scanning the array twice. Something like TryGetValue in C#.

richard
  • 10,572
  • 20
  • 83
  • 144
  • @JohnConde You mean write my own function with a for loop? – richard Dec 03 '13 at 18:58
  • 1
    Just get the value. And then check to see if you got anything. – jszobody Dec 03 '13 at 18:58
  • 5
    use array_key_exists() and if it does use the key to get the value. That's it. – John Conde Dec 03 '13 at 18:58
  • 1
    short if : isset($array[$key)?$array[$key]:null; – ka_lin Dec 03 '13 at 19:00
  • 1
    I want to avoid errors/warnings (i.e. your "just get the value and see if I got anything" suggestion) and I want to avoid scanning the array twice (check for key, and then get the value with the key). – richard Dec 03 '13 at 19:13
  • If the array is addressed by integer index, and contains only consecutive values, meeting the criteria for a plain ordered array, only a bounds check is performed, no scan happens. If the array is hash-based, as bucket lookup is performed, possibly twice. There may be some internal iterator or cache state that arrays hold behind the scene, though. See my answer below. – TylerY86 Nov 29 '15 at 05:37
  • @jszobody gave the best answer in a comment above - I've [added an answer](https://stackoverflow.com/a/56039491/199364) that expands on that. – ToolmakerSteve May 08 '19 at 11:25

3 Answers3

3

No, there isn't a built-in function that does what you want. However, it's not hard to write a new one:

function tryGetValue($array, $key) {
    return (array_key_exists($key, $array)) ? $array[$key] : NULL;
}

Example usage:

$array = array('foo' => 'bar', 'baz', 'bak', 'bam');

var_dump(tryGetValue($array, 'foo'));   // string(3) "bar"
var_dump(tryGetValue($array, 's'));     // NULL
var_dump(tryGetValue($array, 2));       // string(3) "bam"
var_dump(tryGetValue($array, 4));       // NULL
Amal Murali
  • 70,371
  • 17
  • 120
  • 139
  • 2
    Will that scan the array twice? – richard Dec 03 '13 at 19:12
  • @RichardDesLonde: Why do you need to scan the array twice? As the function name suggests, this will check if the given key exists in the array and outputs if it does. – Amal Murali Dec 03 '13 at 19:14
  • 2
    I don't need to scan the array twice. In your function you first check if the key exists (1st scan) and then you get the value with $array[$key] (2nd scan). For performance, I want to avoid scanning twice. – richard Dec 03 '13 at 19:15
  • @RichardDesLonde: It doesn't scan the array twice. It simply checks if the given key exists in the array, and then retrieves the corresponding value. – Amal Murali Dec 03 '13 at 19:17
  • 3
    how does it know if the key exists without scanning the array? – richard Dec 03 '13 at 19:19
  • 1
    it must scan the array in order to check if the key exists. – richard Dec 03 '13 at 19:21
  • @RichardDesLonde: As I said, I edited the above comment to add more clarity. `It doesn't scan the array twice. It simply checks if the given key exists in the array, and then retrieves the corresponding value.` – Amal Murali Dec 03 '13 at 19:22
  • 1
    You don't understand. HOW does the php function `array_key_exists` check if the key exists??? It SCANS THE ARRAY. – richard Dec 03 '13 at 19:23
  • 1
    As explained in [this](http://stackoverflow.com/questions/16675753/php-fastest-way-to-handle-undefined-array-key) similar question, yes: it requires 2 lookup in the B-TREE: One to check existence, another to retrieve value. – T30 Aug 02 '16 at 12:59
1

@jszobody gave the best answer in a comment on the question .. seems to have been overlooked. Expanding on his comment:

What do you want to return, if the array key doesn't exist?

If null, then the answer is "just do it":

@$array[$key]

("@" suppresses warning.)

If something else, and you don't store null values in array - so you don't ever want null to be returned - then the answer is

@$array[$key] ?? $YourDefaultValue

That is, in php, it isn't necessary to pre-test whether a key exists. Unless your design BOTH 1) allows storing of null values in the array, AND 2) wants a default other than null. If both of these conditions are true, then you would need to explicitly test whether the key exists, using array_key_exists.

ToolmakerSteve
  • 5,893
  • 8
  • 67
  • 145
  • Just don't promote bad practice. :) https://stackoverflow.com/questions/136899/suppress-error-with-operator-in-php – TylerY86 Jul 22 '20 at 03:00
0

Check these microbenchmarks I created on 3v4l.

Here are the functions.

function tryGetValue1( $array, $key, Closure $default ) {
  return array_key_exists($key, $array)
    ? $array[$key] : $default();
}

function tryGetValue2( $array, $key, Closure $default ) {
  return ($value = @$array[$key]) !== null || array_key_exists($key, $array)
    ? $value : $default();
}

function tryGetValue3( $array, $key, Closure $default ) {
  return isset($array[$key]) || array_key_exists($key, $array)
    ? $array[$key] : $default();
}

function tryGetValueNotNull1( $array, $key, Closure $default ) {
  return ($value = @$array[$key]) !== null
    ? $value : $default();
}

function tryGetValueNotNull2( $array, $key, Closure $default ) {
  return isset($array[$key])
    ? $array[$key] : $default();
}

It depends on if you care about null, and what version of PHP you're using.

Looks like the compilers try to optimize toward the isset and array_key_exists operations, at least for small arrays. This might imply that arrays have their own internal iterator state for this and similar purposes.

Interestingly, you can combine isset and array_key_exists (see tryGetValue3) and come out ahead sometimes.

This isn't a fully appropriate benchmark, as there are no null existing keys defined in the test array. Feel free to expand on the example. :)

TylerY86
  • 3,609
  • 13
  • 28
  • Note that if the default value you want is `null`, it isn't necessary to do any of the above, so no need to call a function: its as simple as: [`@$array[$key]`](https://stackoverflow.com/a/56039491/199364). – ToolmakerSteve Jul 18 '20 at 00:29