Good evening,
I’ve written an RFC and working patch which attempt to add this feature which has been often requested: https://wiki.php.net/rfc/isset_ternary
Thanks!
Andrea Faulds
http://ajf.me/
Hi Andrea,
Good evening,
I’ve written an RFC and working patch which attempt to add this feature
which has been often requested: https://wiki.php.net/rfc/isset_ternary
I did not look at the patch yet but I like it from a feature point of view.
We should have had this since long :)
Cheers,
Pierre
I've played around with this branch for a bit and seems reasonable, passes
the tests, and doesn't seem to have any serious issues/memories leaks
AFAICT.
I can't stress enough, however, how important it is for us to avoid
inconsistencies in behavior between various forms of syntax. This is often
something users complain of as often they complain about not getting such
features. So let's make ternary consistent before we implement yet another
oddity in PHP (half-assed and ill designed).
I don't actually agree with the premise that ternary should wrap the first
operand in empty() to begin with, but if this is what people want, fine.
Let's just do it right.
And as Rasmus mentioned in the PR, make the documentation very cleary if
it gets accepted.
Hi Andrea,
Good evening,
I’ve written an RFC and working patch which attempt to add this feature
which has been often requested: https://wiki.php.net/rfc/isset_ternaryI did not look at the patch yet but I like it from a feature point of view.
We should have had this since long :)Cheers,
Pierre
I've played around with this branch for a bit and seems reasonable, passes
the tests, and doesn't seem to have any serious issues/memories leaks
AFAICT.
There’s actually a quite serious issue just now, which is that it evaluates the first operand twice if it’s not empty. This is because $a ?: $b is expanded to empty($a) ? $b : $a, such that if you did something which mutates state in there, it’d happen twice. This is obviously not good, and I’m going to figure out how to fix this.
I can't stress enough, however, how important it is for us to avoid
inconsistencies in behavior between various forms of syntax. This is often
something users complain of as often they complain about not getting such
features. So let's make ternary consistent before we implement yet another
oddity in PHP (half-assed and ill designed).I don't actually agree with the premise that ternary should wrap the first
operand in empty() to begin with, but if this is what people want, fine.
Let's just do it right.And as Rasmus mentioned in the PR, make the documentation very cleary if
it gets accepted.
Yeah, I’ll be sure to make it crystal clear that they aren’t quite the same.
FWIW, it’s not our only shorthand which differs in behaviour. For example, ++ and += 1 are NOT the same, though I’d love to fix that particular inconsistency.
--
Andrea Faulds
http://ajf.me/
Hi, Andrea
I feel more like Sherif Ramadan. Even so I've quite often been in the same
situation, I don't think it's a good solution to change something like
that, just for the shorthand-operator.
I think, the notice is really valuable when accessing the value and doing
something with it - like myFunction($_GET['not_set']), but if you're just
checking for the existence, I, too, think it is more annoying. My way was
to suppress it by adding the silence-operator ;)
I always used like:
@$_GET['mykey'] ?: ””
I can't come up with a good mid-way right now, but I don't think it's a
good way to change this ONLY for the short-hand operator.
Bye,
Simon
Good evening,
I’ve written an RFC and working patch which attempt to add this feature
which has been often requested: https://wiki.php.net/rfc/isset_ternaryThanks!
Andrea Faulds
http://ajf.me/
Hi Andrea,
This is great -- thanks to you and Nikita for the work here.
Syntax wise, I would prefer a function-like syntax, e.g. coalesce($a, $b,
'c') or ifsetor() instead of $a ?? $b ?? 'c'. I find this more readable,
and it avoids any possible confusion about precedence within the
expressions. Either way, still +1 for this feature.
Best regards,
--Matthew
Matthew Fonda wrote (on 17/09/2014):
Hi Andrea,
This is great -- thanks to you and Nikita for the work here.
Syntax wise, I would prefer a function-like syntax, e.g. coalesce($a, $b,
'c') or ifsetor() instead of $a ?? $b ?? 'c'. I find this more readable,
and it avoids any possible confusion about precedence within the
expressions. Either way, still +1 for this feature.
Funnily enough, the standard library at my workplace has long included a
coalesce() function as below, which is indeed very handy; there is also
a coalesce_empty(), which calls empty($arg) instead of is_null($arg).
Both pre-date the shorthand ?: operator, which could replace
coalesce_empty(); the proposed ?? could replace coalesce()
As mentioned in the PHPDoc, the downside of a function is that it can't
short-cut evaluation if the first argument passes, whereas an operator
can. It would be possible to work around this by defining a special
"language construct" rather than a real function, but that's probably
more confusing than it's worth.
The special case for $first is a performance optimisation because
func_get_args()
has rather a lot of overhead; I'm guessing 5.6's
variadic signatures ($args...) are less painful (can anyone confirm?)
/**
-
coalesce
-
PHP analogue of the SQL Coalesce() function
-
@param an arbitrary number of arguments
-
@return the first argument which is not NULL; If all arguments are
NULL, will returnNULL
-
coalesce( $a, $b ) is equivalent to ($a ===
NULL
? $a : $b) -
but coalesce( hard_work(), 'default' ) only has to do hard_work() once
-
[OTOH, coalesce( $a, hard_work() ) has to do hard_work() even if the
result gets thrown away]
*/
function coalesce($first)
{
if (!is_null($first))
{
return $first;
}foreach (
func_get_args()
as $arg )
{
if ( ! is_null($arg) )
{
return $arg;
}
}
}
--
Rowan Collins
[IMSoP]
Hi Andrea,
This is great -- thanks to you and Nikita for the work here.
Syntax wise, I would prefer a function-like syntax, e.g. coalesce($a, $b,
'c') or ifsetor() instead of $a ?? $b ?? 'c'. I find this more readable,
and it avoids any possible confusion about precedence within the
expressions. Either way, still +1 for this feature.Best regards,
--Matthew
I’m STRONGLY +1 in favor of this operator, ASAP; I’ve had to write more than a few hacks to keep a large codebase I’m responsible from being a complete mess of isset() checks - 5.6 has saved me a lot of what used to be ugly workarounds (variadic functions anyone?), but this one still haunts me.
I would argue for both coalesce() (as a language token) and ?? and ??=, as shorthand forms, giving the user a choice as to which they find more readable. ?? is standard in both .NET and Apple’s Swift language - Apple added it to Swift (including the chaining behavior) early during the beta cycle due to user demand for exactly this kind of logic, and it’s been part of C# for a long time.
-- Gwynne Raskind
I'm seeing '??' as analogous to the way JS developers use '||', and I use
that all the time when writing JS.
Personally I wouldn't be interested in a function version because the
short-circuiting of '??' is an important distinction; not something you can
replicate with a function. Therefore having both would be confusing IMO.
Also, not much sure about a '??=', perhaps it should be a followup RFC
should '??' be accepted.
Hi Andrea,
This is great -- thanks to you and Nikita for the work here.
Syntax wise, I would prefer a function-like syntax, e.g. coalesce($a, $b,
'c') or ifsetor() instead of $a ?? $b ?? 'c'. I find this more readable,
and it avoids any possible confusion about precedence within the
expressions. Either way, still +1 for this feature.Best regards,
--MatthewI’m STRONGLY +1 in favor of this operator, ASAP; I’ve had to write more
than a few hacks to keep a large codebase I’m responsible from being a
complete mess of isset() checks - 5.6 has saved me a lot of what used to be
ugly workarounds (variadic functions anyone?), but this one still haunts me.I would argue for both coalesce() (as a language token) and ?? and ??=, as
shorthand forms, giving the user a choice as to which they find more
readable. ?? is standard in both .NET and Apple’s Swift language - Apple
added it to Swift (including the chaining behavior) early during the beta
cycle due to user demand for exactly this kind of logic, and it’s been part
of C# for a long time.-- Gwynne Raskind
--
--
Pete Boere
Web Developer
I'm seeing '??' as analogous to the way JS developers use '||', and I use
that all the time when writing JS.
PHP already has a direct equivalent to ||, namely the ?: operator. However, unfortunately PHP always spits out a notice on non-existent indices, unlike JS which just results in undefined, so we need to add a special operator to silence it.
Personally I wouldn't be interested in a function version because the
short-circuiting of '??' is an important distinction; not something you can
replicate with a function. Therefore having both would be confusing IMO.
We could use a function syntax, though, but I don’t like this idea. coalesce() and ifsetor() are both ugly to me, and it’s not super obvious what they do:
var_dump(coalesce($_GET[‘foobar’], 3));
vs.
var_dump($_GET[‘foobar’] ?? 3);
?? also has the advantage of being shorter.
Also, not much sure about a '??=', perhaps it should be a followup RFC
should '??' be accepted.
It’d make sense to do it within this RFC if possible. If it seems too controversial, it could always have a separate vote within the RFC.
Andrea Faulds
http://ajf.me/
We could use a function syntax, though, but I don’t like this idea.
coalesce() and ifsetor() are both ugly to me, and it’s not super
obvious what they do:var_dump(coalesce($_GET[‘foobar’], 3));
vs.
var_dump($_GET[‘foobar’] ?? 3);
?? also has the advantage of being shorter.
If you don't now what ?? does it's far from obvious. coalesce is a term
that can be put into google and will deliver results.
johannes
We could use a function syntax, though, but I don’t like this idea.
coalesce() and ifsetor() are both ugly to me, and it’s not super
obvious what they do:var_dump(coalesce($_GET[‘foobar’], 3));
vs.
var_dump($_GET[‘foobar’] ?? 3);
?? also has the advantage of being shorter.
If you don't now what ?? does it's far from obvious. coalesce is a term
that can be put into google and will deliver results.
On the flip side, coalesce() etc would introduce another keyword,
which would be a BC break, unless we also manage to get
keywords-as-identifiers working and accepted for the same release.
I wouldn't mind betting there are quite a few applications out there
with a function/method called coalesce() defined... I know there's at
least one, because I work on it regularly, and github has over 100,000
hits for it (the vast majority of these are in SQL strings but I still
found 4 PHP functions/methods on the first 3 pages):
https://github.com/search?q=coalesce+language%3Aphp&type=Code
On Sep 18, 2014 9:36 AM, "Johannes Schlüter" johannes@schlueters.de
wrote:We could use a function syntax, though, but I don’t like this idea.
coalesce() and ifsetor() are both ugly to me, and it’s not super
obvious what they do:var_dump(coalesce($_GET[‘foobar’], 3));
vs.
var_dump($_GET[‘foobar’] ?? 3);
?? also has the advantage of being shorter.
If you don't now what ?? does it's far from obvious. coalesce is a term
that can be put into google and will deliver results.johannes
It would (I assume) be described as such on the Comparison Operators manual
page, leading one to Google "coalesce". If I don't know what an unfamiliar
operator does in a language, its operators documentation page is a logical
first stop.
Pete Boere wrote (on 18/09/2014):
I'm seeing '??' as analogous to the way JS developers use '||', and I use
that all the time when writing JS.
Actually, JS's || is more analogous to the existing ?: operator, because
it checks for truthiness, not definedness (!empty() rather than isset(),
in PHP terms).
PHP:
echo false ?: "" ?: 0 ?: "default";
JS:
console.log( false || "" || 0 || "default" );
The behaviour around undefined variables is a bit different, but that's
a property of JS as a language, not any suppression by the || operator
(console.log(x) with undefined x is an error; console.log(x.y) with x as
an empty object is not).
--
Rowan Collins
[IMSoP]