Tuesday 8 March 2016

PHP's equivalent to <cfsavecontent>

I almost wrote an article about this six or so months ago as it's a half-way interesting topic. And now I realise I should have because someone asked the very same question on Stack Overflow ("php equivalent for coldfusion cfsavecontent"). The accepted my answer, so I'm gonna do another sneaky cop-out and replicate my answer as an article here as well. Hey... I wrote it, I should be allowed to do what I like.

For the uninitiated, <cfsavecontent> (or savecontent()) allows one to enclose some code in a block, and any output generated within the block is assigned to a variable instead of being output. This is handy for capturing large strings which need logic to build: much nicer than just string concatenation.

In tag-based code, <cfsavecontent> is pretty slick:

<cfsavecontent variable="content">
    Some text<br>
    <cfif randRange(0,1)>
        <cfset result = "value if true">
        <cfset result = "and if it's false">
    Message from include is:
    <cfinclude template="./inc.cfm">


And inc.cfm is:

<cfset greeting = "G'day">

This outputs:

Some text
and if it's false
Message from include is: G'day

That's pretty straight forward. The script version is a bit sh!t:

savecontent variable="content" {
    // stuff goes here

Honestly Adobe, WTH were you thinking? Passing the variable name as a string? How was this not just an assignment, like anyone with a glimmer of language design skills might do? And, yes, I have mentioned this before: How about this for savecontent?

Anyway, that's CFML. In PHP one doesn't have tags, but equally one doesn't have weirdo assign-by-string-name constructs either. The equivalent PHP code is:

echo "Some text" . PHP_EOL;
if (rand(0,1)){
    $result = "value if true";
    $result = "and if it's false";
echo $result . PHP_EOL;
echo "Message from include is: ";
include __DIR__ . "\inc.php";

echo ob_get_clean();

And inc.php:

$greeting = "G'day";
echo $greeting . PHP_EOL;

(I'm running this from the shell, hence PHP_EOL instead of <br> for the line breaks).

That's pretty straight forward. What I actually like about this is there's no requirement to have a block structure at all: one simply says "start output buffering", and then later one does something with what's been buffered: in this case returning it, so I can output it.

There's a whole bunch of other functionality in the Output Buffering "package", and now it's piqued my interest so I will go have a look at it.

That's it. self-plagiarism complete.