smarty
smarty copied to clipboard
v4 -> v5: Undefined Variables are Treated Differently
I tried upgrading a site to version 5, but ran into some issues that I could not resolve. Specifically, the way Smarty handles variables has changed.
Example:
<?php
// use Smarty\Smarty; // uncomment for v5
require_once 'vendor/autoload.php';
error_reporting(E_ALL);
ini_set('display_errors', '1');
$smarty = new Smarty();
$smarty->display('string:{$TestVarUndefined} is undefined');
Output:
Smarty v4.5.4
Warning: Undefined array key "TestVarUndefined" in [file]_0.string.php on line 18
Warning: Attempt to read property "value" on null in [file]_0.string.php on line 18
is undefined
With a stack trace potentially and more similar warnings.
Smarty v5.4.1
is undefined
There is no indication that the variable was never assigned.
Why's this a problem?
I would like to know when I make a typo, or forget to assign a variable, but with v5 it'll just become the empty string.
Just use error_unassigned
?
Yes, setting error_unassigned
when using v5 will trigger the error, but the problem with this fix is that it will ALSO trigger an error if an undefined variable is used in combination with empty or isset. Like: {if empty($undefinedVar)} Sweet! {else} Oh no! {/if}
PHP's empty
and isset
work in a special way, suppressing warnings about undefined stuff, and simply returning a boolean.
So, I don't see an easy way to fix this without adding significant complexity to the compiler, so that it treats empty and isset in a special/different way when attempting to access variables/values.
The difference between v4 and v5 is significant in how they work, as v4 compiles to direct array access, whereas v5 uses $_smarty_tpl->getVariable().
The relevant compiled code of the above example is:
// v4
echo $_smarty_tpl->tpl_vars['TestVarUndefined']->value;?>
is undefined<?php
// v5
echo $_smarty_tpl->getValue('TestVarUndefined');?>
is undefined<?php
Am I doing something wrong?
Following an anti-pattern?
Is it unreasonable to expect {if empty($neverAssignedVar)}
to work, while also expecting an error if {$neverAssigned}
is used?
I apologize If I missed something in the docs!