php中的文件包含

来源:互联网 发布:淘宝衣服背景素材 编辑:程序博客网 时间:2024/04/28 18:37

php关键词

      php中用于文件包含的关键词有:include、include_once、require、require_once。一般来说,把include和require分在一组里,而include_once和require_once是一种改进完善形式。本文通过研究include和require的性质,兼顾include_once和require_once,获得php文件包含的基本知识和潜在问题,并提供一个可行的解决方案。

被包含文件的类型

      使用包含关键词包含的文件,只要是文本文件,php解析器都将文件的内容作为php文件处理。

     也即php解析器将当前执行脚本的包含文件读出后,将php嵌入标签中的内容作为源代码执行,而其他没有被标签包含的将作为文本直接输出。
     设有两个文件a和b.php,内容分别如下:

a
akjfladskjfla<br>
<?
echo $_SERVER['PHP_SELF'],'<br>';
echo 'I am A<br>';
?>

b.php
<?php
include 'a';

echo $_SERVER['PHP_SELF'],'<br>';
echo 'I am B<br>';
?>

     输出如下:

akjfladskjfla 
/webapp/codesnipe/b.php
I am A
/webapp/codesnipe/b.php
I am B
     
     文件a无后缀名,其中包含了一个php嵌入标签。如果执行文件a,系统将会报错。但是在文件b中,包含了文件a。没有被包含在php嵌入标签中的文本被直接输出,而包含在标签中的文本作为php源代码执行。

信息格式

      还是上面的实验,我们把文件a删除,运行b.php。报错信息如下:

Warning: include(a) [function.include]: failed to open stream: No such file or directory in C:/xampp/htdocs/webapp/codesnipe/b.php on line 3

Warning: include() [function.include]: Failed opening 'a' for inclusion (include_path='.;C:/xampp/php/pear/') in C:/xampp/htdocs/webapp/codesnipe/b.php on line 3
/webapp/codesnipe/b.php
I am B

       可以对照上面,总结出报错信息的格式如下:
       语句或函数:failed to open stream:具体的提示信息,在文件的第几行

include和require的区别

      当遇到文件找不到的情况是,它们的处理不同。include会发出警告,然后继续执行下去;require则报错,并停止当前脚本的执行。

      信息格式中给出的警告格式就是include发出的。两个警告之后就是b.php的输出内容。如果将include换成require,则信息如下:

Warning: require(a) [function.require]: failed to open stream: No such file or directory in C:/xampp/htdocs/webapp/codesnipe/b.php on line 3

Fatal error: require() [function.require]: Failed opening required 'a' (include_path='.;C:/xampp/php/pear/') in C:/xampp/htdocs/webapp/codesnipe/b.php on line 3


      可见,它们信息的格式相同,而且require第二个信息变成了Fatal error。错误信息后也没有b.php执行后的输出,因为require报错之后就是的脚本的执行退出了。

文件包含的死循环

     最简单的死循环形式是两个文件的形式:a.php和b.php。如果a.php中包含文件b.php,而b.php中包含文件a.php,则无论执行a.php还是b.php,都会进入死循环。

     只要将第一个例子中的a加上包含b.php的语句,就可以得到一个很好的例子。死循环的原因还容易理解,这里不做解释。可能有人觉得项目开发时不会犯这种低级的错误。项目小的时候可能正确,但是一个大型的软件多人合作,如何保证没有潜在的执行环呢?再说,从维护的角度来说,这种设计也不合理。

include_once和require_once

     include_once和require_once在第一次执行时,其结果和include和require一样。其后再遇到文件包含关键词(同组的关键词)则会跳过不执行。

     假设有三个文件:indexa.php、indexb.php和indexc.php。其源代码如下:
indexa.php
<?php
include_once 'indexb.php';

echo $_SERVER['PHP_SELF'],'<br>';
echo 'I am A<br>';
?>

indexb.php
<?php
include_once 'indexa.php';
include_once 'indexc.php';

echo $_SERVER['PHP_SELF'],'<br>';
echo 'I am B<br>';
?>

indexc.php
<?php
include_once 'indexb.php';
include_once 'indexa.php';

echo $_SERVER['PHP_SELF'],'<br>';
echo 'I am C<br>';
?>

输出如下:

/webapp/codesnipe/indexa.php
I am C
/webapp/codesnipe/indexa.php
I am B
/webapp/codesnipe/indexa.php
I am A

     执行文件indexa.php,遇到包含语句包含indexb.php,所以读入indexb.php的源代码。indexb.php的源代码的第一句就包含文件indexa.php。由于indexa.php的内容已经存在,故该包含语句无效;第二局包含indexc.php。indexc.php的源代码的第一句包含文件indexb.php。基于indexb.php的内容已经存在,故该语句同样无效;同样的第二个语句也无效。最后程序执行,结果就如上面所示。
     将任一个include_once语句换成require_once,程序执行一样。因而在同组内,处理错误处理不同,并没有什么差别。
     为了更形象地理解,我们可以设想php解析器会给每个执行文件创建一个源代码来源记录表。记录表记录了源代码被包含进来的文件完整路径。include_once和require_once会在每次包含新文件时,检查新文件是否已经在记录表中。如果已经存在,文件内容不会被包含进来;否则文件路径被记录入记录表,并将其内容包含进来。

与前一组的区别

     这里不需要多说,include和require并不检查记录表,这就是差别。通过这种方式,我们很容易解决潜在的死循环的问题,提高程序的可靠性。

目录结构导致的错误

     文件包含除了受到文件包含关系影响,第二个重要因素就是文件包含的目录结构。前面的源代码中我都包含了变量$_SERVER['PHP_SELF']的值。从输出中可以看出变量的值是当前正在运行的脚本的名称,就是直接运行请求的php文件而不是包含进来的文件。这个事实说明,被包含文件的源代码将被执行在直接执行文件的环境中,不如最终要的文件查找路径。
     一个简单的例子。项目包含一个文件夹include,下面是两个文件indexb.php和indexc.php。和文件夹include同目录的是文件indexa.php。源代码如下:
indexa.php
<?php
include_once 'include/indexb.php';

echo $_SERVER['PHP_SELF'],'<br>';
echo 'I am A<br>';
?>

indexb.php
<?php
include_once './indexc.php';

echo $_SERVER['PHP_SELF'],'<br>';
echo 'I am B<br>';
?>

indexc.php
<?php

echo $_SERVER['PHP_SELF'],'<br>';
echo 'I am C<br>';
?>

输出如下:

Warning: include_once(./indexc.php) [function.include-once]: failed to open stream: No such file or directory in C:/xampp/htdocs/webapp/codesnipe/include/indexb.php on line 3

Warning: include_once() [function.include]: Failed opening './indexc.php' for inclusion (include_path='.;C:/xampp/php/pear/') in C:/xampp/htdocs/webapp/codesnipe/include/indexb.php on line 3
/webapp/codesnipe/indexa.php
I am B
/webapp/codesnipe/indexa.php
I am A


上面的输出可以看出,indexb.php的源代码中的"./indexc.php"中的"."指向的是indexa.php所在的目录而不是include目录本身,因而导致文件查找错误。如果把indexb.php中的"./indexc.php"改成"indexc.php",那么脚本将正常运行。这是因为php本身会有一个默认的文件查找路径值。但是从可维护性角度来说,这种侥幸的正确时不可行的。

一个解决方案

     由于存在上面的问题,所以项目设计时会有一个系统的配置文件,在配置文件中设置系统的路径值,通过这种方式来获得要包含文件的绝对路径,从而避免上面的问题。具体的说明可见下一篇文章。