奇怪的定位开放和关闭PHP标签?

I am pretty new to programming and have absorbed some 150 pages of a book. I was going smooth with PHP when the code below bumped me hard. Can anyone explain about the positioning of opening and closing PHP tags.

<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    echo "<p>Thanks for Registering</p>",
    "Username: ", htmlentities ($_POST['username']), "<br />",
    "Email: ", htmlentities ($_POST['email']), "<br />";
    }
    else { ?>
    <form action = "test.php" method = "post">
            <label for = "username">Username: </label>
            <input type = "text" name = "username" />
            <label for = "email">Email: </label>
            <input type = "text" name = "email" />
            <input type = "submit" value = "Register" />
    </form>
    <?php }
?>

What I suppose is that, there should be only one pair of PHP tags:

  1. The opening tag <?php at the very begining of the code above
  2. The closing tag ?> at the closing of the code above

Anything else is hard for me to digest, please help me to understand that why the php tags are there in between the code at very weird positions. Thank you

The easiest way to think about it is to do what the parser does, that is, replace the content outside of the php tags with echo statements within php tags.

The main benefit of doing it like this is that you don't have to escape the HTML in php strings, plus, if well structured, you can view it pretty well in a WYSIWYG editor

Here's an example of code that is equivalent to what you wrote and doesn't switch out of php mode

<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    echo "<p>Thanks for Registering</p>",
    "Username: ", htmlentities ($_POST['username']), "<br />",
    "Email: ", htmlentities ($_POST['email']), "<br />";
}
else { 
  echo "
    <form action = \"test.php\" method = \"post\">
            <label for = \"username\">Username: </label>
            <input type = \"text\" name = \"username\" />
            <label for = \"email\">Email: </label>
            <input type = \"text\" name = \"email\" />
            <input type = \"submit\" value = \"Register\" />
    </form>";
}
?>

Control structures in PHP (e.g. loops, functions, etc.) can be split across pairs of end tags. Effectively, anything not enclosed in PHP tags is just emitted as though it were being echoed (or captured in the current output buffer, if there is one).

       Try this
 <?php
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            echo "<p>Thanks for Registering</p>",
            "Username: ", htmlentities ($_POST['username']), "<br />",
            "Email: ", htmlentities ($_POST['email']), "<br />";
            }
            else { 
    echo '
            <form action = "test.php" method = "post">
                    <label for = "username">Username: </label>
                    <input type = "text" name = "username" />
                    <label for = "email">Email: </label>
                    <input type = "text" name = "email" />
                    <input type = "submit" value = "Register" />
            </form>';
            }
    ?>

As per the manual on PHP tags

When PHP parses a file, it looks for opening and closing tags, which are which tell PHP to start and stop interpreting the code between them. Parsing in this manner allows PHP to be embedded in all sorts of different documents, as everything outside of a pair of opening and closing tags is ignored by the PHP parser.

Which means the code between the php tags will be echo'd and outside one:

<form action = "test.php" method = "post">
            <label for = "username">Username: </label>
            <input type = "text" name = "username" />
            <label for = "email">Email: </label>
            <input type = "text" name = "email" />
            <input type = "submit" value = "Register" />
</form>

will be treated as a normal HTML. In the case above PHP checks if the form has been POSTed, and if so, it displays a thank you message. If the HTTP request is not POST, it will display a form for the user to post.

In general it's not good practice to mix HTML and PHP and you should avoid this sort of structure.

The opening and closing <?php tags are to tell the interpreter which code is php code (and therefore it should interpret) and which code is something else - HTML, CSS, JS etc.

You'll notice this:

echo "<p>Thanks for Registering</p>";

This is a valid PHP statement and is okay to send to the PHP interpreter.

However, later on in the script the author want to output a load more HTML - he could of course do something like this:

  echo '<form action = "test.php" method = "post">
        <label for = "username">Username: </label>
        <input type = "text" name = "username" />
        <label for = "email">Email: </label>
        <input type = "text" name = "email" />
        <input type = "submit" value = "Register" />
</form>';

But instead chooses to tell the interpreter to just ignore all of this HTML content by closing the PHP section with a ?> and output normal HTML.

He needs to finish the else{} block though, so reopens PHP with <?, adds the closing } and then completes with a closing ?>

The PHP manual does a poor job of explaining what actually happens. The PHP parser definitely does not ignore the text outside the block. Instead the PHP parser turns that text into an echo operation. Don't believe me? You can see for yourself in the source code. In zend_language_parser.y, you will find the following line:

|   T_INLINE_HTML           { zend_do_echo(&$1 TSRMLS_CC); }

When you see <?php if($condition) { ?><div>...</div><?php } ?> it's exactly equivalent to <?php if($condition) { echo '<div>...</div>'; ?>.

The syntax might look odd, but it's actually very useful in some situation. For example, all our web pages typically share the same header and footer. People often handle this by doing an include('header.html') at the beginning of the script and an include('footer.html') at the end. It's not a very flexible approach. Moreover, you end up with two halves of one HTML document that won't render correctly in a browser.

A better way is to slices up the HTML doc with function declaration:

<?php function printHeader($title = "Default Title", $extraJSScrpts = array(), $extraCSSFiles = array()) { ?>
<html>
    <head>
        <title>
            <?php echo $title; ?>
        </title>
    </head>
    <body>
        <div style="position: absolute; left: 150px; top: 35px;">
<?php } ?>
<?php function printFooter() { ?>
        </div>
    </body>
</html>
<?php } ?>

If you ignore the <?php ... ?>, what you have is a regular HTML doc. Looking at the PHP again, you see I have two functions, printHeader() and printFooter(). Instead of doing includes, all my pages now just call these two functions. Each page can pass optional arguments to deal with any special needs (an extra stylesheet, for example). Should I want to implement different themes on my site, it'd be very straight forward. All I have to do is change which file I include at the beginning to bring in different versions of these functions.

Note that PHP also provides an alternative syntax for control structures that improves readability when they're employed to control HTML. The following code creates a table with alternating background color from a list of items:

<table style="width: 100%">
    <?php foreach($items as $index => $item): ?>
        <?php if(!($index & 0x0001)): // even ?>
            <tr style="background-color: #FFFFAA">
                <td>
                    <?php echo $item ?>
                </td>
            </tr>
        <?php else: ?>
            <tr style="background-color: #AAFFFF">
                <td>
                    <?php echo $item ?>
                </td>
            </tr>
        <?php endif ?>
    <?php endforeach ?>
</table>