Emulate short tags in PHP when short_open_tag = off

Yesterday I was playing with PHP 5.3. It seems that the default configuration comes with short_open_tag disabled 🙁

The short open tags is what allows to write code like this <?=”algo”?> instead of having to write <?php echo “algo”?>. Something REALLY INTERESTING, it makes PHP code really clear when looking at templates from my point of view.

I think PHP people has not made the right choice here. From what I understood, they disabled this because of the ambiguity when parsing XML documents, which starts by <?xml. I’ll better stop talking.

Anyway, everything is because I have a class called jview which loads the PHP view templates in my system, and lots of the templates (if not all) use this tags, so I wanted to keep writing the code like that without changing the short tags in the template files. You can think on WordPress templates to get an idea of how my templates look like.

Just to make an example of the whole problem, have a look at the following PHP code:

<?php echo "hello"?> <?= "world"?>

When short_open_tags is enabled, the PHP output is:

hello world

But when short_open_tags is disabled, then PHP produces this ugly output:

hello <?= "world"?>

BTW, I had two alternatives for solving this problem:

  • Copy the template file into a temporal file, replace all ‘<?=’ by ‘<?php ‘, include the temporal file as a PHP file, and finally remove the file
  • Make a PHP interpreter in PHP where I replace ‘<?=’ by ‘<?php ‘

If you know me, you know I’ve chosen the second option ;D

It only took me 20 minutes!! Less than I expected!

Here is the code:

  function include_emulating_short_tags ($viewFile)
  {
    // Alternate method for making <?= valid
    $raw = file_get_contents ($viewFile);
    $raw = str_replace ('<?=', '<?php echo ', $raw); 
 
    $html = '';
    $phptokens = @token_get_all ($raw);
 
    $mode    = 'text';
    $phpcode = '';
    foreach ($phptokens as $ptoken)
    {
      if (($mode == 'text') && is_array ($ptoken) && ($ptoken[0] === T_OPEN_TAG)) {
        $mode = 'php';
        continue;
      }
 
      if (($mode == 'php') && is_array ($ptoken) && ($ptoken[0] === T_CLOSE_TAG)) {
        ob_start();
        eval ($phpcode . ';');
        $html .= ob_get_contents();
        ob_end_clean();
 
        $mode    = 'text';
        $phpcode = '';
        continue;
      }
 
      if ($mode == 'text') { 
        $html .= is_array ($ptoken) ? $ptoken[1] : $ptoken;
      }
      else {
        $phpcode .= is_array ($ptoken) ? $ptoken[1] : $ptoken;
      }
    }
 
    if (($mode == 'php') && ($phpcode !== '')) {
      ob_start();
      eval ($phpcode);
      $html .= ob_get_contents();
      ob_end_clean();
    }
 
    return $html;
  }

At the end, the variable $html returned, contains the HTML code that will otherwise be flushed to standard output. This way, you can do with the output whatever you want.

Finally, if we use include_emulating_short_tags when short_open_tags=0 with the original example, the output will be “hello world”, what I wanted :D. I can see a couple of inconveniences (that could be work-arounded by writing something more elaborate), but for practical uses, it works perfectly well.

Trackback URL

, , ,

Comments are closed.