The following behavior seems odd to me.
A value of an array should be checked for existence when using the default filter (the second dump).
{% set var = { 'foo': 0, 'bar': false } %}
{# expected 0, got 0 #}
{{ dump(var.foo|default(true)) }}
{# expected false, got true #}
{{ dump(var.bar|default(true)) }}
{# expected true, got true #}
{{ dump(var.baz|default(true)) }}
this is not specific to arrays:
{% set foo = false %}
{{ dump(foo|default(true)) }}
{# got true #}
And this is what is documented: the doc says the default will be applied for undefined or empty values. And false is considered as an empty value.
Hm.. well, then one has to use the defined test to get around the default check using false (currently applied workaround).
I can't see why Twig is diverting there from php internals; e.g. (int) 0 is considered empty as well within php, but passes the default filter. Any special reasons for this?
I also find this irritating. I thought default would be activated when the variable is not defined. Otherwise it's not really useful.
I agree. Interpreting boolean false values as empty values seems counter-intuitive to me, especially if they were explicitly set.
+1 to this! Just ran into it and I can confirm that it is, in fact, annoying :D
+1
:+1:
+1 I faced the same problem ended up with ugly if condition massacre
+1. I am reading boolean vars from yaml, and some of the vars I want to default to true if they are not defined. This is not currently possible, as TWIG treats var=false identically with the var being undefined or with empty value ...
I +1'd this almost a year ago and still nothing?
There is something, there is #1470, however that one is being discussed because of BC related remarks.
I suppose I should mention the existence of the "same as" test which replicates === in PHP
I've never included a gist in a GH comment before, so hopefully this works... here's a Gist I made for a simple twig filter to fix this behaviour. I only spent about 10 mins on it, so please suggest improvements. This might be a na茂ve approach at it. YMMV.
@chrispappas this filter won't work. When using strict variables, you will get an exception if the key does not exist instead of using the default value, defeating the purpose of the default.
and regarding the sameas test, it has nothing to do with this issue
You can use this workaround for this problem.
{# main.twig #}
{% set var = var ?? false %}
{% if var %}
<span>I'm special!</span>
{% endif %}
{# child1.twig #}
{% extends "main.twig" %}
{% set var = true %}
{# child2.twig #}
{% extends "main.twig" %}
Here's an example: http://twigfiddle.com/ziwbxt
Select "Set as main template" for child2.twig as well and see the difference in the output on the right.
The catch is that the variable you're testing must be defined with {% set %} in the main template.
EDIT:
You don't really have to predefine variables in the main template, you can just use the null-coalescing operator inline.
{# main.twig #}
{% if (var ?? false) %}
<span>I'm special!</span>
{% endif %}
One more vote for not triggering the 'default' filter on FALSE but only on NULL or UNDEF
may be we could add an option to the default filter
I already hit this behavior, and indeed this is not very convenient
@gggeek but then, that would be exactly the ?? operator (but slower as it could not always be identified as such at compile time and be replaced by the ?? operator which compiles to faster code when it can use the PHP ?? operator)
@stof "I'm never quite so stupid as when i'm being smart". Point taken.
Maybe it would be worth mentioning the '??' operator in the doc. page for 'default' ?
@gggeek , @stof: 馃憤 for adding it to the twig default page. As I stumbled upon this today as well and had to find this issue to find my answers.
this is _so_ counterintuitive and dumb
- $0.02
I suggest to close here. The suggested change would be a BC break, there already is the ?? operator and noone seemed to be interested in updating the docs for the defined test.
Most helpful comment
You can use this workaround for this problem.
Here's an example: http://twigfiddle.com/ziwbxt
Select "Set as main template" for child2.twig as well and see the difference in the output on the right.
The catch is that the variable you're testing must be defined with
{% set %}in the main template.EDIT:
You don't really have to predefine variables in the main template, you can just use the null-coalescing operator inline.