On Wed, Jul 18, 2012 at 12:21 PM, Galen Wright-Watson <[email protected]>wrote:
>
>
> On Wed, Jul 18, 2012 at 7:20 AM, Anthony Ferrara <[email protected]>wrote:
>
>>
>> On Wed, Jul 18, 2012 at 10:15 AM, Rafael Dohms <[email protected]
>> >wrote:
>>
>> > [...]
>>
>> >
>> > This is basically because the ternary operator does not do a internal
>> > implicit isset, only an empty.
>> >
>>
>> It does not do an empty. Empty would avoid notices as well. All it does is
>> an implicit bool cast...
>>
>>
>> > Does this seem like a possible improvement we can work on? Anyone
>> > interested in championing the change?
>> >
>>
>> I like it in principle. My only concern is *why* wasn't it done this way
>> in
>> the first place... Is there a reason?
>>
>
> It changes the semantics. If the variable is set to a falsey value and ?:
> uses an implicit isset, the value of the expression will be the falsey
> value.
>
> $config['width'] = ''
> $width = $config['width'] ?: 300
> # $width == ''
>
> If !empty were used instead of isset, you could preserve semantics ($a ?:
> dflt = !empty($a) ? $a : dflt).
>
However, this would break if someone were to use an explicit isset, so ?:
could only use an implicit !empty if the expression isn't an isset
expression (which starts to get messy, grammar-wise).
Looking over the previous discussion, people objected to altering the
behavior of ?: precisely because it currently generates notices, which they
desire.
The following use-cases were put forward as commonly occurring and verbose
enough to desire syntactic sugar:
1. isset($arr['key']) ? $arr['key'] : dflt
2. ! empty($arr['key']) ? $arr['key'] : dflt
3. ! is_null($arr['key']) ? $arr['key'] : dflt (used instead of isset
version; both wouldn't appear in same code base)
4. $arr['key'] = isset($arr['key']) ? $arr['key'] : dflt
5. isset($arr['key']) ? strtoupper($arr['key']) : dflt
The following new operators were suggested:
1. new ternary based on isset (e.g. "$a ?? strtoupper($a) : 'DFLT'" with
implicit isset)
2. new shortcut ternary based on isset
3. new shortcut ternary based on !empty (objection: not as useful as
isset, since !empty is equivalent to !! but with notice suppression)
4. new shortcut ternary based on !== null or ! is_null
5. new shortcut ternary that only works on arrays and is based
on array_key_exists
6. indexing operator that suppress undefined index notices
7. variable access that suppresses undefined variable notices
8. assign-if-not-set operator (like ||= in Javascript)
Some objections to the above:
1. (new ternary) ?
2. (isset) Some developers always set variables and never want undefined
notice suppression (the "never-unset" style), which isset will do. However,
this isn't as common a style.
3. (!empty) Not as useful as isset, since !empty is equivalent to !! but
with notice suppression. Also, !empty($a)?$a:dflt isn't used as much as
isset($a)?$a:dflt.
4. (!== null / ! is_null) Not as useful as isset, since it doesn't
suppress notices, so isn't a replacement for the isset($a)?$a:dflt pattern.
However, it can be used in combination with 6 for the isset-based ternary
for arrays (e.g. "$arr?['key'] ?: 'dflt'").
5. (array_key_exists) Conceptually, anything unset has a null value, and
should thus be equivalent in value to something set to NULL.
array_key_exists distinguishes between unset and set to NULL, which
won't always match how some want to use the shortcut ternary. Thus, not as
useful as is_null.
6. (indexing w/o notices) ?
7. (variable access) Probably do more harm than good. It's easy to
ensure a variable is set.
8. (assign-if-not-set) For arrays, there's the alternative:
$arr += Array('key' => 'value');
This can also be used for a "never-unset" style to set defaults for an
array, which goes with the "! is_null($a) ? $a : dflt" pattern.
Various syntax proposals:
1. "$a ?? $b : dflt" as a ternary, with shortcutting behavior.
2. "$a ?? dflt" as a shortcut ternary
3. "$a ?! dflt" as a shortcut ternary based on !empty (could be added
along with "??"; objection is that it could ambiguate PHP's syntax,
conflicting with the not operator)
4. "$a $: dflt" as a shortcut ternary
5. "$arr?['key']" to suppress undefined index notices
6. "$arr@['key']" to suppress undefined index notices
7. "$?var" to suppress undefined variable notices
8. "$a ??= dflt" as an assign-if-not-set operator (goes along with "??")
9. "$a !?= dflt" as an assign-if-not-set operator ("!" suggests not-set)
10. "$a $:= dflt" as an assign-if-not-set operator (goes along with "$:")
?? / isset vs ?? / is_null
Of the various proposals, "??" (with semantics of "isset($a) ? $a : dflt")
already has a precedence: in C# as the null-coalescing operator. While PHP
doesn't have non-nullable types (hence "??" isn't a necessity), using ?? is
perhaps the least surprising option, and (including "??=") would cover
use-cases 1 and 4. On the other hand, PHP's "??" wouldn't be the same as
C#, since C# requires that variables be declared. Arguably, having "??"
equivalent to "!is_null($a) ? $a : dflt" is closer to C# semantics. Also,
use-cases 2 and 3 would be left out, whereas operator proposals 4 (?? /
is_null), 6 (?[]) and 8 (??= / is_null) together cover use-cases 1, 3 and
4. Back on the first hand, use-cases 2 and 3 are less common and this is
(after all) merely syntactic sugar, which should be targeting the common
cases.
??: vs ??
The ternary "??:" (whether based on isset or is_null) can also cover
use-case 5, but isn't so good for case 4 ("??:=" would be ugly). One one
hand, the short-cut "??:" may be surprising to developers familiar with
C#'s "??:". On the other, PHP ain't C#, and documentation can cover
"??:".
Besides, "??" isn't the only null-coalescing operator out there, so why
should C# be given special consideration? Less rhetorically, would
supporting both "??" and "??:", with "$a ??: dflt" equivalent to
"$a ?? dflt",
be undesirable?
Personally, I support syntaxes 8. ??= with either 1. ??: / isset or
(1. ??:/ is_null and 5.
?[]).