TLDR
Also allow to convert echo statements with comma-separated values to echo statements with HEREDOC syntax
// ... given
$gender = 'male';
$name = 'Matteo';
function getSalutation(string $gender): string { return $gender === 'male' ? 'Mr' : 'Mrs'; }
/*
* To be converted: echo with comma-separated expressions
* <pre>Mr. Matteo</pre>
*/
echo '<pre>', getSalutation($gender), ' ', $name, '</pre>';
// converted, from echo with comma-separated, to echo with HEREDOC
$getSalutation = 'Mr.'; // in HEREDOC, need to have extracted expressions to variables
echo <<<DELIMITER
<pre>$getSalutation $name</pre>
DELIMITER;
Background
In PHP, a common practice is/was to output to a buffer a bunch of expressions separated by comma.
This is still very prevalent in both legacy and recent code-bases, and I consider it to be an ugly malpractice, in MOST of the cases (nothing wrong in keeping it simple for small cases with a little amount of comma-separated expressions).
Gotchas
This one can be tricky. Echo with comma-separated values acts slightly different from concatenation expressions within an echo statement.
Concatenation expressions first accumulate all the returned expression results, and then output them to the buffer.
Take this example
// given
function getCandPrintB(): string {
echo 'b'; // (!)
return 'c';
}
echo 'a', getCandPrintB(), 'd'; // outputs: 'abcd'
If we just simply convert it to a concatenation, we will get the wrong result
echo 'a' . getCandPrintB() . 'd'; // outputs: 'bacd'
'b'
is the first thing to be printed out, because the rest is printed out only when the full concatenated string is built.
Who would do this?
Sadly, a lot of people. Usually, functions which output to the buffer themselves, do not have a return value.
Solutions
Do not convert to HEREDOC if echo with commas contains a function call
Just avoid the hassle in the first place. If we see a function call, we do not display the HEREDOC intention.
Convert to HERDOC anyway
We could also decide to not care at all, whether the result would have the same output, and push the responsibility of testing to the developers themselves.
However, it feels wrong to offer automated conversions which might break your code.
Convert to HEREDOC anyway, but wrap function calls between ob_start()
and ob_get_clean()
This would allow us to catch the output of the function calls, and the result.
Then, in the HEREDOC string, we just need to add both values we have caught.
For example
// ...
ob_start(); // new temporary buffer
$fnCallReturn = getCandPrintB(); // will return 'c', and print 'b' to the new temporary buffer
$fnCallOutput = ob_get_clean(); // close temporary buffer, and save 'c' into $fnCallOutput
// will print abcd
echo <<<DELIMITER
a{$fnCallOutput}{$fnCallReturn}d;
>>>;