Your teacher is wrong, echoing HTML is always considered bad practise.
A very common (more advanced) pattern is called MVC, you don’t need to learn or focus on this at the moment, but it can help explain why we separate stuff. In this pattern you have:
Model:
Where your application logic resides.
View:
“Blind” html view templates. Note that with PHP we usually write these in a php file so we can echo variables, do ifs and loops, etc. But the view should never “go out” and fetch data on its own, it should not know about the database/datastore, it should not know of any APIs, etc.
Controller:
The code where you take actions from the user (urls/params), and use the Model(s) to get data and pass along to a view.
Writing code like this might be a bit overkill for a small project. But I prefer it nevertheless as it makes the code extremely structured.
Simple example:
[php]
// .htaccess
turn on apaches rewrite engine
RewriteEngine On
will silently redirect
to the real (and ugly) url
the user will still see the pretty url though!
RewriteRule ^blog/post/([^/]*).html$ /Controllers/Blog.php?post=$1 [L]
// Controllers/Blog.php
<?php
// include some common stuff, like config, db, session, error handling, etc
require_once '../Common.php';
if (isset($_GET['post'])) {
// Show the specified post
// Note how the controller doesn't care about how we find a post,
// we just ask the PostModel to handle it for us
$post = PostModel::findOneByIdSlugAndActive($_GET['post']);
if (!$post) {
// We didn't get a post back from the post model,
// show a beautiful error message to the user!
View::render('404');
}
// All ok, show the post
// Note how we let the View class handle how we render our views
// We just pass along the template we wish to use, and any potential
// parameters we want to have available in the view.
View::render('Post/Single', $post);
} else if (isset($_GET['cat'])) {
// Show the specified category
$category = CategoryModel::findByIdAndActive($_GET['cat']);
if (!$category) {
View::render('404');
}
$posts = PostModel::findAllByCategoryAndActive($_GET['cat']);
View::render('Category/Grid', array($category, $posts));
} else {
// Show everything
$posts = PostModel::findAllByActive();
View::render('Post/List', array($posts));
}
// Models/PostModel.php
<?php
Class PostModel extends BaseModel {
// base model sets up our db stuff with error handling
private $db;
public static function findAllByActive() {
return self::db::query(
'SELECT *
FROM post
WHERE active = 1'
);
}
public static function findAllByIdAndActive($id) {
return self::db::query(
'SELECT *
FROM post
WHERE id = ?
AND active = 1',
$id
);
}
public static function findAllByCategoryAndActive($categoryId) {
return self::db::query(
'SELECT *
FROM post
WHERE category_id = ?
AND active = 1',
$categoryId
);
}
public static function findOneByIdSlugAndActive($idAndSlug) {
list($id, $slug) = explode('-', $idAndSlug, 1);
return self::findAllByActive($id);
}
}
// Views/404.php
404 - page not found
// Views/Post/Single.php
<?= $post->title ?>
![]()
<?= $post->body ?>
// Views/Category/Grid.php
<?= $Category->title ?>
<?php foreach ($posts as $post) { ?>
<?= $post->title ?>
<?php } ?>
[/php]
As you can see lots of code even for this simple example (and it’s not even complete).
But! It is structured, the controllers are very slim andPso readable you don’t even need comments. With the model separated you can change the data store without having to rewrite your entire application (controllers and views stay the same). The loose coupling between controllers, models and the db also mean that you are able to test your application. Which in a professional environment is very important.
Another positive thing with not echoing html is that your IDE/editor can actually highligh the code/autocomplete/show errors when you write proper html instead of strings in PHP