Wednesday, May 30, 2012

What"s the best way to separate PHP Code and HTML?


I really don't like mixing PHP and HTML. Mixing them makes it difficult to maintain both the PHP and the HTML, and it just makes sense to keep the two apart.



See also the question on whether PHP is a good enough templating system on its own.



What's the best way to do it?


Source: Tips4all

30 comments:

  1. Sheer, iron-willed discipline.

    ReplyDelete
  2. To separate your PHP and HTML as much as possible you need a small template class and a small set of rules to follow.


    Function calls should only be made to render templates or format data like date();
    Only use foreach, no for or while loops
    If statements should only check a variable for true. All boolean logic should be pre-computed.
    Using else is ok.
    If you need to alternate a color either pass boolean values with your array for each row or use ($i++%2). Then in your view you will use an inline if

    < div class='menu < ?=($link['alternate'])?'white':'grey'?>'>
    again if you need to check for the beginning or end of a list pass a flag in the associate array that your currently iterating through.


    To make simple or advanced web site you need something that can hold data and a file path. With the below classes you create a new Template object and bind some data to it as it is created.

    $main = new Template('mainView.php', array('title' => 'example page'));


    Now in your view file mainView.php you access the title like this.

    <?= $title; ?> // php 4 version
    <?= $this->title; ?> // php 5 version


    The reason you use an object instead of just an include file is to encapsulate data. For example:

    $main = new Template('mainView.php', array(
    'title' => 'example page',
    'leftMenu' => new Template('linkView.php', array('links' => $links)),
    'centerContent' => new Template('homeView.php', array('date' => date())),
    ));

    $main->render();


    mainView.php

    <html>
    <head>
    <title><?= $this->title; ?><title/>
    </head>
    <body>
    <div id='left'><? $this->leftMenu->render(); ?></div>
    <div id='center'><? $this->centerContent->render(); ?></div>
    </body>
    </html>


    Below are minimal template classes for both php 4 and 5.

    // PHP 4
    class Template {
    var $args;
    var $file;

    function Template($file, $args = array()) {
    $this->file = $file;
    $this->args = $args;
    }

    function render() {
    extract($this->args);
    include $this->file;
    }
    }

    // PHP 5
    class Template {
    private $args;
    private $file;

    public function __get($name) {
    return $this->args[$name];
    }

    public function __construct($file, $args = array()) {
    $this->file = $file;
    $this->args = $args;
    }

    public function render() {
    include $this->file;
    }
    }

    ReplyDelete
  3. PHP itself was born as a template language with a scripting capabilities. Using Smarty or any other template language means running an interpreted language on top of an interpreted language, which doesn't sound like a good idea if you think about it. At the end of the day, Smarty templates are still "compiled" to PHP code (which is sometimes ineffective and always unreadable), so it might be wiser to just use PHP and not to learn another language.

    Starting there, one should limit the "HTML code" to echo(), basic loops and conditionals, strengthtened maybe with function calls with no side-effects. Calculating MD5 hash inside HTML template to get a link to gravatar image is ok, executing some SQL is not. All data to be rendered inside PHP templates should already be prepared by another module, unless it is trivial to get inside your "view" part.

    The MVC pattern is a good way of thinking about your code. A framework, such as CakePHP, could offer a powerful platform to build on, and provide some hints on organizing code if all its complexity is an overkill for your task.

    ReplyDelete
  4. In my opinion, Smarty's over-complexity defeats the point in separating the logic. Most people abuse Smarty and just treat it as PHP. If you really want to make life easier, use a templating system that is limited to just conditionals and loops. It's all you need in reality.

    ReplyDelete
  5. Use a templating system such as Smarty

    ReplyDelete
  6. Rather than try to seperate your php and html you should instead be separating your backend logic and display logic.

    A templating system requires people to learn its syntax so why not just use php for it

    ReplyDelete
  7. From my point of view you are asking the wrong question, the question should be: ¿How do I separate my Business Logic from the Presentation?

    And the answer is, use a Model-View-Controller Framework (or make your own architecture around this concept).

    Use PHP strong Object support and make nice classes that obtain data from your database, this classes should also handle the saving of this same data. This classes are called "Models".

    Make a nice class that handle the loading of a template (might be a simple "include template.php" or a full [smarty][1] implementation). The template should only do conditionals and loops. This is the "View"

    You still need a third element, a php file that will load the model and will send the data to the view and viceversa (this is where the nasty code usually lives), is called the "Controller"

    The idea is to create reusable components, you can make your own basic MVC architecture or use one of the nice Frameworks out there like Zend's or Cake PHP.

    The basic idea is that if you just split PHP and HTML, you are only splitting the mess in two bedrooms, leaving the corridor with much bigger mess.

    Think like a store, you have your front that display products(usually in a very creative way), a business man in the middle handling clients, and a store room in the back with everything really really ordered. [1]: http://www.smarty.net/

    ReplyDelete
  8. I tend to like Smarty. It's clean, at the cost of a few CPU cycles.

    Rasmus Lerdorf, creator of PHP, has posted some slides from a presentation titled "Simple is Hard." Starting on slide 24, he compares static HTML and basic inline PHP to a number of PHP frameworks. Makes one want to try inline PHP again. Template syntax can be approximated in straight PHP while staying reasonably readable:

    <html>
    <head>
    <title><?php echo $template->title; ?></title>
    </head>
    <body>
    <?php foreach($items as $item): ?>
    <h2><?php echo $item->title; ?></h2>
    <div class="content">
    <?php echo $item->content; ?>
    </div>
    <?php endforeach; ?>
    </body>
    </html>


    Using auto_prepend_value in your .htaccess can automate inclusion of your initialization script, which has the potential to reduce extraneous PHP in your "template." Definitely lots of ways to remove business logic from your HTML pages.

    ReplyDelete
  9. What I have done in the past is to generate all the data for a page and store in hash array:

    $data['#title#'] = 'Page title';
    $data['#textcontent#'] = ' Yadda yadda yadda';


    Grab a seperate bit of text that is the HTML with placeholders in it:

    $html = '<html>
    <head>
    <title>#title#</title>
    </head>
    <body><p>#textcontent#</p>
    </body>
    </html>'; // etc


    Then merge the two with a simple command:

    $html = str_replace(array_keys($data),array_values($data),$html);


    The print or store in cache.

    ReplyDelete
  10. Personally, I live by the "conditionals and loops" rule: my HTML can contain only conditionals and loops in PHP code. This is a subjective rule, obviously, but it's a good principle. You can use PHP to format your HTML (to display a table row for every item in an array or to display a user's login name, for instance) and still keep your business logic completely separate.

    However, if you're not happy with that, there's a host of possible solutions, including Smarty or XSL (might be overkill, depending on what you're doing).

    ReplyDelete
  11. Remember that despite the constant dogma about keeping business logic and presentation separate, there is such a thing as presentational logic.

    Don't be afraid to use inline PHP logic for tasks like sorting and arranging data for display on the page. If your "business logic" modules are full of helper functions with little bits of presentational logic, you are doing it just as wrong as if you were spewing out business logic in the middle of the templates.

    Be suspicious of 'advanced' templating languages that limit you to outputting simple attributes using a microlanguage, instead of letting you use the full power of PHP. This is inflexible dogma which only constrains you; you will end up polluting your business logic with presentational concerns that the templating language won't let you express. You can do perfectly good 'readable' templates with PHP as long as you use it tastefully - for example see the example posted by Adam Backstrom for a good way of keeping track of your structures using indentation.

    (Unfortunately, that example - along with every other one posted here so far - is full of the HTML-injection security holes that PHP is so famous for. Any time you output a bunch of normal text into an HTML page, you must use htmlspecialchars! One way to make this slightly less onerous is to define a function that does echo(htmlspecialchars($s)) and call it something nice and short like 'h', so that you can put:

    <?php h($item->title) ?>


    in the template.)

    ReplyDelete
  12. You must use MVC (model-view-controller) pattern.

    ReplyDelete
  13. Use an application framework like Zend, CakePHP, Symfony or CodeIgniter. These make it possible to divide your application into controllers and views, where the controllers are the code that retrieves the data you want to display and the views are what renders that data to HTML. The views contain a minimal amount of code. Some of the frameworks have a special templating language for conditionals and loops in the views, others just use PHP, but all are focused on keeping the amount of code in the views to a minimum.

    ReplyDelete
  14. Smart is well respected but many people think implementing a macro language in the templates negates one of the main reasons for using a template system - separation of code and html. I would tend to agree with that and instead would point you at Tiny But Strong (www.tinybutstrong.com).

    IMHO the great joy and strength of TBS is it is completely Dreamweaver compatible so if you use that templates can be designed WYSIWYG. If you're working with a designer or uses Dreamweaver (or you do yourself) TBS scores massively as they can be up and running modifying your basic templates within 5 or 10 minutes. Smarty breaks the WYSIWYG model so your designer (or you) has to learn that too and visualize what the clean html looks like instead of seeing it.

    TBS doesn't come with an AJAX library, but it's relatively easy to add one (XAJAX works nicely) and ditto for whatever Javascript library/framework you'd like too. It also enforces a very simple, discrete, code/template model which fans of Zend and the like will look down on, but for 95% of websites this is a positive plus as this modularity pays off in ease of maintenance.

    ReplyDelete
  15. Best practices for software development call for a full separation of business and display logic.

    This particularly applies if you are building a large scale web application (even more so if you wish to release that application as a product and have your users/customers tailor it).

    As noted by others, PHP was originally designed to be a templating system, but has evolved into a rich complex object oriented development language.

    As a result, the best way to split your true presentation code from your business logic is to use a templating engine.

    There are many of these.

    Smarty is a popular and long-standing templating engine, which is somewhat "Pushing the boundries" and getting closer to PHP (i.e. becoming a language in it's own right). The Zend Framework includes it's own templating engine which takes a pure PHP5 OO approach using PHP as the formatting language in templates. And the SimpleT template takes a very light weight PHP4 approach to using PHP as a templating engine. There are other engines around such as PEAR's HTML Template Flexy class which provide a less "language like" templating engine.

    The right choice for your application will depend on what you are doing, always remembering that the right choice might be no templating class but simply performing the logic in one code block followed by a full "template" of HTML populated with loops and variables in the next part of the file. If it's a small application with a limited lifespan, the saving in effort doing this in the short term may pay off against the larger effort required to fully implement templating.

    ReplyDelete
  16. I like to use alternate syntax when working with html. For example:

    <div class="profile-header">
    <div class="left">Blog</div>
    <?php if($profile_data['userid']==$userid):?>
    (<a href="/<?=strtolower($profile_data['username']);?>/edit/blog">New Blog Post</a>)
    <?php else:?>
    (<a href="/rss/<?=strtolower($profile_data['username']);?>/">RSS Feed</a>)
    <?php endif;?>
    </div>


    It really does help keep the code clean, and to a designer, it shouldn't be too hard to pick up. not only that, but it's similar to the way Wordpress templates work.

    ReplyDelete
  17. If you use REST techniques - so that POST requests do work and then send the browser a 303 redirect to GET to view the results, you quickly achieve two things:


    The browser back button behaves itself - no more duplicated actions.
    Your business logic and views get nicely separated.

    ReplyDelete
  18. Template systems such as Smarty are a good way to go.

    If this is overkill for your particular project, then the best solution is to separate the PHP logic and HTML presentation code into separate files, including the PHP files in your HTML, e.g.

    index.php:

    <?php
    include("user_functions.php");
    $user_data = get_user_data();
    ?>
    <html>
    <body>
    <?php
    foreach($user_data as $user)
    {
    echo "User: ".$user."<br />";
    ?>


    user_functions.php:

    <?php
    function get_user_data()
    {
    ...
    }
    ?>


    There is still some cross-over between PHP and the HTML, but it's at a minimum, and makes maintenance of the PHP functions much easier when you're not rooting through layers of HTML to get at it.

    ReplyDelete
  19. A good MVC framework that I have come across is Kohana It is simple to use and easily extensible. Doesn't require any server side includes.

    I will be using it in one of my web projects.

    ReplyDelete
  20. I agree with the answers here suggesting that you avoid using anything besides PHP for templating. And of course, there is such a thing as presentation or display logic. That said ...

    You can separate your PHP and HTML into separate files -- putting HTML files into a views or templates directory -- depending on how you want to set things up. If you do it this way, the last line of any PHP script using that template or view can just be an include statement.

    If you keep things in the same file, that can work too, if the project isn't too complicated. In this case, instead of an include statement, you'd have two chunks of stuff, PHP to start and HTML to follow.

    Of course, you will need to pepper your HTML with echos, and sometimes you will need some logic right there along side your HTML, but try to keep it to a minimum. There's often no way around it when you are presenting results, say, from multiple rows in a database. Sometimes you can put the WHILE chunk in a nested sub-template.

    One thing is don't echo HTML with PHP. Yuck. You will regret this.

    I try to avoid using curly braces around chunks of HTML too. Not always feasible, but a good rule to follow.

    ReplyDelete
  21. Separating your code into MVC should NOT be an automatic first step. There are many cases where a simple procedural framework makes much more sense.

    I agree with @AdamBackstrom that inline PHP is simpler and more effective than placing one templating system (such as Smarty) on top of another templating system (PHP). If you don't take advantage of PHP's existing templating system, why are you using the language at all?

    ReplyDelete
  22. @[levhita]:

    At the end of the day, the Presentation or View part of a project must have some form of code or templating system in it, as there is variables that need to be outputted, template files to be included, etc etc etc.

    Perhaps the question should then be what code and how much code is allowed in the Presentation / View part of a framework / project.

    ReplyDelete
  23. It's good practice to separate you data model, your business logic, and your presentation layer. The most popular and talked about way to do that is to use and Model-View-Controller (MVC) design pattern. There are other design patterns such as the Presentation-Abstraction-Control (PAC) design pattern. While this pattern is not as widely talked about it is regularly used.

    Most of the frameworks and content management systems use some form of this right now. If you start digging through the code of systems like symfony, cakephp, drupal, joomla, and others you'll see these types of systems in action.

    ReplyDelete
  24. My way of doings is the same as described above. Add inbetween is the easiest. And if I need to insert things into a snippet of code I create multiline variables with placeholdes that I replace later.

    <?php
    $snippetCode = <<<html
    <a href="%URL%" alt="%ALT%">%TEXT%</a>
    html;

    echo str_replace(array('%URL%','%ALT%','%TEXT%'),array('http://stackoverflow.com', 'Stack Overflow', 'This way to Stack Sverflow'),$snippetCode);
    ?>

    ReplyDelete
  25. Personally I found the way that works for me is to work with XSL Transformations (XSLT).

    Have one script containing your (PHP) logic outputting XML and one script produce the XSL to translate the XML to something visible. I usually implement this all on top of a homemade rewrite of Fusebox (the rewrite is purely because I don't use most of the features Fusebox offers and they do create overhead).

    This might seem like a bit of overkill, especially on smaller projects, but I noticed a huge increase in the speed with which I can make modifications. Let's just say that my boss was pleased.

    Imagine having the following information in an array, which you want to display in a table.

    Array
    {
    [car] => green
    [bike] => red
    }


    You easily create a script that outputs this information in XML:

    echo "<VEHICLES>\n";
    foreach(array_keys($aVehicles) as $sVehicle)
    echo "\t<VEHICLE>".$sVehicle."</NAME><COLOR>".$aVehicles[$sVehicle]."</COLOR></VEHICLE>\n";
    echo "</VEHICLES>\n";


    Resulting in the following XML:

    <VEHICLES>
    <VEHICLE>
    <NAME>car</NAME>
    <COLOR>green</COLOR>
    </VEHICLE>
    <VEHICLE>
    <NAME>bike</NAME>
    <COLOR>red</COLOR>
    </VEHICLE>
    </VEHICLES>


    Now this is all excellent, but that won't display in a nice format. This is where XSLT comes in. With some simple code, you can transform this into a table:

    <xsl:template match="VEHICLES">
    <TABLE>
    <xsl:apply-templates select="VEHICLE">
    </TABLE>
    </xsl:template>

    <xsl:template match="VEHICLE">
    <TR>
    <TD><xsl:value-of select="NAME"></TD>
    <TD><xsl:value-of select="COLOR"></TD>
    </TR>
    </xsl:template>


    Et voila, you have:

    <TABLE>
    <TR>
    <TD>car</TD>
    <TD>green</TD>
    </TR>
    <TR>
    <TD>bike</TD>
    <TD>red</TD>
    </TR>
    </TABLE>


    Now for this simple example, this is a bit of overkill; but for complex structures in big projects, this is an absolute way to keep your scripting logic away from your markup.

    ReplyDelete
  26. You can use a template system like Smarty or you could use a framework like CakePHP.

    ReplyDelete
  27. PConroy's is a good answer - also make extensive use of CSS so that those elements are kept separate.

    ReplyDelete
  28. Back in the days when PHP4 was cutting edge, PHPlib's templating system served me well. It is simple to setup and really easy to use for basic things. See some examples here.

    It is a bit old but it is stable and simple.

    ReplyDelete
  29. The best way to separate PHP Code and HTML is to follow MVC pattern. Adopting one of the PHP frameworks like Zend or CakePHP would be a good start. Using one of these frameworks would save you countless development hours and help you focus on meeting the business needs of the project.

    ReplyDelete
  30. You can write your own basic template system with something like:

    function Render($Template, $Data) {
    extract($Data);
    include($Template);
    }


    Extract() is used to create local variables from an associative array that can be used in template file. You could also automatically escape your data.

    In your template file you can use <?= $Foo ?> to render a variable. Short tags are not portable but you can use your favorite build tool to replace <?= to <?php echo before deploying your application.

    For loops and conditions, your can use the alternative syntax:

    <? if ($Foo): ?>
    ...
    <? endif; ?>

    ReplyDelete