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 > > -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php