Mixing PHP function call and HTML in a template foreach loop


Banging my head against…

What is wrong with this?

I am aware html element attributes require double quotes and I am aware php within double quotes is parsed and not taken as a lteral string
…code is heavily reduced for clarity…

<?php foreach ($groups as $group) : ?>
<img src="/img/$vertical_group->id.jpg" (should parse to /img/1.jpg")

I have tried replacing $vertical_group->id with <?= $vertical_group->id ?> to echo it.


That won’t get parsed because it’s not inside <?php ... ?> tags.

1 Like


Do I need to put the whole html element inside php tags?

No, that should work, but I guess you’ll be getting a different error. What is the result when you use

<img src="/img/<?=$vertical_group->id ?>.jpg"

This doesn’t work:

    echo '<img src="/img/raster/vertical_groups/' . $vertical_group->vertical_group_id . '.jpg">'

and this doesn’t work:

	echo "<img src=\"/img/raster/vertical_groups/$vertical_group->vertical_group_id.jpg\">"


Define doesn’t work. What error are you getting, or what is being echoed?

The foreach creates a quite a complex navigation system, including a header bar with 6 links, each of which, when clicked, shows a “mega menu” (in CSS speak). The image I am having issues with is displayed on the left of this mega menu.

That aside, the problem is nothing to do with the other code as:

  1. I know I have $course_groups as an array of objects (I have successfully used the $title property of the first object just above this code and I know I do have an $id property available. This from debugging.

  2. If I just use your code but replace this (<?=$vertical_group->id ?>) with this (1), it works perfectly.

p.s. You can see from my code in my later post that the values are actually different in reality. I did simplify for the post but have expanded the reply to the true values before testing. Use the later ones if you want.

So this doesn’t work:

<img src="/img/raster/vertical_groups<?=$vertical_group->vertical_group_id ?>.jpg">

But this does:

<img src="/img/raster/vertical_groups/1.jpg">

And the “error” I’m getting is that, when I view the page, I get only the first navigation link (so the foreach has only looped once) and I also don’t get the mega menu at all (so the loop is incomplete - debugging just breaks out when it gets to this line… rather unhelpfully… doesn’t say why just jumps out of the debug process… I’m using xdebug and vim)

So the code is “stopping” at this line but I have no idea why?

I can post the code for the whole template and the controller that feeds it the $course_groups array if you’d like (fair bit of it).

As you have discovered, jumping between php and templates is a real pain especially when quoting is involved. That is one of the reasons why template engines such as Twig are so popular. However, I know you want to understand all the details.

I would suggest switching to the php heredoc string notation which not only reduces having to switch between php and templating but pretty much eliminates the quoting issue.

I would also suggest that you start to move some code into dedicated functions. I think it will help in debugging. So here is a working example:


$groups = [
    ['id' => 1, 'name' => 'image1'],
    ['id' => 2, 'name' => 'image2'],
foreach($groups as $group) {
    echo render_group_image($group) . "\n";
function render_group_image($group) : string {
    $html = <<<EOT
<img src="/img/{$group['id']}.jpg">{$group['name']}</img>
    return $html;

I used arrays here just to keep the example simple but $group->id will work just fine as well for objects.

I might add that your really should be escaping your html output but that is a refinement that can be added later.

Is that because the second has a / before the 1 and the first does not? Or does your variable include the leading slash? What does the first show when you view source in your browser?


Thank you for your response.

I have triple checked this before I replied. No, it’s not that. I’ve made sure there is that forward slash in place. Having this <?=$vertical_group->vertical_group_id ?> doesn’t work. As I said above, I just get the one navigation link which, when clicked, does not drop down the mega menu. Removing exactly that piece of code and replacing with a 1 works beautifully.


Pain is right!

So, looking at your code:

I wouldn’t need this:

$groups = [
    ['id' => 1, 'name' => 'image1'],
    ['id' => 2, 'name' => 'image2'],

as I have my data available from the controller.


foreach($groups as $group) {
    echo render_group_image($group) . "\n";

would be exactly the same.

And, I could add the function as a method in my entity class and call it with something like this:

$var = $entityClass->render_group_image($group);


Sure. Don’t know what your $entityClass does nor if it should be rendering but you can make the function a method if you like.

By the way, the original code I posted was meant to be a standalone file you could run directly from the command line. Hence the data initialization. Reducing problems to small test cases can be an effective means of trouble shooting.

Is there an ambiguation issue where curly-braces might help? I’m never sure of the rules on this.

<?={$vertical_group->vertical_group_id} ?>

My rule is very simple: Always use the curly braces.

I sort-of meant that I’m never sure where they’d help or where they’re appropriate.

In the first post the OP is inside a foreach that produces $group, how does that relate to the $vertical_group that is being used? Or does it not, that was just to give a flavour of the layout?


I get an error… “unexpected { on line…”

They always work so, in my opinion, they are always appropriate. Never ran across a case where using them broke something. Already have too many rules to remember as it is.

Remember the {} are only used inside of actual strings. So <?= {$ whatever is not going to work.

I assume the $vertical_group was just a distraction or a test of some kind.


I’ve not used braces before like this. What would be the syntax in my example?

That would be it then, not appropriate here.

I’m afraid this is one of those fish vs dynamite cases. There is simply not enough info for me to provide you with a copy/paste fix.

Take the original code I posted and paste it into a file then, from your command line, do something like “php file.php”. Look at the results and compare it to the code. Study the heredoc link in the manual I posted as well.

After that, you will either understand or your won’t.