PHP foreach alternate syntax - php

I am learning PHP from the book "Murach PHP and MySQL 2nd Edition" and I came across this code which I don't fully understand...
<select name="productkey">
<?php foreach ($products as $key => $product):
$cost = number_format($product['cost'], 2);
$name = $product['name'];
$item = $name . ' ($)' . $cost . ')';
?>
<option value="<?php echo $key; ?>"> <?php echo $item; ?></option>
<?php endforeach; ?>
</select>
Why are there instructions after the colon (:) at the start of the foreach loop??
I read that after the colon there should be "?>" and then the instructions to execute and then at end "" to mark the end of the foreach loop...
Please explain this AND IF I WRITE THE LINES STARTING WITH $cost,$name and $item after <?php foreach ($products as $key => $product): ?> would the code still work???

yes it would still work : is the same as { but you have to write endforeach at the end of your foreach it does the same thing more info check out this page
documentation

: called an Alternative Syntax For Control Structures.
PHP offers an alternative syntax for some of its control structures; namely, if, while, for, foreach, and switch. In each case, the basic form of the alternate syntax is to change the opening brace to a colon (:) and the closing brace to endif;, endwhile;, endfor;, endforeach;, or endswitch;, respectively.
It allows you to omit braces {} from a foreach to make it look cleaner and its mostly used, within templates.

The colon is an alternative to using brackets.
This:
foreach (...) :
#execute Code in loop
endforeach;
is the same as this:
foreach (...) {
#execute Code in loop
}

The alternative syntax is mainly for use with mixed html content. The main advantage is say you have something like this
<?php if( $var ){ ?>
<!-- some html here -->
<?php foreach( $var as $v ){ ?>
<!-- some html here -->
<?php if( $v=='foo'){ ?>
<!-- some html here -->
<?php } ?>
<!-- some html here -->
<?php } ?>
<!-- some html here -->
<?php } ?>
You quickly wind up with a mess of } everywhere, compare to this
<?php if( $var ): ?>
<!-- some html here -->
<?php foreach( $var as $v ): ?>
<!-- some html here -->
<?php if( $v=='foo'): ?>
<!-- some html here -->
<?php endif; ?>
<!-- some html here -->
<?php endforeach; ?>
<!-- some html here -->
<?php endif; ?>
This is a small example so I don't think if fully shows the issue, but it's much easier to where the if blocks end and the foreach ends even in this.
Now multiple that by about 200 lines of mixed content. Otherwise you can look at it as the : is a { and the end{blocktype}; is the }
Personally I never use it ( except on SO ), because I don't mix HTML and PHP in my code.
cheers.

As you said it normally called PHP alternate syntax for control structure. You can read in more depth in that article:
Alternate Syntax is normally used when we need to mix-up HTML inside PHP. In your code:
<select name="productkey">
<?php foreach ($products as $key => $product):
$cost = number_format($product['cost'], 2);
$name = $product['name'];
$item = $name . ' ($)' . $cost . ')';
?>
<option value="<?php echo $key; ?>"> <?php echo $item; ?></option>
<?php endforeach; ?>
You can see you have a option inside foreach. In this type of case it's better to use alternate syntax. We can use the alternate syntax for if else and switch case as well.

Related

Cleaner code when using alternative syntax and associative arrays.

Im writing a foreach loop for my view using the alternative syntax, to get a piece of html like this
<h3>My Post</h3>
Ive used the line below, but it seems awfully clunky with all the concatenation.
<?php
foreach ($index_posts as $post):
?>
<h3><?= "" . $post['title'] . ""; ?></h3>
<?php
endforeach;
?>
Ive also tried writing it like this :
<?= "<a href='post.php/?id=$post['id']'>$post['title']</a>"; ?>
But it shows errors when written in sublime text 2 around the ['id'] and ['title'] any ideas why this is, as they are single quotes ?
Is there another way i could write this that is cleaner ?
You could just do:
<?php foreach ($index_posts as $post): ?>
<h3>
<a href="post.php?id=<?php echo $post['id']; ?>">
<?php echo $post['title']; ?>
</a>
</h3>
<?php endforeach; ?>
The reason Sublime is showing an error when you do this
<?= "<a href='post.php/?id=$post['id']'>$post['title']</a>"; ?>
is due to the fact that it's a syntax error as you can't have complex variables (like array values with strings for keys) interpolated into a string directly like this. You need to wrap them in {}
<?= "<a href='post.php/?id={$post['id']}'>{$post['title']}</a>"; ?>
Alternatively, you could use:
foreach ($posts as $post) {
printf('%s', $post['id'], $post['title']);
}
<?php foreach ($index_posts as $post): ?>
<h3>
<a href='post.php/?id=<?=$post['id']?>'>
<?=$post['title']?>
</a>
</h3>
<?php endforeach; ?>
Keeping it to HTML whenever you can; I much prefer to not 'echo' out HTML unless needed, although this question really quite about preference. Afterall, PHP is an templating language!
Gotta help a fellow sam...
<?php echo "<h3>{$post['title']}</h3>"; ?>

displaying html from a "php foreach" on a fixed number of columns

I have this code:
<?php if(count($this->items)): ?>
<section class="itemList">
<?php foreach ($this->items as $item): ?>
<...>
<?php endforeach; ?>
</section>
<...> represents item title, description etc... for each item: how can i work on css/html to make those items to be displayed on a fixed number of rows, say 3, instead of on a unique long column?
Thanks to anybody who can help
If you can use CSS3 you can use the propery -webkit-column-count:3; -moz-column-count:3; column-count:3;. Otherwise you have to do it in a different way (splitting it up in your PHP code).
Try something like:
<?php if(count($this->items)): ?>
<section class="itemList">
<?php foreach ($this->items as $item){
$x++;
if($x % 3 == 0){
?><br><?php
}?>
<...>
<?php } ?>
</section>

PHP keeping $variable outside scope of if statement

I've picked up a project from another developer and I'm trying to finish and clean up a bit. This part of the code renders products from a database after checking for a language cookie:
<?php if (get_cookie('spanish')) : ?>
<?php if ($product['details_spanish'] != '') : ?>
<?php $details = explode(':',$product['details_spanish']); ?>
<h3>Especificaciones</h3>
<?php else : ?>
<?php if ($product['details'] != '') : ?>
<?php $details = explode(':',$product['details']); ?>
<h3>Especificaciones</h3>
<?php endif ?>
<?php endif; ?>
<?php else : ?>
<?php if ($product['details'] != '') : ?>
<?php $details = explode(':',$product['details']); ?>
<h3>Specifications</h3>
<?php endif; ?>
<?php endif; ?>
<ul>
<?php if ($details) : ?>
<?php foreach ($details as $detail) : ?>
<?php $detail = split(',',$detail); ?>
<?php if ($detail[0] != '' && $detail[1] != '') : ?>
<li>
<strong><?=ucwords($detail[0])?></strong> : <?=$detail[1]?>
</li>
<?php endif; ?>
<?php $i++; ?>
<?php endforeach; ?>
<?php endif; ?>
Sorry, I know this is hard to read due to inconsistency and bad coding (not my project initially. What it's doing is checking for a spanish cookie on the users machine. If it finds it, it pulls the values from the spanish column of the table instead of the regular. It falls back on the english value if there is no spanish value in the table. Also, it creates a $details variable that contains one of the values of the database, and splits it where the : is.
The problem I'm having is on some products, it gives me an error saying it can't find the $details variable, I'm assuming it is because the variable doesn't live outside the scope of the first if statement?
I'm a php noob really but even I know this isn't good practice. is there a better way to clean this up and have my $detail variable available?
Quick workaround is to pre-initialize that variable at the very top:
<?php $details = ''; ?>

Can I use PHP try/catch around a large block of HTML?

I would like to surround this entire block of code in a try/catch since its causing an error when there is nothing in the grid array. Whats the best way to do this?
<?php foreach ($grid->result() as $idx => $row): ?> <?php if ($idx % 3 == 2): ?>
<div class="img_grid_3"><img src="/images/thumb/<?= $row->images_name; ?>" /></div>
<?php else: ?>
<div class="img_grid"><img src="/images/thumb/<?= $row->images_name; ?>" /></div>
<?php endif; ?>
<?php endforeach; ?>
Thanks
Maybe Im missing the point but why dont you test $grid before doing the foreach?
<?php if($grid): ?>
.... foreach ....
<?php endif; ?>
If I got you right, you're looking for the # error suppression operator. If you pass an empty array to foreach, you'll get a PHP warning, you can't catch this with a try/catch block.
<?php #foreach ($grid->result() as $idx => $row): ?>
<?php if ($idx % 3 == 2): ?>
<div class="img_grid_3"><img src="/images/thumb/<?= $row->images_name; ?>" /></div>
<?php else: ?>
<div class="img_grid"><img src="/images/thumb/<?= $row->images_name; ?>" /></div>
<?php endif; ?>
<?php endforeach; ?>
It's possible to use a try catch block with html contents too, but it will obviously only catch Exceptions.
Note that it's cleaner to check wheter the array is empty or not before you use it in a foreach block.
foreach will not produce an error if the array is empty.
So either $grid is not an object, or result() is returning a non-array like false or null. If the former, surround the foreach with if ($grid), of the latter, than use if (!empty($grid->result()))

endforeach in loops?

I use brackets when using foreach loops. What is endforeach for?
It's mainly so you can make start and end statements clearer when creating HTML in loops:
<table>
<? while ($record = mysql_fetch_assoc($rs)): ?>
<? if (!$record['deleted']): ?>
<tr>
<? foreach ($display_fields as $field): ?>
<td><?= $record[$field] ?></td>
<? endforeach; ?>
<td>
<select name="action" onChange="submit">
<? foreach ($actions as $action): ?>
<option value="<?= $action ?>"><?= $action ?>
<? endforeach; ?>
</td>
</tr>
<? else: ?>
<tr><td colspan="<?= array_count($display_fields) ?>"><i>record <?= $record['id'] ?> has been deleted</i></td></tr>
<? endif; ?>
<? endwhile; ?>
</table>
versus
<table>
<? while ($record = mysql_fetch_assoc($rs)) { ?>
<? if (!$record['deleted']) { ?>
<tr>
<? foreach ($display_fields as $field) { ?>
<td><?= $record[$field] ?></td>
<? } ?>
<td>
<select name="action" onChange="submit">
<? foreach ($actions as $action) { ?>
<option value="<?= $action ?>"><?= action ?>
<? } ?>
</td>
</tr>
<? } else { ?>
<tr><td colspan="<?= array_count($display_fields) ?>"><i>record <?= $record['id'] ?> has been deleted</i></td></tr>
<? } ?>
<? } ?>
</table>
Hopefully my example is sufficient to demonstrate that once you have several layers of nested loops, and the indenting is thrown off by all the PHP open/close tags and the contained HTML (and maybe you have to indent the HTML a certain way to get your page the way you want), the alternate syntax (endforeach) form can make things easier for your brain to parse. With the normal style, the closing } can be left on their own and make it hard to tell what they're actually closing.
It's the end statement for the alternative syntax:
foreach ($foo as $bar) :
...
endforeach;
Useful to make code more readable if you're breaking out of PHP:
<?php foreach ($foo as $bar) : ?>
<div ...>
...
</div>
<?php endforeach; ?>
as an alternative syntax you can write foreach loops like so
foreach($arr as $item):
//do stuff
endforeach;
This type of syntax is typically used when php is being used as a templating language as such
<?php foreach($arr as $item):?>
<!--do stuff -->
<?php endforeach; ?>
It's just a different syntax. Instead of
foreach ($a as $v) {
# ...
}
You could write this:
foreach ($a as $v):
# ...
endforeach;
They will function exactly the same; it's just a matter of style. (Personally I have never seen anyone use the second form.)
How about this?
<ul>
<?php while ($items = array_pop($lists)) { ?>
<ul>
<?php foreach ($items as $item) { ?>
<li><?= $item ?></li>
<?php
}//foreach
}//while ?>
We can still use the more widely-used braces and, at the same time, increase readability.
Using foreach: ... endforeach; does not only make things readable, it also makes least load for memory as introduced in PHP docs
So for big apps, receiving many users this would be the best solution
How about that?
<?php
while($items = array_pop($lists)){
echo "<ul>";
foreach($items as $item){
echo "<li>$item</li>";
}
echo "</ul>";
}
?>

Categories