On 9/11/07, Marcus Boerger <[EMAIL PROTECTED]> wrote: > 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: > > > On 9/11/07, Marcus Boerger <[EMAIL PROTECTED]> wrote: > >> Hello Andrew, > >> > >> did you check out '?:' shortcut in HEAD? > >> > >> php -r 'echo 4?:2;' -> 4 > >> php -r 'echo 0?:2;' -> 2 > >> > >> best 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. > >> > >> > On Sep 11, 2007, at 5:27 AM, Marcus Boerger wrote: > >> > >> >> 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 like array_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 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/ > >> >> Best regards, > >> >> Marcus > >> > >> > Andrew Shearer > >> > http://ashearer.com/ > >> > >> > >> > >> > >> Best regards, > >> Marcus > >> > >> > > > > > Best regards, > Marcus > > -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php