0

I am writing a CMS templating "engine". The idea is quite simple - I would preload snippets of HTML in HEREDOC strings, and than call them as and if the flow control asks for them.

The issue is that heredoc strings behave strange. Here is the example:

$ERROR_MESSAGE = "default";
$tst = <<<EOF
<div id="error-message">$ERROR_MESSAGE</div>
EOF;

function splice_message_output()
    {
    global $ERROR_MESSAGE;
    global $tst;

    if (isset($ERROR_MESSAGE))
        {
        echo <<<EOF
<div id="error-message">$ERROR_MESSAGE</div>
EOF;
        echo $tst;
        }
    }

Below I have a condition that sets ERROR_MESSAGE and calls the function:

if (isset($_GET["MSGTYPE"]))
    {
    if ($_GET["MSGTYPE"] == "ERR")
        {
        $ERROR_MESSAGE = $_GET["MSG"];

        }
    }

   function splice_message_output()

And the output is:

<div id="error-message">This is the errormessage text</div>
<div id="error-message">default</div>

How is this possible? I have clearly defined string that was called BELOW in code, and the HEREDOC snippet returns the string that was set just above, and the other function the string that was set below.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
mrmut
  • 484
  • 5
  • 18

3 Answers3

0

You only ever define $tst once with the message 'default' in it. Your code below the function sets $ERROR_MESSAGE = $_GET["MSG"]; only if $_GET["MSGTYPE"] is set and equals 'ERR'. So it sets the variable, prints the embedded HEREDOC string and then prints $tst which hasn't changed. There is nothing strange about HEREDOCs here!

I think where you're getting confused is that you think the HEREDOC string will always contain a reference to $ERROR_MESSAGE. This is not so. A variable such as $ERROR_MESSAGE is replaced by its contents whenever it is used in a string, exactly the same as if you used $tst = "The message is: $ERROR_MESSAGE";. Afterwards the value of $tst will be 'The message is: default'.

CJ Dennis
  • 4,226
  • 2
  • 40
  • 69
0

As mentioned, you have already declared the value of $tst before changing the value of $ERROR_MESSAGE. Your understanding of heredoc is the problem here. When you're inserting a variable into a heredoc (or even any type of string for that matter), it doesn't literally mean that you're inserting that variable itself (or a reference to the variable). Rather, you are inserting the value of that variable into the heredoc. So for example, if you have the following variables;

$var1 = "inserted var";
$var2 =
<<<VAR2
My $var1 goes here.
VAR2;

... changing the value of $var1 would not automatically change the value of var2.

$var1 = "inserted var";
$var2 =
<<<VAR2
My $var1 goes here.
VAR2;

$var1 = "var changed";

echo
<<<MYECHO
var1: $var1
<br>
var2: $var2
MYECHO;

OUTPUT:

var1: var changed
var2: My inserted var goes here.

Heredoc functions like every other string. The difference is that in heredoc, you avoid the need to escape " and interchange between ' and " or any further escape hell. Overall, heredoc is just for making your code much easier to read and maintain.

<?Php
echo "<button onclick='alert(\"double-quote\")'>double-quote</button>";
echo '<button onclick="alert('."'single-quote'".')">single-quote</button>';
echo
<<<HEREDOCSAMPLE
<button onclick='alert("heredoc")'>heredoc</button>
HEREDOCSAMPLE;
?>

Another useful one is the nowdoc, but only if you're not planning to insert any php variable in your string.

$this = "example";
echo
<<<'NOWDOCSAMPLE'
$this variable would not be treated as a $variable.
NOWDOCSAMPLE;

OUTPUT:

$this variable would not be treated as a $variable.

Now in your code sample:

$ERROR_MESSAGE = "default";
$tst =
<<<EOF
<div id="error-message">$ERROR_MESSAGE</div>
EOF;
//THIS WOULD MAKE THE CURRENT VALUE OF $tst as:
//<div id="error-message">default</div>

function splice_message_output()
{   global $ERROR_MESSAGE;
    global $tst;

    if (isset($ERROR_MESSAGE))
    // I DON'T THINK THIS VALIDATION MAKES SENSE SINCE $ERROR_MESSAGE
    // WOULD ALWAYS BE DECLARED
    {   echo <<<EOF
<div id="error-message">$ERROR_MESSAGE</div>
EOF;
        echo $tst;
    }
}

if (isset($_GET["MSGTYPE"]))
{   if ($_GET["MSGTYPE"] == "ERR")
    {   $ERROR_MESSAGE = $_GET["MSG"];
        // THE ONLY VARIABLE THAT CHANGED HERE IS $ERROR MESSAGE
        // $tst DID NOT CHANGE AT ALL
    }
}

function splice_message_output()
// RE-DECLARED FUNCTION? OR PERHAPS:
splice_message_output();
// AT THIS POINT ONLY $ERROR_MESSAGE HAS CHANGED ITS VALUE.

Now if I were to propose a revision of that code, this'll be it:

$ERROR_MESSAGE = "default";
function splice_message_output()
{   global $ERROR_MESSAGE;
    global $tst;

    if (isset($_GET["MSG"]))
    {   echo <<<EOF
<div id="error-message">$ERROR_MESSAGE</div>
EOF;
        $tst = <<<EOF
<div id="error-message">$ERROR_MESSAGE</div>
EOF;
        // NOW HERE'S A TRICKY ONE. SINCE YOU DECLARED $tst AS A
        // GLOBAL VARIABLE WITHIN THIS FUNCTION, DOING AN if(isset($tst))
        // OUTSIDE THIS FUNCTION AFTER CALLING THIS FUNCTION WOULD
        // BE EQUAL TO 'TRUE'
        echo $tst;
    }
}

if (isset($_GET["MSGTYPE"]))
{   if ($_GET["MSGTYPE"] == "ERR")
    {   $ERROR_MESSAGE = $_GET["MSG"];
        // THE ONLY VARIABLE THAT CHANGED HERE IS $ERROR MESSAGE
        // $tst DID NOT CHANGE AT ALL
    }
}

// THE VARIABLE $tst DOESN'T EXIST AT THIS POINT BUT
splice_message_output(); // ONCE THIS FUNCTION IS CALLED
// $tst WOULD HAVE ALREADY EXISTED
RJBaytos
  • 71
  • 1
  • 8
0

The value of $tst is being evaluated before you can change the vale of $ERROR_MEGGAGE. So, you simply need to check your condition and make any changes to the value of $ERROR_MESSAGE before you use it in the HEREDOC statement for $tst.

Akhil Gupta
  • 101
  • 1
  • 8