PHP include最佳实践问题

26

我一直在学习PHP的语法并进行练习。我来自.NET背景,所以当涉及到页眉和页脚时,主控页面始终让我感到非常容易。

目前为止,我有一个mainHeader.php和mainFooter.php文件,它们包含我的头部菜单和页脚HTML。我创建了一个mainBody.php文件,在顶部放置了:

<?php include "mainHeader.php" ?>

对于页脚,我放置了


<?php include "mainFooter.php" ?>

这个方法完美地解决了问题,让我很开心,因为我的页面都很好地拼合在一起了。mainHeader中包含了我的<html><body>标签,而mainFooter则包含了它们的闭合标签。

这种做法好吗?


这些文件名应该用引号括起来,对吧? - BoltClock
否则它们将被评估为连接的字符串定义,发出警告,并包括 mainHeaderphpmainFooterphp(没有点)。 - aularon
谢谢。是的,它们在引号中,只是我没有在这里输入它们。 - ItsPronounced
10个回答

53

我在我的控制器中包含了我的视图。我还定义了文件位置以使维护更容易。

config.php

define('DIR_BASE',      dirname( dirname( __FILE__ ) ) . '/');
define('DIR_SYSTEM',    DIR_BASE . 'system/');
define('DIR_VIEWS',     DIR_SYSTEM . 'views/');
define('DIR_CTLS',      DIR_SYSTEM . 'ctls/');
define('DIR_MDLS',      DIR_SYSTEM . 'mdls/');
define('VIEW_HEADER',   DIR_VIEWS . 'header.php');
define('VIEW_NAVIGATION',   DIR_VIEWS . 'navigation.php');
define('VIEW_FOOTER',   DIR_VIEWS . 'footer.php');
现在我只需要包含config.php就可以获得所有所需信息了。 controller.php
require( '../config.php' );
include( DIR_MDLS . 'model.php' );

$model = new model();
if ( $model->getStuff() ) {
    $page_to_load = DIR_VIEWS . 'page.php';
}
else {
    $page_to_load = DIR_VIEWS . 'otherpage.php';
}

include( VIEW_HEADER );
include( VIEW_NAVIGATION );
include( DIR_VIEWS . $page_to_load );
include( VIEW_FOOTER );

谢谢!这非常有用,我已经实现了类似的东西。 - ItsPronounced
快速问题:您是否使用框架?我正在尝试CodeIgniter,想知道是否需要在config.php中定义这些目录信息? - ItsPronounced
不,那是我自己的“框架”。你不必使用CodeIgniter这样的框架。 - Galen
我喜欢这个概念...但有时会挠头来解决行末的语法错误: $page_to_load = DIR_VIEWS . 'page.php' - floCoder
必须在末尾添加分号^,以防你是认真的。此外,我知道这是一篇旧帖子,但仍然非常有用。 - mattroberts33
为什么你要两次使用dirname() - Daniel W.

5
您也可以采用另一种方式。拥有一个带有页眉/页脚的主页面,仅包含正文部分。
<!DOCTYPE html>
<html lang="en">
    <head>
        ...
    </head>
    <body>
        <?php include $page ?>
    </body>
</html>

2
啊,我可以看出这对于生成动态数据非常有用。非常感谢! - ItsPronounced

4

总结以上内容。
使用包含文件的方式是不错的,但不要忘记为页面内容使用模板页。

部分基于Galen和Balus的思路:

page.php

require $_SERVER['DOCUMENT_ROOT'].'/../config.php';
$data = get_data(); // assume we get all required data here.
$pagetitle = "This is a sample page";
$template = "page.tpl.php";
include "main.tpl.php";

main.tpl.php

<!DOCTYPE html> 
<html lang="en"> 
    <head> 
         <title><?php echo $pagetitle?></title>
    </head> 
    <body> 
        <?php include $template ?> 
    </body> 
</html> 

page.tpl.php大概是这样的:

<h1><?php echo $pagetitle?></h1>
<?php if (!$data): ?>
No news yet :-(
<?php else: ?>
<ul>
<? foreach ($data as $row): ?>
<li><a href="news.php?id=<?php echo $row['name']?>"><?php echo $row['name']?></a></li>
<?php endforeach ?>
</ul>
<?php endif ?>

3

在你使用"视图(Views)"或者"模板(Templates)"的时候,你不再需要在控制器(Controller)或操作(Action)中排列你的HTML内容。之后你将会加载一个视图(View),并将其中的值填充,这样所有的HTML源码排列都交给了视图而非你的PHP文件。

$view = new View('layout.php');
$view->header = $header;
$view->content = 'This is the main content!';
$view->footer = $footer;
print $view;

然后加载布局文件,大致如下:
<!DOCTYPE html>
<html lang="en">
    <head>
        ...
    </head>
    <body>
        <div id="header"><?php print $header; ?></div>
        <div id="content"><?php print $content; ?></div>
        <div id="footer"><?php print $footer; ?></div>
    </body>
</html>

这很棒。我刚好在想如何组织视图及其对应的 HTML 元素。 - James P.
为什么我没想到这个!这太棒了。 - Jack

3

这个答案是从2010年的,而在过去的十年中,情况已经发生了改变。

现在的最佳实践方法是使用一个单一的require_once,从一个固定、已知的位置的脚本中利用__DIR__,因为现在Composer已经取代了大多数手工编写的自动加载器。

require_once __DIR__ . '/vendor/autoload.php';

如今使用define()已不再普遍。

根据环境无关的方法,来自环境的依赖项会使用.env或类似方法注入到应用程序中。


2
现今的良好实践是使用模板引擎,例如 smarty。对于整个应用程序,考虑使用一个框架,如codeigniter

10
很抱歉,我没有理解清楚您的请求。请提供更多上下文或详细说明需要翻译的内容。 - Galen
2
我不太喜欢Smarty,但使用模板引擎的想法很好。除了PHP...因为PHP已经是一个模板引擎,这有点奇怪。尽管如此,MVC类型的模式要好得多...嗯...让我们都使用框架吧!但对于PHP来说,h20模板非常酷。 - Mark Snidovich
1
无论你喜欢还是不喜欢特定的模板引擎,使用一个来处理变量替换、循环、条件语句、子模板/包含/宏作为标记(而不是 PHP 代码)在我看来是一个巨大的进步。我使用 PHPTAL,我相信也有很多人讨厌它,但模板就是你的 PHP 等效于母版页。 - grossvogel
1
Smarty、PHPTemplate或其他任何模板引擎的目的在于,在多人合作项目中强制实现关注点分离。它允许PHP开发人员隐藏业务逻辑,只向前端开发人员公开某些部分。如果您是该项目的唯一参与者,则Smarty是不必要的复杂层。 - siliconrockstar
关于框架,CodeIgniter是一个很好的学习框架,但与Yii相比,它的开箱即用功能非常少。CodeIgniter的默认cookie处理也非常不安全。Yii在架构上几乎与CI相同,但包括脚手架、内置Active Record、强大的用户模块、前端小部件和本地jQuery支持。 - siliconrockstar
显示剩余6条评论

1
对于小型网站,include/include_once和require/require_once非常好用,我已经多年没有建立过没有它们的网站了。然而,我建议确保每个包含文件都是一个有效的XML离散代码块。我的意思是不要在一个包含文件中打开标签并在另一个文件中关闭它,反之亦然——这将使更改变得复杂,并且更容易因为文件之间存在依赖关系而导致错误。祝编码愉快!

0

我知道这可能有点晚了,但我想为这个问题提供我的建议。

我的建议是创建相应的方法,例如我的根目录是:var/www/htdocs/,而函数文件位于includes/functions/template-parts.php中。
我的函数看起来会像这样:

<?php

define("DOC_ROOT", "/var/www/htdocs/"); # Add a trailing slash to make it a little easier

function GetHeader()
{
    return include DOC_ROOT . 'includes/parts/header.htm'; # Header found at include/parts/header.htm
}

function GetFooter()
{
    return include DOC_ROOT . 'includes/parts/footer.htm'; # Footer found at include/parts/footer.htm
}

?>

并且可以这样使用:

<?php

# From the main page (/var/www/htdocs/index.php)
require_once 'includes/functions/template-parts.php';
GetHeader();
?>
<!-- Page content -->
<?php

GetFooter();

?>

0

这是一个完全可以接受的方法,只要您的网站不超过20页的限制。但我建议使用函数风格的include(),而不是作为结构,并将这些模板放在单独的子文件夹中。如果它们中没有PHP代码,还可以使用.htm文件扩展名(htm表示部分html)。

 include("template/main/header.htm");   // would still parse PHP code!

这种方法的缺点是,你最终会通过全局变量将HTML注入其中。例如:$HEAD='<link...>'; include("../header.htm")。这本身并不是坏事,但很容易积累垃圾代码。

-1

我喜欢使用函数来打印页眉和页脚,而不是使用包含文件。这样可以更好地调整变量的作用域。


那就是你的答案? - Tilak Madichetti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接