Here's a patch against HEAD that implements the array_get function
previously suggested on this list. I also attached a test suite,
which should go in ext/standard/tests/array/array_get.phpt. Feedback
is welcome.
Independently, someone else had posted the same idea as a feature
request for PHP 5, and if there's interest I can backport it.
40792 Open Wish: Function array_get(&$mixed, $key, $defaultvalue)
/* Prototype:
- mixed array_get ( array $search, mixed $key, mixed $default );
- Description:
- Returns the value corresponding to the given key if the key exists
- in the array. $key can be any value possible for an array index.
- If the key does not exist, the function returns $default, or
FALSE
- if $default is not specified. Also works on objects.
- Similar semantics to array_key_exists.
*/
Here is the original proposal:
array_get, a more palatable alternative to ifsetor
MOTIVATION
There is an unmet need for an accessor that doesn't generate an
E_NOTICE
when the value is missing, as shown by ongoing discussions
and repeated requests for an ifsetor operator. However, ifsetor had a
special-case syntax and generally didn't fit very well with the rest
of the language.
http://devzone.zend.com/node/view/id/1481#Heading2 has a brief
summary. See the Related Functions and Proposals section for more.
Reading over those ideas (firstset(), coalesce(), :?, ifset(), and a
workaround using settype()
), most of the best uses boil down to
retrieving values from arrays.
PROPOSAL
As a simpler alternative to constructs such as this common double
array reference...
$value = isset($_POST['command']) ? $_POST['command'] : '';
I propose an array_get function, like this...
$value = array_get($_POST, 'command', '');
The third argument provides a default. This function would require no
special syntax, and makes a very common construct easier to read and
less error-prone to type. It's a concise way of saying that missing
values can be handled gracefully.
Though request processing was used as an example, the function has
wide applicability across many other uses of associative arrays.
GREAT, BUT WHY NOT ADD IT TO AN INCLUDE FILE, INSTEAD OF THE CORE?
One of the goals is to make everyday PHP code simpler and clearer.
Writers of sample code snippets should be able to rely on array_get()
being available. Otherwise, they will not use it. Clearer sample code
particularly benefits beginners, who would probably find array_get
easier to understand, but anyone else who has to read or maintain
other people's code would benefit from its wide deployment in core as
well. The function is generally useful enough to be part of the
language, and the implementation in C is also more efficient than a
PHP version.
That said, a compatibility function for older versions of PHP is
given below.
SEMANTICS
mixed array_get(array $array, mixed $key[, mixed $default = FALSE]);
If $array contains the key $key, $array[$key] is returned. Otherwise
$default is returned.
If $default is not specified, it defaults to FALSE. (NULL would also
be possible, and would more closely match other languages such as
Python with its dict.get method, but other PHP functions tend to
return FALSE
to indicate no value.)
The semantics match
array_key_exists($key, $array) ? $array[$key] : $default
... but for comparison,
isset($array[$key]) ? $array[$key] : $default
is subtly different. The preferred array_key_exists version has these
differences:
1. If $array[$key] exists but has been set to null, that null
value will be returned instead of $default. This is likely to be the
least surprising thing to do.
2. If $array itself is unset, an error is generated. This is good.
The intention is to gracefully handle a missing $key. But if even
$array itself doesn't exist, there may be another problem, such as
misspelling the array variable. isset() ignores all errors, sweeping
more under the rug than we typically want.
IMPLEMENTATION
A core C implementation of array_get() benchmarked between two and
three times as fast as the implementation in PHP. I'll attach the
patch after responding to feedback.
See the last section for the code of the PHP implementation.
RELATED FUNCTIONS AND PROPOSALS
This function is different than the array_get function proposed and
rejected in http://bugs.php.net/bug.php?id=28185. That function had
no default value and throws a notice when the key doesn't exist,
eliminating the major purpose of this function.
The ?: operator doesn't serve the same purpose, because it causes an
E_NOTICE
for missing values. However, ?: and array_get can be used
together to provide short-circuit evaluation, overcoming the
limitations of both. See the LIMITATIONS section for an example.
ifsetor: as discussed above, ifsetor wasn't a regular function. It
required special language syntax support because it attempted to test
whether a direct parameter itself was set or unset, and was
ultimately rejected.
ifset: a related proposal to ifsetor, with a simpler syntax, ifset
was missing a way to control the default value.
See here for more discussion about the 'E_STRICT ternary pain-in-the-
ass expression' and alternatives:
http://keithdevens.com/weblog/archive/2005/Nov/24
http://www.php.net/~derick/meeting-notes.html#id39
http://devzone.zend.com/node/view/id/1481#Heading2
LIMITATIONS
This proposal doesn't address every requested feature. The third
parameter is always evaluated, so calling a slow function there would
be undesirable. However, the limitation appears to be unavoidable
without special language support, and there are workarounds. These
snippets have approximately equal meanings (though they may differ is
the handling of array values that convert to false):
array_get($_GET, 'foo', slowDefaultCalculation())
$val = array_get($_GET, 'foo'); if (!$val) $val =
slowDefaultCalculation();
array_get($_GET, 'foo') ?: slowDefaultCalculation()
The last example uses the new PHP 6 ?: operator.
This function applies only to array elements. Unlike other proposed
functions, it doesn't also attempt to determine whether variables are
set. However, the practical uses suggested for the other functions
generally ended up applying to array elements.
COMPATIBILITY FUNCTION FOR OLDER VERSIONS OF PHP
if (!function_exists('array_get')) {
function array_get($arr, $key, $default = false) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
}
else {
return $default;
}
}
}
(This version turned in the fastest times out of several variants.
Passing $arr by reference or attempting to return the result by
reference had a huge negative impact, and using the ternary ? :
operator instead of the if/else was slightly slower.)
=======
Andrew Shearer
http://ashearer.com/
Let me try that again with the files attached. I'll leave out the
full original proposal this time.
I had forgotten that attachments aren't allowed. Here are links to
the patch and test suite.
This ought to work. Sorry for the multiple posts, everyone.
http://ashearer.com/software/array_get/2007-09-10-php6/array_get.diff
http://ashearer.com/software/array_get/2007-09-10-php6/array_get.phpt
Let me try that again with the files attached. I'll leave out the
full original proposal this time.Here's a patch against HEAD that implements the array_get function
previously suggested on this list. I also attached a test suite,
which should go in ext/standard/tests/array/array_get.phpt.
Feedback is welcome.Independently, someone else had posted the same idea as a feature
request for PHP 5, and if there's interest I can backport it.40792 Open Wish: Function array_get(&$mixed, $key,
$defaultvalue)/* Prototype:
- mixed array_get ( array $search, mixed $key, mixed $default );
- Description:
- Returns the value corresponding to the given key if the key exists
- in the array. $key can be any value possible for an array index.
- If the key does not exist, the function returns $default, or
FALSE
- if $default is not specified. Also works on objects.
- Similar semantics to array_key_exists.
*/Here is the original proposal:
--
Andrew Shearer
http://ashearer.com/
Hi,
Please also add the patch provided by John Bafford last Januari.
Arnold
Andrew Shearer wrote:
I had forgotten that attachments aren't allowed. Here are links to the
patch and test suite.This ought to work. Sorry for the multiple posts, everyone.
http://ashearer.com/software/array_get/2007-09-10-php6/array_get.diff
http://ashearer.com/software/array_get/2007-09-10-php6/array_get.phptLet me try that again with the files attached. I'll leave out the
full original proposal this time.Here's a patch against HEAD that implements the array_get function
previously suggested on this list. I also attached a test suite,
which should go in ext/standard/tests/array/array_get.phpt. Feedback
is welcome.Independently, someone else had posted the same idea as a feature
request for PHP 5, and if there's interest I can backport it.40792 Open Wish: Function array_get(&$mixed, $key, $defaultvalue)
/* Prototype:
- mixed array_get ( array $search, mixed $key, mixed $default );
- Description:
- Returns the value corresponding to the given key if the key exists
- in the array. $key can be any value possible for an array index.
- If the key does not exist, the function returns $default, or
FALSE
- if $default is not specified. Also works on objects.
- Similar semantics to array_key_exists.
*/Here is the original proposal:
--
Andrew Shearer
http://ashearer.com/
Here's a patch against HEAD that implements the array_get function
previously suggested on this list. I also attached a test suite,
which should go in ext/standard/tests/array/array_get.phpt. Feedback
is welcome.Independently, someone else had posted the same idea as a feature
request for PHP 5, and if there's interest I can backport it.40792 Open Wish: Function array_get(&$mixed, $key, $defaultvalue)
/* Prototype:
- mixed array_get ( array $search, mixed $key, mixed $default );
- Description:
- Returns the value corresponding to the given key if the key exists
- in the array. $key can be any value possible for an array index.
- If the key does not exist, the function returns $default, or
FALSE
- if $default is not specified. Also works on objects.
- Similar semantics to array_key_exists.
*/
Can you explain, what's the difference between your implementation and this?
<?php
function array_get(&$array, $key, $default) {
if (isset($array[$key])) {
return $array[$key];
}
return $default;
}
?>
--
Wbr,
Antony Dovgal
Here's a patch against HEAD that implements the array_get function
previously suggested on this list. I also attached a test suite,
which should go in ext/standard/tests/array/array_get.phpt. Feedback
is welcome.Independently, someone else had posted the same idea as a feature
request for PHP 5, and if there's interest I can backport it.40792 Open Wish: Function array_get(&$mixed, $key,
$defaultvalue)/* Prototype:
- mixed array_get ( array $search, mixed $key, mixed $default );
- Description:
- Returns the value corresponding to the given key if the key exists
- in the array. $key can be any value possible for an array index.
- If the key does not exist, the function returns $default, or
FALSE
- if $default is not specified. Also works on objects.
- Similar semantics to array_key_exists.
*/Can you explain, what's the difference between your implementation
and this?<?php
function array_get(&$array, $key, $default) {
if (isset($array[$key])) {
return $array[$key];
}
return $default;
}?>
The overall idea is to enable cleaner code by having this function
available everywhere, including example snippets. This kind of
expression is needed all over the place, but is often verbosely
written out each time using an error-prone repetition of the array
reference. At best a custom function library is included just to get
some kind of similar function, which doesn't promote readability or
code sharing.
There are a few specific technical differences between the function
above and array_get. From the proposal:
=======
SEMANTICS
[...]
The semantics match
array_key_exists($key, $array) ? $array[$key] : $default
... but for comparison,
isset($array[$key]) ? $array[$key] : $default
is subtly different. The preferred array_key_exists version has these
differences:
1. If $array[$key] exists but has been set to null, that null
value will be returned instead of $default. This is likely to be the
least surprising thing to do.
2. If $array itself is unset, an error is generated. This is good.
The intention is to gracefully handle a missing $key. But if even
$array itself doesn't exist, there may be another problem, such as
misspelling the array variable. isset() ignores all errors, sweeping
more under the rug than we typically want.
IMPLEMENTATION
A core C implementation of array_get() benchmarked between two and
three times as fast as the implementation in PHP.
[...]
COMPATIBILITY FUNCTION FOR OLDER VERSIONS OF PHP
if (!function_exists('array_get')) {
function array_get($arr, $key, $default = false) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
}
else {
return $default;
}
}
}
(This version turned in the fastest times out of several variants.
Passing $arr by reference or attempting to return the result by
reference had a huge negative impact, and using the ternary ? :
operator instead of the if/else was slightly slower.)
=======
For the text of the full proposal (which I didn't include in my
followups as I slowly came to the realization that attachments were
being dropped), see:
http://marc.info/?l=php-internals&m=118946242013246&w=2
--
Andrew Shearer
http://ashearer.com/
Hello Andrew,
you can easily implement this function run time. It is not very flexible
and far away from what ifsetor was meant to be. Thus I do not think it is a
good idea. See comments below.
marcus
Tuesday, September 11, 2007, 12:12:55 AM, you wrote:
Here's a patch against HEAD that implements the array_get function
previously suggested on this list. I also attached a test suite,
which should go in ext/standard/tests/array/array_get.phpt. Feedback
is welcome.
Independently, someone else had posted the same idea as a feature
request for PHP 5, and if there's interest I can backport it.
40792 Open Wish: Function array_get(&$mixed, $key, $defaultvalue)
/* Prototype:
- mixed array_get ( array $search, mixed $key, mixed $default );
array should not be passed as reference as that would be a slowdown unless
the function is supposed to create the index key which according to the
specs below it doesn't.
- Description:
- Returns the value corresponding to the given key if the key exists
- in the array. $key can be any value possible for an array index.
- If the key does not exist, the function returns $default, or
FALSE
- if $default is not specified. Also works on objects.
- Similar semantics to array_key_exists.
*/
Here is the original proposal:
array_get, a more palatable alternative to ifsetor
Things this cannot do but ifsetor can.
- Check whether the array exists
- Mulitlevel queries
- Other types of queries (e.g. object members)
- In theory we could have ifsetor even return a writeable reference where a
non existing key would either be created or (pretty bad imo) a reference to
the default value gets returned.
MOTIVATION
There is an unmet need for an accessor that doesn't generate an
E_NOTICE
when the value is missing, as shown by ongoing discussions
and repeated requests for an ifsetor operator. However, ifsetor had a
special-case syntax and generally didn't fit very well with the rest
of the language.
http://devzone.zend.com/node/view/id/1481#Heading2 has a brief
summary. See the Related Functions and Proposals section for more.
Reading over those ideas (firstset(), coalesce(), :?, ifset(), and a
workaround usingsettype()
), most of the best uses boil down to
retrieving values from arrays.
PROPOSAL
As a simpler alternative to constructs such as this common double
array reference...$value = isset($_POST['command']) ? $_POST['command'] : '';
I propose an array_get function, like this...
$value = array_get($_POST, 'command', '');
The third argument provides a default. This function would require no
special syntax, and makes a very common construct easier to read and
less error-prone to type. It's a concise way of saying that missing
values can be handled gracefully.
Though request processing was used as an example, the function has
wide applicability across many other uses of associative arrays.
GREAT, BUT WHY NOT ADD IT TO AN INCLUDE FILE, INSTEAD OF THE CORE?
One of the goals is to make everyday PHP code simpler and clearer.
Writers of sample code snippets should be able to rely on array_get()
being available. Otherwise, they will not use it. Clearer sample code
particularly benefits beginners, who would probably find array_get
easier to understand, but anyone else who has to read or maintain
other people's code would benefit from its wide deployment in core as
well. The function is generally useful enough to be part of the
language, and the implementation in C is also more efficient than a
PHP version.
That said, a compatibility function for older versions of PHP is
given below.
SEMANTICS
mixed array_get(array $array, mixed $key[, mixed $default = FALSE]);
If $array contains the key $key, $array[$key] is returned. Otherwise
$default is returned.If $default is not specified, it defaults to FALSE. (NULL would also
be possible, and would more closely match other languages such as
Python with its dict.get method, but other PHP functions tend to
returnFALSE
to indicate no value.)The semantics match
array_key_exists($key, $array) ? $array[$key] : $default
... but for comparison,
isset($array[$key]) ? $array[$key] : $default
is subtly different. The preferred array_key_exists version has these
differences:
1. If $array[$key] exists but has been set to null, that null
value will be returned instead of $default. This is likely to be the
least surprising thing to do.
2. If $array itself is unset, an error is generated. This is good.
The intention is to gracefully handle a missing $key. But if even
$array itself doesn't exist, there may be another problem, such as
misspelling the array variable. isset() ignores all errors, sweeping
more under the rug than we typically want.
IMPLEMENTATION
A core C implementation of array_get() benchmarked between two and
three times as fast as the implementation in PHP. I'll attach the
patch after responding to feedback.
See the last section for the code of the PHP implementation.
RELATED FUNCTIONS AND PROPOSALS
This function is different than the array_get function proposed and
rejected in http://bugs.php.net/bug.php?id=28185. That function had
no default value and throws a notice when the key doesn't exist,
eliminating the major purpose of this function.
The ?: operator doesn't serve the same purpose, because it causes an
E_NOTICE
for missing values. However, ?: and array_get can be used
together to provide short-circuit evaluation, overcoming the
limitations of both. See the LIMITATIONS section for an example.
ifsetor: as discussed above, ifsetor wasn't a regular function. It
required special language syntax support because it attempted to test
whether a direct parameter itself was set or unset, and was
ultimately rejected.
ifset: a related proposal to ifsetor, with a simpler syntax, ifset
was missing a way to control the default value.
See here for more discussion about the 'E_STRICT ternary pain-in-the-
ass expression' and alternatives:
http://keithdevens.com/weblog/archive/2005/Nov/24
http://www.php.net/~derick/meeting-notes.html#id39
http://devzone.zend.com/node/view/id/1481#Heading2
LIMITATIONS
This proposal doesn't address every requested feature. The third
parameter is always evaluated, so calling a slow function there would
be undesirable. However, the limitation appears to be unavoidable
without special language support, and there are workarounds. These
snippets have approximately equal meanings (though they may differ is
the handling of array values that convert to false):
array_get($_GET, 'foo', slowDefaultCalculation())
$val = array_get($_GET, 'foo'); if (!$val) $val =
slowDefaultCalculation();
array_get($_GET, 'foo') ?: slowDefaultCalculation()
The last example uses the new PHP 6 ?: operator.
This function applies only to array elements. Unlike other proposed
functions, it doesn't also attempt to determine whether variables are
set. However, the practical uses suggested for the other functions
generally ended up applying to array elements.
COMPATIBILITY FUNCTION FOR OLDER VERSIONS OF PHP
if (!function_exists('array_get')) {
function array_get($arr, $key, $default = false) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
}
else {
return $default;
}
}
}
(This version turned in the fastest times out of several variants.
Passing $arr by reference or attempting to return the result by
reference had a huge negative impact, and using the ternary ? :
operator instead of the if/else was slightly slower.)
=======
Andrew Shearer
http://ashearer.com/
Best regards,
Marcus
If there's a workable proposal for ifsetor() that fixes the concerns
brought up by the original and is likely to go in PHP 6, that would
be great.
In this case, perfect can be the enemy of good. array_get() helps
with many common use cases of ifsetor() while fitting into the the
standard PHP syntax and function model, potentially making its
adoption much easier.
See below for answers to what you mentioned.
Hello Andrew,
you can easily implement this function run time. It is not very
flexible
and far away from what ifsetor was meant to be. Thus I do not think
it is a
good idea. See comments below.marcus
Tuesday, September 11, 2007, 12:12:55 AM, you wrote:
Here's a patch against HEAD that implements the array_get function
previously suggested on this list. I also attached a test suite,
which should go in ext/standard/tests/array/array_get.phpt. Feedback
is welcome.Independently, someone else had posted the same idea as a feature
request for PHP 5, and if there's interest I can backport it.40792 Open Wish: Function array_get(&$mixed, $key,
$defaultvalue)/* Prototype:
- mixed array_get ( array $search, mixed $key, mixed $default );
array should not be passed as reference as that would be a slowdown
unless
the function is supposed to create the index key which according to
the
specs below it doesn't.
True, as you suggest, it is not passed by reference. (That bug title
was posted independently by someone who might not have thought that
particular aspect through, and it isn't important to the text.)
- Description:
- Returns the value corresponding to the given key if the key exists
- in the array. $key can be any value possible for an array index.
- If the key does not exist, the function returns $default, or
FALSE
- if $default is not specified. Also works on objects.
- Similar semantics to array_key_exists.
*/Here is the original proposal:
array_get, a more palatable alternative to ifsetor
Things this cannot do but ifsetor can.
- Check whether the array exists
True, though there's an argument that this could even be better (less
error-prone) for the typical uses I've seen in my code and elsewhere,
where we're interested in whether the key exists in an array we
already have. An isset-like function doesn't allow you to separate
the two existence checks, allowing spelling errors in the array name
to go undetected when they could easily be caught. In circumstances
where you really do need to check both, you can call isset() or !empty
() on the array first:
$value = isset($array) ? array_get($array, 'mykey') : FALSE;
- Mulitlevel queries
Use nested array_get().
- Other types of queries (e.g. object members)
array_get() supports object members, just likearray_key_exists()
.
- In theory we could have ifsetor even return a writeable reference
where a
non existing key would either be created or (pretty bad imo) a
reference to
the default value gets returned.
Something like that would be nice, but it doesn't exist and I haven't
seen a concrete proposal for it.
MOTIVATION
There is an unmet need for an accessor that doesn't generate an
E_NOTICE
when the value is missing, as shown by ongoing discussions
and repeated requests for an ifsetor operator. However, ifsetor had a
special-case syntax and generally didn't fit very well with the rest
of the language.http://devzone.zend.com/node/view/id/1481#Heading2 has a brief
summary. See the Related Functions and Proposals section for more.Reading over those ideas (firstset(), coalesce(), :?, ifset(), and a
workaround usingsettype()
), most of the best uses boil down to
retrieving values from arrays.PROPOSAL
As a simpler alternative to constructs such as this common double
array reference...$value = isset($_POST['command']) ? $_POST
['command'] : '';
I propose an array_get function, like this...
$value = array_get($_POST, 'command', '');
The third argument provides a default. This function would require no
special syntax, and makes a very common construct easier to read and
less error-prone to type. It's a concise way of saying that missing
values can be handled gracefully.Though request processing was used as an example, the function has
wide applicability across many other uses of associative arrays.GREAT, BUT WHY NOT ADD IT TO AN INCLUDE FILE, INSTEAD OF THE CORE?
One of the goals is to make everyday PHP code simpler and clearer.
Writers of sample code snippets should be able to rely on array_get()
being available. Otherwise, they will not use it. Clearer sample code
particularly benefits beginners, who would probably find array_get
easier to understand, but anyone else who has to read or maintain
other people's code would benefit from its wide deployment in core as
well. The function is generally useful enough to be part of the
language, and the implementation in C is also more efficient than a
PHP version.That said, a compatibility function for older versions of PHP is
given below.SEMANTICS
mixed array_get(array $array, mixed $key[, mixed
$default = FALSE]);
If $array contains the key $key, $array[$key] is returned. Otherwise
$default is returned.If $default is not specified, it defaults to FALSE. (NULL would also
be possible, and would more closely match other languages such as
Python with its dict.get method, but other PHP functions tend to
returnFALSE
to indicate no value.)The semantics match
array_key_exists($key, $array) ? $array[$key] :
$default
... but for comparison,
isset($array[$key]) ? $array[$key] : $default
is subtly different. The preferred array_key_exists version has these
differences:
1. If $array[$key] exists but has been set to null, that
null
value will be returned instead of $default. This is likely to be the
least surprising thing to do.
2. If $array itself is unset, an error is generated.
This is good.
The intention is to gracefully handle a missing $key. But if even
$array itself doesn't exist, there may be another problem, such as
misspelling the array variable. isset() ignores all errors, sweeping
more under the rug than we typically want.IMPLEMENTATION
A core C implementation of array_get() benchmarked between two and
three times as fast as the implementation in PHP. I'll attach the
patch after responding to feedback.See the last section for the code of the PHP implementation.
RELATED FUNCTIONS AND PROPOSALS
This function is different than the array_get function proposed and
rejected in http://bugs.php.net/bug.php?id=28185. That function had
no default value and throws a notice when the key doesn't exist,
eliminating the major purpose of this function.The ?: operator doesn't serve the same purpose, because it causes an
E_NOTICE
for missing values. However, ?: and array_get can be used
together to provide short-circuit evaluation, overcoming the
limitations of both. See the LIMITATIONS section for an example.ifsetor: as discussed above, ifsetor wasn't a regular function. It
required special language syntax support because it attempted to test
whether a direct parameter itself was set or unset, and was
ultimately rejected.ifset: a related proposal to ifsetor, with a simpler syntax, ifset
was missing a way to control the default value.See here for more discussion about the 'E_STRICT ternary pain-in-the-
ass expression' and alternatives:
http://keithdevens.com/weblog/archive/2005/Nov/24
http://www.php.net/~derick/meeting-notes.html#id39
http://devzone.zend.com/node/view/id/1481#Heading2LIMITATIONS
This proposal doesn't address every requested feature. The third
parameter is always evaluated, so calling a slow function there would
be undesirable. However, the limitation appears to be unavoidable
without special language support, and there are workarounds. These
snippets have approximately equal meanings (though they may differ is
the handling of array values that convert to false):array_get($_GET, 'foo', slowDefaultCalculation())
$val = array_get($_GET, 'foo'); if (!$val) $val =
slowDefaultCalculation();
array_get($_GET, 'foo') ?: slowDefaultCalculation()
The last example uses the new PHP 6 ?: operator.
This function applies only to array elements. Unlike other proposed
functions, it doesn't also attempt to determine whether variables are
set. However, the practical uses suggested for the other functions
generally ended up applying to array elements.COMPATIBILITY FUNCTION FOR OLDER VERSIONS OF PHP
if (!function_exists('array_get')) {
function array_get($arr, $key, $default = false) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
}
else {
return $default;
}
}
}(This version turned in the fastest times out of several variants.
Passing $arr by reference or attempting to return the result by
reference had a huge negative impact, and using the ternary ? :
operator instead of the if/else was slightly slower.)=======
Andrew Shearer
http://ashearer.com/
Best regards,
Marcus
Andrew Shearer
http://ashearer.com/
Hello Andrew,
did you check out '?:' shortcut in HEAD?
php -r 'echo 4?:2;' -> 4
php -r 'echo 0?:2;' -> 2
best regards
marcus
Tuesday, September 11, 2007, 3:20:46 PM, you wrote:
If there's a workable proposal for ifsetor() that fixes the concerns
brought up by the original and is likely to go in PHP 6, that would
be great.
In this case, perfect can be the enemy of good. array_get() helps
with many common use cases of ifsetor() while fitting into the the
standard PHP syntax and function model, potentially making its
adoption much easier.
See below for answers to what you mentioned.
Hello Andrew,
you can easily implement this function run time. It is not very
flexible
and far away from what ifsetor was meant to be. Thus I do not think
it is a
good idea. See comments below.marcus
Tuesday, September 11, 2007, 12:12:55 AM, you wrote:
Here's a patch against HEAD that implements the array_get function
previously suggested on this list. I also attached a test suite,
which should go in ext/standard/tests/array/array_get.phpt. Feedback
is welcome.Independently, someone else had posted the same idea as a feature
request for PHP 5, and if there's interest I can backport it.40792 Open Wish: Function array_get(&$mixed, $key,
$defaultvalue)/* Prototype:
- mixed array_get ( array $search, mixed $key, mixed $default );
array should not be passed as reference as that would be a slowdown
unless
the function is supposed to create the index key which according to
the
specs below it doesn't.
True, as you suggest, it is not passed by reference. (That bug title
was posted independently by someone who might not have thought that
particular aspect through, and it isn't important to the text.)
- Description:
- Returns the value corresponding to the given key if the key exists
- in the array. $key can be any value possible for an array index.
- If the key does not exist, the function returns $default, or
FALSE
- if $default is not specified. Also works on objects.
- Similar semantics to array_key_exists.
*/Here is the original proposal:
array_get, a more palatable alternative to ifsetor
Things this cannot do but ifsetor can.
- Check whether the array exists
True, though there's an argument that this could even be better (less
error-prone) for the typical uses I've seen in my code and elsewhere,
where we're interested in whether the key exists in an array we
already have. An isset-like function doesn't allow you to separate
the two existence checks, allowing spelling errors in the array name
to go undetected when they could easily be caught. In circumstances
where you really do need to check both, you can call isset() or !empty
() on the array first:
$value = isset($array) ? array_get($array, 'mykey') : FALSE;
- Mulitlevel queries
Use nested array_get().
- Other types of queries (e.g. object members)
array_get() supports object members, just likearray_key_exists()
.
- In theory we could have ifsetor even return a writeable reference
where a
non existing key would either be created or (pretty bad imo) a
reference to
the default value gets returned.
Something like that would be nice, but it doesn't exist and I haven't
seen a concrete proposal for it.
MOTIVATION
There is an unmet need for an accessor that doesn't generate an
E_NOTICE
when the value is missing, as shown by ongoing discussions
and repeated requests for an ifsetor operator. However, ifsetor had a
special-case syntax and generally didn't fit very well with the rest
of the language.http://devzone.zend.com/node/view/id/1481#Heading2 has a brief
summary. See the Related Functions and Proposals section for more.Reading over those ideas (firstset(), coalesce(), :?, ifset(), and a
workaround usingsettype()
), most of the best uses boil down to
retrieving values from arrays.PROPOSAL
As a simpler alternative to constructs such as this common double
array reference...$value = isset($_POST['command']) ? $_POST
['command'] : '';
I propose an array_get function, like this...
$value = array_get($_POST, 'command', '');
The third argument provides a default. This function would require no
special syntax, and makes a very common construct easier to read and
less error-prone to type. It's a concise way of saying that missing
values can be handled gracefully.Though request processing was used as an example, the function has
wide applicability across many other uses of associative arrays.GREAT, BUT WHY NOT ADD IT TO AN INCLUDE FILE, INSTEAD OF THE CORE?
One of the goals is to make everyday PHP code simpler and clearer.
Writers of sample code snippets should be able to rely on array_get()
being available. Otherwise, they will not use it. Clearer sample code
particularly benefits beginners, who would probably find array_get
easier to understand, but anyone else who has to read or maintain
other people's code would benefit from its wide deployment in core as
well. The function is generally useful enough to be part of the
language, and the implementation in C is also more efficient than a
PHP version.That said, a compatibility function for older versions of PHP is
given below.SEMANTICS
mixed array_get(array $array, mixed $key[, mixed
$default = FALSE]);
If $array contains the key $key, $array[$key] is returned. Otherwise
$default is returned.If $default is not specified, it defaults to FALSE. (NULL would also
be possible, and would more closely match other languages such as
Python with its dict.get method, but other PHP functions tend to
returnFALSE
to indicate no value.)The semantics match
array_key_exists($key, $array) ? $array[$key] :
$default
... but for comparison,
isset($array[$key]) ? $array[$key] : $default
is subtly different. The preferred array_key_exists version has these
differences:
1. If $array[$key] exists but has been set to null, that
null
value will be returned instead of $default. This is likely to be the
least surprising thing to do.
2. If $array itself is unset, an error is generated.
This is good.
The intention is to gracefully handle a missing $key. But if even
$array itself doesn't exist, there may be another problem, such as
misspelling the array variable. isset() ignores all errors, sweeping
more under the rug than we typically want.IMPLEMENTATION
A core C implementation of array_get() benchmarked between two and
three times as fast as the implementation in PHP. I'll attach the
patch after responding to feedback.See the last section for the code of the PHP implementation.
RELATED FUNCTIONS AND PROPOSALS
This function is different than the array_get function proposed and
rejected in http://bugs.php.net/bug.php?id=28185. That function had
no default value and throws a notice when the key doesn't exist,
eliminating the major purpose of this function.The ?: operator doesn't serve the same purpose, because it causes an
E_NOTICE
for missing values. However, ?: and array_get can be used
together to provide short-circuit evaluation, overcoming the
limitations of both. See the LIMITATIONS section for an example.ifsetor: as discussed above, ifsetor wasn't a regular function. It
required special language syntax support because it attempted to test
whether a direct parameter itself was set or unset, and was
ultimately rejected.ifset: a related proposal to ifsetor, with a simpler syntax, ifset
was missing a way to control the default value.See here for more discussion about the 'E_STRICT ternary pain-in-the-
ass expression' and alternatives:
http://keithdevens.com/weblog/archive/2005/Nov/24
http://www.php.net/~derick/meeting-notes.html#id39
http://devzone.zend.com/node/view/id/1481#Heading2LIMITATIONS
This proposal doesn't address every requested feature. The third
parameter is always evaluated, so calling a slow function there would
be undesirable. However, the limitation appears to be unavoidable
without special language support, and there are workarounds. These
snippets have approximately equal meanings (though they may differ is
the handling of array values that convert to false):array_get($_GET, 'foo', slowDefaultCalculation())
$val = array_get($_GET, 'foo'); if (!$val) $val =
slowDefaultCalculation();
array_get($_GET, 'foo') ?: slowDefaultCalculation()
The last example uses the new PHP 6 ?: operator.
This function applies only to array elements. Unlike other proposed
functions, it doesn't also attempt to determine whether variables are
set. However, the practical uses suggested for the other functions
generally ended up applying to array elements.COMPATIBILITY FUNCTION FOR OLDER VERSIONS OF PHP
if (!function_exists('array_get')) {
function array_get($arr, $key, $default = false) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
}
else {
return $default;
}
}
}(This version turned in the fastest times out of several variants.
Passing $arr by reference or attempting to return the result by
reference had a huge negative impact, and using the ternary ? :
operator instead of the if/else was slightly slower.)=======
Andrew Shearer
http://ashearer.com/
Best regards,
Marcus
Andrew Shearer
http://ashearer.com/
Best regards,
Marcus
Hello Andrew,
did you check out '?:' shortcut in HEAD?
php -r 'echo 4?:2;' -> 4
php -r 'echo 0?:2;' -> 2best regards
marcus
Yes, I had hoped that the ?: operator would solve this. But it doesn't
serve the same purpose, because it causes an E_NOTICE
for missing
values. However, ?: and array_get can be used together to provide
short-circuit evaluation, overcoming the limitations of both.
Example:
array_get($_GET, 'foo') ?: slowDefaultCalculation()
Here is a test of ?: with CVS HEAD + the array_get function:
var_dump($_SERVER['test'] ?: 'nope');
PHP Notice: Undefined index: test in - on line 2
string(4) "nope"
var_dump(array_get($_SERVER, 'test', 'nope'));
string(4) "nope"
Tuesday, September 11, 2007, 3:20:46 PM, you wrote:
If there's a workable proposal for ifsetor() that fixes the concerns
brought up by the original and is likely to go in PHP 6, that would
be great.In this case, perfect can be the enemy of good. array_get() helps
with many common use cases of ifsetor() while fitting into the the
standard PHP syntax and function model, potentially making its
adoption much easier.See below for answers to what you mentioned.
Hello Andrew,
you can easily implement this function run time. It is not very
flexible
and far away from what ifsetor was meant to be. Thus I do not think
it is a
good idea. See comments below.marcus
Tuesday, September 11, 2007, 12:12:55 AM, you wrote:
Here's a patch against HEAD that implements the array_get function
previously suggested on this list. I also attached a test suite,
which should go in ext/standard/tests/array/array_get.phpt. Feedback
is welcome.Independently, someone else had posted the same idea as a feature
request for PHP 5, and if there's interest I can backport it.40792 Open Wish: Function array_get(&$mixed, $key,
$defaultvalue)/* Prototype:
- mixed array_get ( array $search, mixed $key, mixed $default );
array should not be passed as reference as that would be a slowdown
unless
the function is supposed to create the index key which according to
the
specs below it doesn't.True, as you suggest, it is not passed by reference. (That bug title
was posted independently by someone who might not have thought that
particular aspect through, and it isn't important to the text.)
- Description:
- Returns the value corresponding to the given key if the key exists
- in the array. $key can be any value possible for an array index.
- If the key does not exist, the function returns $default, or
FALSE
- if $default is not specified. Also works on objects.
- Similar semantics to array_key_exists.
*/Here is the original proposal:
array_get, a more palatable alternative to ifsetor
Things this cannot do but ifsetor can.
- Check whether the array exists
True, though there's an argument that this could even be better (less
error-prone) for the typical uses I've seen in my code and elsewhere,
where we're interested in whether the key exists in an array we
already have. An isset-like function doesn't allow you to separate
the two existence checks, allowing spelling errors in the array name
to go undetected when they could easily be caught. In circumstances
where you really do need to check both, you can call isset() or !empty
() on the array first:
$value = isset($array) ? array_get($array, 'mykey') : FALSE;
- Mulitlevel queries
Use nested array_get().
- Other types of queries (e.g. object members)
array_get() supports object members, just likearray_key_exists()
.
- In theory we could have ifsetor even return a writeable reference
where a
non existing key would either be created or (pretty bad imo) a
reference to
the default value gets returned.
Something like that would be nice, but it doesn't exist and I haven't
seen a concrete proposal for it.MOTIVATION
There is an unmet need for an accessor that doesn't generate an
E_NOTICE
when the value is missing, as shown by ongoing discussions
and repeated requests for an ifsetor operator. However, ifsetor had a
special-case syntax and generally didn't fit very well with the rest
of the language.http://devzone.zend.com/node/view/id/1481#Heading2 has a brief
summary. See the Related Functions and Proposals section for more.Reading over those ideas (firstset(), coalesce(), :?, ifset(), and a
workaround usingsettype()
), most of the best uses boil down to
retrieving values from arrays.PROPOSAL
As a simpler alternative to constructs such as this common double
array reference...$value = isset($_POST['command']) ? $_POST
['command'] : '';
I propose an array_get function, like this...
$value = array_get($_POST, 'command', '');
The third argument provides a default. This function would require no
special syntax, and makes a very common construct easier to read and
less error-prone to type. It's a concise way of saying that missing
values can be handled gracefully.Though request processing was used as an example, the function has
wide applicability across many other uses of associative arrays.GREAT, BUT WHY NOT ADD IT TO AN INCLUDE FILE, INSTEAD OF THE CORE?
One of the goals is to make everyday PHP code simpler and clearer.
Writers of sample code snippets should be able to rely on array_get()
being available. Otherwise, they will not use it. Clearer sample code
particularly benefits beginners, who would probably find array_get
easier to understand, but anyone else who has to read or maintain
other people's code would benefit from its wide deployment in core as
well. The function is generally useful enough to be part of the
language, and the implementation in C is also more efficient than a
PHP version.That said, a compatibility function for older versions of PHP is
given below.SEMANTICS
mixed array_get(array $array, mixed $key[, mixed
$default = FALSE]);
If $array contains the key $key, $array[$key] is returned. Otherwise
$default is returned.If $default is not specified, it defaults to FALSE. (NULL would also
be possible, and would more closely match other languages such as
Python with its dict.get method, but other PHP functions tend to
returnFALSE
to indicate no value.)The semantics match
array_key_exists($key, $array) ? $array[$key] :
$default
... but for comparison,
isset($array[$key]) ? $array[$key] : $default
is subtly different. The preferred array_key_exists version has these
differences:
1. If $array[$key] exists but has been set to null, that
null
value will be returned instead of $default. This is likely to be the
least surprising thing to do.
2. If $array itself is unset, an error is generated.
This is good.
The intention is to gracefully handle a missing $key. But if even
$array itself doesn't exist, there may be another problem, such as
misspelling the array variable. isset() ignores all errors, sweeping
more under the rug than we typically want.IMPLEMENTATION
A core C implementation of array_get() benchmarked between two and
three times as fast as the implementation in PHP. I'll attach the
patch after responding to feedback.See the last section for the code of the PHP implementation.
RELATED FUNCTIONS AND PROPOSALS
This function is different than the array_get function proposed and
rejected in http://bugs.php.net/bug.php?id=28185. That function had
no default value and throws a notice when the key doesn't exist,
eliminating the major purpose of this function.The ?: operator doesn't serve the same purpose, because it causes an
E_NOTICE
for missing values. However, ?: and array_get can be used
together to provide short-circuit evaluation, overcoming the
limitations of both. See the LIMITATIONS section for an example.ifsetor: as discussed above, ifsetor wasn't a regular function. It
required special language syntax support because it attempted to test
whether a direct parameter itself was set or unset, and was
ultimately rejected.ifset: a related proposal to ifsetor, with a simpler syntax, ifset
was missing a way to control the default value.See here for more discussion about the 'E_STRICT ternary pain-in-the-
ass expression' and alternatives:
http://keithdevens.com/weblog/archive/2005/Nov/24
http://www.php.net/~derick/meeting-notes.html#id39
http://devzone.zend.com/node/view/id/1481#Heading2LIMITATIONS
This proposal doesn't address every requested feature. The third
parameter is always evaluated, so calling a slow function there would
be undesirable. However, the limitation appears to be unavoidable
without special language support, and there are workarounds. These
snippets have approximately equal meanings (though they may differ is
the handling of array values that convert to false):array_get($_GET, 'foo', slowDefaultCalculation())
$val = array_get($_GET, 'foo'); if (!$val) $val =
slowDefaultCalculation();
array_get($_GET, 'foo') ?: slowDefaultCalculation()
The last example uses the new PHP 6 ?: operator.
This function applies only to array elements. Unlike other proposed
functions, it doesn't also attempt to determine whether variables are
set. However, the practical uses suggested for the other functions
generally ended up applying to array elements.COMPATIBILITY FUNCTION FOR OLDER VERSIONS OF PHP
if (!function_exists('array_get')) {
function array_get($arr, $key, $default = false) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
}
else {
return $default;
}
}
}(This version turned in the fastest times out of several variants.
Passing $arr by reference or attempting to return the result by
reference had a huge negative impact, and using the ternary ? :
operator instead of the if/else was slightly slower.)=======
Andrew Shearer
http://ashearer.com/
Best regards,
MarcusAndrew Shearer
http://ashearer.com/Best regards,
Marcus
Hello Andrew,
how about @<expression>?:<default> style?
Like: $val = $myarray[$key] ?: $default;
marcus
Tuesday, September 11, 2007, 6:33:42 PM, you wrote:
Hello Andrew,
did you check out '?:' shortcut in HEAD?
php -r 'echo 4?:2;' -> 4
php -r 'echo 0?:2;' -> 2best regards
marcus
Yes, I had hoped that the ?: operator would solve this. But it doesn't
serve the same purpose, because it causes anE_NOTICE
for missing
values. However, ?: and array_get can be used together to provide
short-circuit evaluation, overcoming the limitations of both.
Example:
array_get($_GET, 'foo') ?: slowDefaultCalculation()
Here is a test of ?: with CVS HEAD + the array_get function:
var_dump($_SERVER['test'] ?: 'nope');
PHP Notice: Undefined index: test in - on line 2
string(4) "nope"
var_dump(array_get($_SERVER, 'test', 'nope'));
string(4) "nope"
Tuesday, September 11, 2007, 3:20:46 PM, you wrote:
If there's a workable proposal for ifsetor() that fixes the concerns
brought up by the original and is likely to go in PHP 6, that would
be great.In this case, perfect can be the enemy of good. array_get() helps
with many common use cases of ifsetor() while fitting into the the
standard PHP syntax and function model, potentially making its
adoption much easier.See below for answers to what you mentioned.
Hello Andrew,
you can easily implement this function run time. It is not very
flexible
and far away from what ifsetor was meant to be. Thus I do not think
it is a
good idea. See comments below.marcus
Tuesday, September 11, 2007, 12:12:55 AM, you wrote:
Here's a patch against HEAD that implements the array_get function
previously suggested on this list. I also attached a test suite,
which should go in ext/standard/tests/array/array_get.phpt. Feedback
is welcome.Independently, someone else had posted the same idea as a feature
request for PHP 5, and if there's interest I can backport it.40792 Open Wish: Function array_get(&$mixed, $key,
$defaultvalue)/* Prototype:
- mixed array_get ( array $search, mixed $key, mixed $default );
array should not be passed as reference as that would be a slowdown
unless
the function is supposed to create the index key which according to
the
specs below it doesn't.True, as you suggest, it is not passed by reference. (That bug title
was posted independently by someone who might not have thought that
particular aspect through, and it isn't important to the text.)
- Description:
- Returns the value corresponding to the given key if the key exists
- in the array. $key can be any value possible for an array index.
- If the key does not exist, the function returns $default, or
FALSE
- if $default is not specified. Also works on objects.
- Similar semantics to array_key_exists.
*/Here is the original proposal:
array_get, a more palatable alternative to ifsetor
Things this cannot do but ifsetor can.
- Check whether the array exists
True, though there's an argument that this could even be better (less
error-prone) for the typical uses I've seen in my code and elsewhere,
where we're interested in whether the key exists in an array we
already have. An isset-like function doesn't allow you to separate
the two existence checks, allowing spelling errors in the array name
to go undetected when they could easily be caught. In circumstances
where you really do need to check both, you can call isset() or !empty
() on the array first:
$value = isset($array) ? array_get($array, 'mykey') : FALSE;
- Mulitlevel queries
Use nested array_get().
- Other types of queries (e.g. object members)
array_get() supports object members, just likearray_key_exists()
.
- In theory we could have ifsetor even return a writeable reference
where a
non existing key would either be created or (pretty bad imo) a
reference to
the default value gets returned.
Something like that would be nice, but it doesn't exist and I haven't
seen a concrete proposal for it.MOTIVATION
There is an unmet need for an accessor that doesn't generate an
E_NOTICE
when the value is missing, as shown by ongoing discussions
and repeated requests for an ifsetor operator. However, ifsetor had a
special-case syntax and generally didn't fit very well with the rest
of the language.http://devzone.zend.com/node/view/id/1481#Heading2 has a brief
summary. See the Related Functions and Proposals section for more.Reading over those ideas (firstset(), coalesce(), :?, ifset(), and a
workaround usingsettype()
), most of the best uses boil down to
retrieving values from arrays.PROPOSAL
As a simpler alternative to constructs such as this common double
array reference...$value = isset($_POST['command']) ? $_POST
['command'] : '';
I propose an array_get function, like this...
$value = array_get($_POST, 'command', '');
The third argument provides a default. This function would require no
special syntax, and makes a very common construct easier to read and
less error-prone to type. It's a concise way of saying that missing
values can be handled gracefully.Though request processing was used as an example, the function has
wide applicability across many other uses of associative arrays.GREAT, BUT WHY NOT ADD IT TO AN INCLUDE FILE, INSTEAD OF THE CORE?
One of the goals is to make everyday PHP code simpler and clearer.
Writers of sample code snippets should be able to rely on array_get()
being available. Otherwise, they will not use it. Clearer sample code
particularly benefits beginners, who would probably find array_get
easier to understand, but anyone else who has to read or maintain
other people's code would benefit from its wide deployment in core as
well. The function is generally useful enough to be part of the
language, and the implementation in C is also more efficient than a
PHP version.That said, a compatibility function for older versions of PHP is
given below.SEMANTICS
mixed array_get(array $array, mixed $key[, mixed
$default = FALSE]);
If $array contains the key $key, $array[$key] is returned. Otherwise
$default is returned.If $default is not specified, it defaults to FALSE. (NULL would also
be possible, and would more closely match other languages such as
Python with its dict.get method, but other PHP functions tend to
returnFALSE
to indicate no value.)The semantics match
array_key_exists($key, $array) ? $array[$key] :
$default
... but for comparison,
isset($array[$key]) ? $array[$key] : $default
is subtly different. The preferred array_key_exists version has these
differences:
1. If $array[$key] exists but has been set to null, that
null
value will be returned instead of $default. This is likely to be the
least surprising thing to do.
2. If $array itself is unset, an error is generated.
This is good.
The intention is to gracefully handle a missing $key. But if even
$array itself doesn't exist, there may be another problem, such as
misspelling the array variable. isset() ignores all errors, sweeping
more under the rug than we typically want.IMPLEMENTATION
A core C implementation of array_get() benchmarked between two and
three times as fast as the implementation in PHP. I'll attach the
patch after responding to feedback.See the last section for the code of the PHP implementation.
RELATED FUNCTIONS AND PROPOSALS
This function is different than the array_get function proposed and
rejected in http://bugs.php.net/bug.php?id=28185. That function had
no default value and throws a notice when the key doesn't exist,
eliminating the major purpose of this function.The ?: operator doesn't serve the same purpose, because it causes an
E_NOTICE
for missing values. However, ?: and array_get can be used
together to provide short-circuit evaluation, overcoming the
limitations of both. See the LIMITATIONS section for an example.ifsetor: as discussed above, ifsetor wasn't a regular function. It
required special language syntax support because it attempted to test
whether a direct parameter itself was set or unset, and was
ultimately rejected.ifset: a related proposal to ifsetor, with a simpler syntax, ifset
was missing a way to control the default value.See here for more discussion about the 'E_STRICT ternary pain-in-the-
ass expression' and alternatives:
http://keithdevens.com/weblog/archive/2005/Nov/24
http://www.php.net/~derick/meeting-notes.html#id39
http://devzone.zend.com/node/view/id/1481#Heading2LIMITATIONS
This proposal doesn't address every requested feature. The third
parameter is always evaluated, so calling a slow function there would
be undesirable. However, the limitation appears to be unavoidable
without special language support, and there are workarounds. These
snippets have approximately equal meanings (though they may differ is
the handling of array values that convert to false):array_get($_GET, 'foo', slowDefaultCalculation())
$val = array_get($_GET, 'foo'); if (!$val) $val =
slowDefaultCalculation();
array_get($_GET, 'foo') ?: slowDefaultCalculation()
The last example uses the new PHP 6 ?: operator.
This function applies only to array elements. Unlike other proposed
functions, it doesn't also attempt to determine whether variables are
set. However, the practical uses suggested for the other functions
generally ended up applying to array elements.COMPATIBILITY FUNCTION FOR OLDER VERSIONS OF PHP
if (!function_exists('array_get')) {
function array_get($arr, $key, $default = false) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
}
else {
return $default;
}
}
}(This version turned in the fastest times out of several variants.
Passing $arr by reference or attempting to return the result by
reference had a huge negative impact, and using the ternary ? :
operator instead of the if/else was slightly slower.)=======
Andrew Shearer
http://ashearer.com/
Best regards,
MarcusAndrew Shearer
http://ashearer.com/Best regards,
Marcus
Best regards,
Marcus
Hello Andrew,
how about @<expression>?:<default> style?
Like: $val = $myarray[$key] ?: $default;
Did you mean like:
@$val = $myarray[$key] ?: $default;
Because that's an expensive assignment since it will hit the error
handler when the index is not assigned. I thought the ifsetor system was
going to throttle undefined index notices for the left operand.
Cheers,
Rob.
...........................................................
SwarmBuy.com - http://www.swarmbuy.com
Leveraging the buying power of the masses!
...........................................................
Hello Robert,
yeah ifsetor if much better than the @-?: combination. But for 5.3 that
would be all we could do. For 6 and in the long run we might do a real
ifsetor. If ever we could come to a consensus... and no i don't really like
to restart discussions on ifsetor at this point.
marcus
Tuesday, September 11, 2007, 7:17:02 PM, you wrote:
Hello Andrew,
how about @<expression>?:<default> style?
Like: $val = $myarray[$key] ?: $default;
Did you mean like:
@$val = $myarray[$key] ?: $default;
Because that's an expensive assignment since it will hit the error
handler when the index is not assigned. I thought the ifsetor system was
going to throttle undefined index notices for the left operand.
Cheers,
Rob............................................................
SwarmBuy.com - http://www.swarmbuy.com
Leveraging the buying power of the masses!
...........................................................
Best regards,
Marcus
Hello Robert,
yeah ifsetor if much better than the @-?: combination. But for 5.3 that
would be all we could do. For 6 and in the long run we might do a real
ifsetor. If ever we could come to a consensus... and no i don't really
like
to restart discussions on ifsetor at this point.
It was my understanding that ifsetor had been rejected long ago, after going
around the list a few times after your proposal of it in 2004. I'd hate to
hold up other language progress in the hopes of eventually restarting
discussion on it, unless you'd like to bring a modified proposal now.
Meanwhile, array_get() provides the most-needed functionality while avoiding
the issues that prevented ifsetor's acceptance.
There's a backward compatibility problem with ifsetor: its special syntax
means that there's no way to write a pure-PHP userland version of it. The
effect is that there's no upgrade path for applications that have to
straddle both old and new versions of PHP, and practical usefulness of
ifsetor would be delayed for years after release.
Of course, accepting array_get() now would not preclude bringing up ifsetor
again someday on its unique merits.
Here is the patch and unit test file for array_get():
And here is the backward compatibility function:
if (!function_exists('array_get')) {
function array_get($arr, $key, $default = false) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
}
else {
return $default;
}
}
}
Tuesday, September 11, 2007, 7:17:02 PM, you wrote:
Hello Andrew,
how about @<expression>?:<default> style?
Like: $val = $myarray[$key] ?: $default;
Did you mean like:
@$val = $myarray[$key] ?: $default;
Because that's an expensive assignment since it will hit the error
handler when the index is not assigned. I thought the ifsetor system was
going to throttle undefined index notices for the left operand.Cheers,
Rob.
Best regards,
Marcus
Here is the patch and unit test file for array_get():
http://ashearer.com/software/array_get/2007-09-10-php6/array_get.diff
http://ashearer.com/software/array_get/2007-09-10-php6/array_get.phptAnd here is the backward compatibility function:
if (!function_exists('array_get')) {
function array_get($arr, $key, $default = false) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
}
else {
return $default;
}
}
}
IMHO the default value for $default should be null. That way it has the
same return value as using an undefined index on an array.
Comments?
Cheers,
Rob.
...........................................................
SwarmBuy.com - http://www.swarmbuy.com
Leveraging the buying power of the masses!
...........................................................
Andrew Shearer wrote:
Meanwhile, array_get() provides the most-needed functionality while avoiding
the issues that prevented ifsetor's acceptance.
Aside from lack of BC hacks what is the issue? I remember some fussing
about the name, but I find this a joke of an argument. You cant get much
clearer a name than ifsetor().
There's a backward compatibility problem with ifsetor: its special syntax
means that there's no way to write a pure-PHP userland version of it. The
effect is that there's no upgrade path for applications that have to
straddle both old and new versions of PHP, and practical usefulness of
ifsetor would be delayed for years after release.
I use ifsetor() type functionality on a daily basis. As such I would
appreciate it if it would be an operator and would make its way not only
into php 6, but also php 5.3.
Marcus's half solution is not a solution to what I need. Andrew's
solution gets close enough to solve my real world needs. Now if I could
just see the slightest bit if a real argument against ifsetor(), I might
even vote for array_get() (not sure if I appreciate the name though).
regards,
Lukas
Andrew Shearer wrote:
Meanwhile, array_get() provides the most-needed functionality
while avoiding
the issues that prevented ifsetor's acceptance.Aside from lack of BC hacks what is the issue? I remember some
fussing about the name, but I find this a joke of an argument. You
cant get much clearer a name than ifsetor().There's a backward compatibility problem with ifsetor: its special
syntax
means that there's no way to write a pure-PHP userland version of
it. The
effect is that there's no upgrade path for applications that have to
straddle both old and new versions of PHP, and practical
usefulness of
ifsetor would be delayed for years after release.I use ifsetor() type functionality on a daily basis. As such I
would appreciate it if it would be an operator and would make its
way not only into php 6, but also php 5.3.Marcus's half solution is not a solution to what I need. Andrew's
solution gets close enough to solve my real world needs. Now if I
could just see the slightest bit if a real argument against ifsetor
(), I might even vote for array_get() (not sure if I appreciate the
name though).regards,
Lukas
I think we want the same thing. We both want the essential
functionality in PHP one way or another. If ifsetor was in the
running now, I'd support it. But after seeing the discussion and lack
of consensus on it since 2004, I'm sure that the best way to reach
the goal is to champion array_get().
Other suggestions for the name are welcome, but the choice of it was
careful. array_get() has at least one precendent, the Python dict.get
() method, which works basically the same way. The fact that the same
name and function signature (give or take a reference) was also
suggested completely independently in a PHP wishlist item means it's
probably on the right track.
--
Andrew Shearer
http://ashearer.com/
Hello Andrew,
if we go the array_get() route as a short half solution to hopefully make
a lot of people happy (at least it would serve $_GET/_REQUEST etc needs).
Then I think we should make it a bit more useable:
Get the default or the multilevel subscription of $ar
proto mixed array_get(array $ar, mixed index*, mixed $default)
function array_get(array $ar) {
$ret = $ar;
for ($i=1; $i < func_num_args()
- 1; ++$i) {
$idx = func_get_arg($i);
if (array_key_exists($idx, $ret)) {
$ret = $ret[$idx];
} else {
if (func_num_args() > 1) {
return func_get_arg(func_num_args() - 1);
} else {
return NULL;
}
}
}
return $ret;
}
best regards
marcus
Thursday, September 13, 2007, 2:54:51 PM, you wrote:
Andrew Shearer wrote:
Meanwhile, array_get() provides the most-needed functionality
while avoiding
the issues that prevented ifsetor's acceptance.Aside from lack of BC hacks what is the issue? I remember some
fussing about the name, but I find this a joke of an argument. You
cant get much clearer a name than ifsetor().There's a backward compatibility problem with ifsetor: its special
syntax
means that there's no way to write a pure-PHP userland version of
it. The
effect is that there's no upgrade path for applications that have to
straddle both old and new versions of PHP, and practical
usefulness of
ifsetor would be delayed for years after release.I use ifsetor() type functionality on a daily basis. As such I
would appreciate it if it would be an operator and would make its
way not only into php 6, but also php 5.3.Marcus's half solution is not a solution to what I need. Andrew's
solution gets close enough to solve my real world needs. Now if I
could just see the slightest bit if a real argument against ifsetor
(), I might even vote for array_get() (not sure if I appreciate the
name though).regards,
Lukas
I think we want the same thing. We both want the essential
functionality in PHP one way or another. If ifsetor was in the
running now, I'd support it. But after seeing the discussion and lack
of consensus on it since 2004, I'm sure that the best way to reach
the goal is to champion array_get().
Other suggestions for the name are welcome, but the choice of it was
careful. array_get() has at least one precendent, the Python dict.get
() method, which works basically the same way. The fact that the same
name and function signature (give or take a reference) was also
suggested completely independently in a PHP wishlist item means it's
probably on the right track.
--
Andrew Shearer
http://ashearer.com/
Best regards,
Marcus
Hello Andrew,
how about @<expression>?:<default> style?
Like: $val = $myarray[$key] ?: $default;
marcus
There are drawbacks with using the @ style regularly. One is the lack
of error checking: all error messages generated by finding the array
itself or creating the key are suppressed, which are errors it would
probably be better to see. There are also performance considerations.
Changing the error reporting level internally to suppress errors and
then restoring it has a cost. Testing 100,000 iterations:
array_get() time taken, with default: 0.818 sec
array_get() time taken, no default: 0.565 sec
@ time taken, with default: 2.539 sec
@ time taken, no default: 2.43 sec
(All the above times were similar whether or not the element was found
in the array, and whether the array was small or large.)
Even a pure-PHP implementation of array_get is almost twice as
efficient as using @.
Tuesday, September 11, 2007, 6:33:42 PM, you wrote:
Hello Andrew,
did you check out '?:' shortcut in HEAD?
php -r 'echo 4?:2;' -> 4
php -r 'echo 0?:2;' -> 2best regards
marcusYes, I had hoped that the ?: operator would solve this. But it doesn't
serve the same purpose, because it causes anE_NOTICE
for missing
values. However, ?: and array_get can be used together to provide
short-circuit evaluation, overcoming the limitations of both.Example:
array_get($_GET, 'foo') ?: slowDefaultCalculation()Here is a test of ?: with CVS HEAD + the array_get function:
var_dump($_SERVER['test'] ?: 'nope');
PHP Notice: Undefined index: test in - on line 2
string(4) "nope"var_dump(array_get($_SERVER, 'test', 'nope'));
string(4) "nope"Tuesday, September 11, 2007, 3:20:46 PM, you wrote:
If there's a workable proposal for ifsetor() that fixes the concerns
brought up by the original and is likely to go in PHP 6, that would
be great.In this case, perfect can be the enemy of good. array_get() helps
with many common use cases of ifsetor() while fitting into the the
standard PHP syntax and function model, potentially making its
adoption much easier.See below for answers to what you mentioned.
Hello Andrew,
you can easily implement this function run time. It is not very
flexible
and far away from what ifsetor was meant to be. Thus I do not think
it is a
good idea. See comments below.marcus
Tuesday, September 11, 2007, 12:12:55 AM, you wrote:
Here's a patch against HEAD that implements the array_get function
previously suggested on this list. I also attached a test suite,
which should go in ext/standard/tests/array/array_get.phpt. Feedback
is welcome.Independently, someone else had posted the same idea as a feature
request for PHP 5, and if there's interest I can backport it.40792 Open Wish: Function array_get(&$mixed, $key,
$defaultvalue)/* Prototype:
- mixed array_get ( array $search, mixed $key, mixed $default );
array should not be passed as reference as that would be a slowdown
unless
the function is supposed to create the index key which according to
the
specs below it doesn't.True, as you suggest, it is not passed by reference. (That bug title
was posted independently by someone who might not have thought that
particular aspect through, and it isn't important to the text.)
- Description:
- Returns the value corresponding to the given key if the key exists
- in the array. $key can be any value possible for an array index.
- If the key does not exist, the function returns $default, or
FALSE
- if $default is not specified. Also works on objects.
- Similar semantics to array_key_exists.
*/Here is the original proposal:
array_get, a more palatable alternative to ifsetor
Things this cannot do but ifsetor can.
- Check whether the array exists
True, though there's an argument that this could even be better (less
error-prone) for the typical uses I've seen in my code and elsewhere,
where we're interested in whether the key exists in an array we
already have. An isset-like function doesn't allow you to separate
the two existence checks, allowing spelling errors in the array name
to go undetected when they could easily be caught. In circumstances
where you really do need to check both, you can call isset() or !empty
() on the array first:
$value = isset($array) ? array_get($array, 'mykey') : FALSE;
- Mulitlevel queries
Use nested array_get().
- Other types of queries (e.g. object members)
array_get() supports object members, just likearray_key_exists()
.
- In theory we could have ifsetor even return a writeable reference
where a
non existing key would either be created or (pretty bad imo) a
reference to
the default value gets returned.
Something like that would be nice, but it doesn't exist and I haven't
seen a concrete proposal for it.MOTIVATION
There is an unmet need for an accessor that doesn't generate an
E_NOTICE
when the value is missing, as shown by ongoing discussions
and repeated requests for an ifsetor operator. However, ifsetor had a
special-case syntax and generally didn't fit very well with the rest
of the language.http://devzone.zend.com/node/view/id/1481#Heading2 has a brief
summary. See the Related Functions and Proposals section for more.Reading over those ideas (firstset(), coalesce(), :?, ifset(), and a
workaround usingsettype()
), most of the best uses boil down to
retrieving values from arrays.PROPOSAL
As a simpler alternative to constructs such as this common double
array reference...$value = isset($_POST['command']) ? $_POST
['command'] : '';
I propose an array_get function, like this...
$value = array_get($_POST, 'command', '');
The third argument provides a default. This function would require no
special syntax, and makes a very common construct easier to read and
less error-prone to type. It's a concise way of saying that missing
values can be handled gracefully.Though request processing was used as an example, the function has
wide applicability across many other uses of associative arrays.GREAT, BUT WHY NOT ADD IT TO AN INCLUDE FILE, INSTEAD OF THE CORE?
One of the goals is to make everyday PHP code simpler and clearer.
Writers of sample code snippets should be able to rely on array_get()
being available. Otherwise, they will not use it. Clearer sample code
particularly benefits beginners, who would probably find array_get
easier to understand, but anyone else who has to read or maintain
other people's code would benefit from its wide deployment in core as
well. The function is generally useful enough to be part of the
language, and the implementation in C is also more efficient than a
PHP version.That said, a compatibility function for older versions of PHP is
given below.SEMANTICS
mixed array_get(array $array, mixed $key[, mixed
$default = FALSE]);
If $array contains the key $key, $array[$key] is returned. Otherwise
$default is returned.If $default is not specified, it defaults to FALSE. (NULL would also
be possible, and would more closely match other languages such as
Python with its dict.get method, but other PHP functions tend to
returnFALSE
to indicate no value.)The semantics match
array_key_exists($key, $array) ? $array[$key] :
$default
... but for comparison,
isset($array[$key]) ? $array[$key] : $default
is subtly different. The preferred array_key_exists version has these
differences:
1. If $array[$key] exists but has been set to null, that
null
value will be returned instead of $default. This is likely to be the
least surprising thing to do.
2. If $array itself is unset, an error is generated.
This is good.
The intention is to gracefully handle a missing $key. But if even
$array itself doesn't exist, there may be another problem, such as
misspelling the array variable. isset() ignores all errors, sweeping
more under the rug than we typically want.IMPLEMENTATION
A core C implementation of array_get() benchmarked between two and
three times as fast as the implementation in PHP. I'll attach the
patch after responding to feedback.See the last section for the code of the PHP implementation.
RELATED FUNCTIONS AND PROPOSALS
This function is different than the array_get function proposed and
rejected in http://bugs.php.net/bug.php?id=28185. That function had
no default value and throws a notice when the key doesn't exist,
eliminating the major purpose of this function.The ?: operator doesn't serve the same purpose, because it causes an
E_NOTICE
for missing values. However, ?: and array_get can be used
together to provide short-circuit evaluation, overcoming the
limitations of both. See the LIMITATIONS section for an example.ifsetor: as discussed above, ifsetor wasn't a regular function. It
required special language syntax support because it attempted to test
whether a direct parameter itself was set or unset, and was
ultimately rejected.ifset: a related proposal to ifsetor, with a simpler syntax, ifset
was missing a way to control the default value.See here for more discussion about the 'E_STRICT ternary pain-in-the-
ass expression' and alternatives:
http://keithdevens.com/weblog/archive/2005/Nov/24
http://www.php.net/~derick/meeting-notes.html#id39
http://devzone.zend.com/node/view/id/1481#Heading2LIMITATIONS
This proposal doesn't address every requested feature. The third
parameter is always evaluated, so calling a slow function there would
be undesirable. However, the limitation appears to be unavoidable
without special language support, and there are workarounds. These
snippets have approximately equal meanings (though they may differ is
the handling of array values that convert to false):array_get($_GET, 'foo', slowDefaultCalculation())
$val = array_get($_GET, 'foo'); if (!$val) $val =
slowDefaultCalculation();
array_get($_GET, 'foo') ?: slowDefaultCalculation()
The last example uses the new PHP 6 ?: operator.
This function applies only to array elements. Unlike other proposed
functions, it doesn't also attempt to determine whether variables are
set. However, the practical uses suggested for the other functions
generally ended up applying to array elements.COMPATIBILITY FUNCTION FOR OLDER VERSIONS OF PHP
if (!function_exists('array_get')) {
function array_get($arr, $key, $default = false) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
}
else {
return $default;
}
}
}(This version turned in the fastest times out of several variants.
Passing $arr by reference or attempting to return the result by
reference had a huge negative impact, and using the ternary ? :
operator instead of the if/else was slightly slower.)=======
Andrew Shearer
http://ashearer.com/
Best regards,
MarcusAndrew Shearer
http://ashearer.com/Best regards,
MarcusBest regards,
Marcus