That is the exact behavior I want to separate parts. I would like to see use cases where I would actually need the safeInclude function.
Example
<?php
include 'header.php';
include 'nav.php';
include 'content.php';
include 'footer.php';
That example is NOT something I would do, since it looks like "blind includes". Do those include contain functions, or are they spitting out markup directly without functions?
Really there's NO reason for them to be separate includes, and I would suspect you've got ZERO scope isolation.
Hmm... the database connection in the next release of this is a very good usage case. Let's take some features from main() which replaces the IIFE in index. (see previous post about the new index.php)
It connects to the DB
$db = new Database($dsn, $username, $password, $options);
Later on the same function loads the content outputter:
if (file_exists($fn = $data['contentFilePath'] . '.content.php')) {
safeInclude($fn);
action_content($data);
}
That PHP file has ZERO business having access to the database handler. None. Nada, Zip, Zilch. Given how easy code appendages are
(thanks to the F***wit ability of PHP to fopen source files) and how often they are a "non-destructive avenue of attack", restricting access to the gooey bits and adding re-use prevention is essential to at least make them work harder for it.
Since any idiot can fopen "a", modifying the existing code or supplanting it takes a bit more work. It's not a great answer, but with PHP's "insecure by design" methodology, we do what we can do.
EDIT: Ok, I see why this "problem" exists. In the function, you are echoing the text "test" instead of returning it. If you return the text then all the examples work as they should.
The periods are concatenation. The commas are argument separators just like in functions. The arguments are written to the output in the same order as they are passed in.
With your first example, the period has precedence so the function right after it is run first, then everything else is output.
I would have to call this a good example of bad programming.
It's not always. In fact if you understand the underlying mechanism if all you're going to do is echo the result, it can be more efficient on memory use since you're not expanding the stack or lobbing the result onto the heap.
But it's a matter of do you want to be a pedantic ass willing to slop out a massive memory footprint for the name of some esoteric bullshit, or do you want efficient code.
Though again, I suspect that's my inner machine language coder talking. There's a LOT of things high level language dev's say that make me go "dafuq u say?"Generally though yes, it's a construct one would not use without very good reason. It's more of a mental exercise to illustrate why string addition
(concatenation my ass) on echo is an inefficient construct, painfully so if you look at memory usage. It's not "operator precedence" apart from the fact the string HAS to be COMPLETELY built before it can be passed to echo!
When you use a string addition the ENTIRE string has to be built in memory before it can be passed to the result. Be that result a variable, a function, or a language construct like echo.
That means you have to malloc a "guess' as to how big the result is going to be, it means you might have to "grow" using pointers or reallocate to a new larger memory pointer (the latter wasting time copying your existing values again and leading to memory fragmentation). EVERYTHING has to be copied into this new result before it can be passed along.
Whereas if you comma delimit echo, static pointers to the static strings and dynamic pointers to the variables can just be passed in sequence, requiring none of the mental masturbation and memory thrashing idiocy that string addition brings to the table. Inf act, this is why most of the string heavy string-based string processing "template" systems like Smarty are bloated inefficient crap, no matter how much it mollycoddles "front end developers" who to be frank, don't know enough about the back end to be front-ending jack!
About two years ago I had a client where their site was killing their high end hosting despite traffic numbers a cheap VPS could have handled. It was constantly choking out on RAM, and the reason was obvious to me, but invisible to most. String addition.
They had constructed their PHP output to be one giant ternary operation as a single string added echo. The result was that their bloated 240k of markup was taking a megabyte or more to process. Now, a megabyte might seem like piss in a bucket in the age of gigabytes of RAM... but that's a megabyte of string processing, multiple stack/heap grows, endless copying of that megabyte of strings around, and you multiply that against a hundred thousand requests an hour, and we're talking terrabytes of memory thrashing over that time period.
Just switching it to separate statements and comma delimited echo's dropped the memory footprint by a factor of four and processing time by 3. Of course once I replaced their nutjob 240k of bloat with the 28k needed to do the job, they were able to switch from a big fancy expensive dedicated server to a $20/mo VPS.
And in that way, calling a function to output something from inside an echo can in fact result in lower memory use. I mean in practice it's NO different (given how null is echo'd) from:
echo 'This is a ';
test();
echo '<br>';
It's just a cleaner simpler syntax. It can also be a handy construct in template separation.
echo test($id, $db) ? '<i class="fas fa-lock-open"></i>' : '<i class="fas fa-lock"></i>';
function test($id, $db) {
$stmt = $db->prepare('SELECT text, statusCode FROM status WHERE id = ?');
$stmt->execute([$id]);
if ($row = $stmt->fetch()) {
echo $row['text'];
return $statusCode > 0;
}
echo sprintf(Lang::get('failed_status'), $id);
return false;
} // test
Test may echo any of a dozen different text values, but it returns true or false so we can show the correct icon SEPARATELY from the content text. That way the template can set the icon without care for what text is echo'd out by the function.
Consider it akin to how you can leverage boolean false with === on a return value vs. string where a empty string is a valid value, or multi-handle parameter types (like echo does).