views:

5801

answers:

7

In PHP, the HEREDOC string declarations are really useful for outputting a block of html. You can have it parse in variables just by prefixing them with $, but for more complicated syntax (like $var[2][3]), you have to put your expression inside {} braces.

In PHP 5, it is possible to actually make function calls within {} braces inside a HEREDOC string, but you have to go through a bit of work. The function name itself has to be stored in a variable, and you have to call it like it is a dynamically-named function. For example:

$fn = 'testfunction';
function testfunction() { return 'ok'; }
$string = <<< heredoc
plain text and now a function: {$fn()}
heredoc;

As you can see, this is a bit more messy than just:

$string = <<< heredoc
plain text and now a function: {testfunction()}
heredoc;

There are other ways besides the first code example, such as breaking out of the HEREDOC to call the function, or reversing the issue and doing something like:

?>
<!-- directly output html and only breaking into php for the function -->
plain text and now a function: <?PHP print testfunction(); ?>

The latter has the disadvantage that the output is directly put into the output stream (unless I'm using output buffering), which might not be what I want.

So, the essence of my question is: is there a more elegant way to approach this?

Edit based on responses: It certainly does seem like some kind of template engine would make my life much easier, but it would require me basically invert my usual PHP style. Not that that's a bad thing, but it explains my inertia.. I'm up for figuring out ways to make life easier though, so I'm looking into templates now.

+2  A: 

I would do the following:

$string = <<< heredoc
plain text and now a function: %s
heredoc;
$string = sprintf($string, testfunction());

Not sure if you'd consider this to be more elegant ...

boxxar
+2  A: 

You are pretty much describing what happens in a templating engine. You obviously know php pretty well. Have you considered taking a look at an actual templating engine?

Internet Friend
+9  A: 

I would not use HEREDOC at all for this, personally. It just doesn't make for a good "template building" system. All your HTML is locked down in a string which has several disadvantages

  • No option for WSYIWYG
  • No code completion for HTML from IDEs
  • Output (HTML) locked to logic files
  • You end up having to use hacks like what you're trying to do now to achieve more complex templating, such as looping

Get a basic template engine, or just use PHP with includes - it's why we have the delimiters.

template_file.php

<html>
<head>
  <title><?php echo $page_title; ?></title>
</head>
<body>
  <?php echo getPageContent(); ?>
</body>

index.php

<?php
$page_title = "This is a simple demo";
function getPageContent()
{
    return '<p>Hello World!</p>';
}

include( 'template_file.php' );
Peter Bailey
+1  A: 

I'd take a look at Smarty as a template engine - I haven't tried any other ones myself, but it has done me well.

If you wanted to stick with your current approach sans templates, what's so bad about output buffering? It'll give you much more flexibility than having to declare variables which are the the sting names of the functions you want to call.

nickf
+1  A: 

I'm a bit late, but I randomly came across it. For any future readers, here's what I would probably do:

I would just use an output buffer. So basically, you start the buffering using ob_start(), then include your "template file" with any functions, variables, etc. inside of it, get the contents of the buffer and write them to a string, and then close the buffer. Then you've used any variables you need, you can run any function, and you still have the HTML syntaxt highlighting available in your IDE.

Here's what I mean:

Template File:

<?php echo "plain text and now a function: " . testfunction(); ?>

Script:

<?php
ob_start();
include "template_file.php";
$output_string = ob_get_contents();
ob_end_clean();
echo $output_string;
?>

So the script includes the template_file.php into its buffer, running any functions/methods and assigning any variables along the way. Then you simply record the buffer's contents into a variable and do what you want with it.

That way if you don't want to echo it onto the page right at that second, you don't have to. You can loop and keep adding to the string before outputting it.

I think that's the best way to go if you don't want to use a templating engine.

BraedenP
+1  A: 

Try this (either as a global variable, or instantiated when you need it):

<?php
  class Fn {
    public function __call($name, $args) {
      if (function_exists($name)) {
        return call_user_func_array($name, $args);
      }
    }
  }

  $fn = new Fn();
?>

Now any function call goes through the $fn instance. So the existing function 'testfunction' can be called in a heredoc with {$fn->testfunction()}

Basically we are wrapping all functions into a class instance, and using PHP's __call magic method to map the class method to the actual function needing to be called.

Isofarro
A: 

Guys should note that it also works with double-quoted strings.

http://www.php.net/manual/en/language.types.string.php

Interesting tip anyway.

SomeOne