当前位置: 首页 > news >正文

PHP的include和require

文章目录

  • 环境
  • require和include
  • require VS include
  • require(include) VS require_once(include_once)
  • 路径问题
    • 当前工作目录对相对路径的影响
    • 题外话
    • 总结
    • 其它
  • 参考

环境

  • Windows 11 专业版
  • XAMPP v3.3.0
    • PHP 8.2.12
    • Apache 2.4.58
  • VSCode 1.99.3

require和include

requireinclude 有点类似于C语言的 include 和Java的 import

比如,创建文件 test0504_util1.php 如下:

<?php
function add($a, $b) {return $a + $b;
}const PI = 3.14; // 注意全部用大写字母,且不加 `$` 前缀。$name = '张三';echo "我是util1" . PHP_EOL;
?>

该PHP文件里:

  • 定义了 add() 函数
  • 定义了常量 PI
  • 定义了变量 $name
  • 有一段全局的代码

在同级目录里,创建文件 test0504_1.php 如下:

<?php
require 'test0504_util1.php';$x = add(1, 2);
echo "x = $x" . PHP_EOL;echo "PI = " . PI . PHP_EOL;echo "name = $name" . PHP_EOL;
?>

在该PHP文件里引入了 test0504_util1.php 文件。因此,就可以使用其中的函数、常量、变量。

运行结果如下:

我是util1
x = 3
PI = 3.14
name = 张三

注意,被引入文件的全局代码,也会被运行(本例中输出了 我是util1 )。

上面的例子里,引用文件使用了被引用文件的函数、常量、变量。反过来,被引用文件也可以使用引用文件的函数、常量、变量。

比如,可以把被引用文件当作一个模板,引用文件在引用模板前,先设置好数据。

一个典型的例子是页面的header。

创建文件 test0504_header1.php 如下:

<head><title><?phpecho "当前页面:$title";?></title>
</head>

该文件是将要被引用的模板文件,其中有一个变量 $titile

创建文件 test0504_page1.php 如下:

<html><?php$title = 'page1';require 'test0504_header1.php';?><body><p>这是页面1</p></body>
</html>

类似的,创建文件 test0504_page2.php 如下:

<html><?php$title = 'page2';require 'test0504_header1.php';?><body><p>这是页面2</p></body>
</html>

在这两个文件中,先设置好 $title 变量的值,然后引用模板文件。

访问页面1:

在这里插入图片描述

访问页面2:

在这里插入图片描述

可见,二者的header是相同的模板,只是title的值不同。

require VS include

requireinclude 的主要区别在于,对于被引用文件不存在时的行为:

  • require :如果文件不存在,PHP 会抛出 E_COMPILE_ERROR ,并立即终止脚本:
Fatal error: Uncaught Error: Failed opening required 'xxx.php' (include_path='C:\xampp\php\PEAR') in C:\xampp\htdocs\test0504_2.php:2
  • include :如果文件不存在,PHP 会抛出 E_WARNING ,但脚本会继续执行后续代码:
Warning: include(): Failed opening 'xxx.php' for inclusion (include_path='C:\xampp\php\PEAR') in C:\xampp\htdocs\test0504_2.php on line 3

使用场景:

  • require :用于加载程序运行必需的依赖(如数据库连接、核心函数库)。也就是“必须要有,没有不行”的文件
  • include :用于加载可选的模板文件或用户自定义内容。也就是“可有可无,没有也影响不大”的文件

require(include) VS require_once(include_once)

二者的区别在于,当重复引入同一个文件时:

  • require :会引入多次
  • require_once :只会引入一次

该使用 require 还是 require_once ,取决于具体的应用场景。比如,同一个页面上确实需要多次显示同一个东西(比如一个 div 元素),那就在不同的位置使用require 来多次引入同一文件。如果是要引入类、变量、常量等,那显然应该使用 require_once ,以避免重复定义,冲突报错。

includeinclude_once 也同理。

路径问题

当前工作目录对相对路径的影响

在上面的例子里,引入的是同一目录里的文件,所以没有指定目录:

require 'xxx.php';

这里使用的是相对路径(相对于当前脚本文件)。

使用相对路径的问题是,如果“当前工作目录”发生了变化,则相对路径所代表的绝对路径也改变了。

现有目录结构如下:

htdocs|----dir1|  |----1.php|----dir2|----test0504_3.php

1.php 里,定义了变量 $aaa

<?php$aaa = 123;
?>

test0504_3.php 里引入 1.php

<?phprequire '../dir1/1.php';echo $aaa . PHP_EOL;
?>

在VSCode里运行,是没有问题的,在浏览器里访问 http://localhost/dir2/test0504_3.php ,也没有问题。

修改文件如下:

<?phpecho "__DIR__ : " . __DIR__ . PHP_EOL;echo "get_include_path() : " . get_include_path() . PHP_EOL;echo "getcwd() : " . getcwd() . PHP_EOL;echo "realpath('../dir1/1.php') : " . realpath('../dir1/1.php') . PHP_EOL; echo "stream_resolve_include_path('../dir1/1.php') : " . stream_resolve_include_path('../dir1/1.php') . PHP_EOL;require '../dir1/1.php';echo $aaa . PHP_EOL;
?>

其中:

  • __DIR__ :脚本文件所在的绝对路径
  • get_include_path() :PHP查找文件的路径
  • getcwd() :当前工作目录
  • realpath() :获取目标路径的绝对路径(比如目标路径可能会含有 ..
  • stream_resolve_include_path() :在 include_path 指定的目录列表中查找目标文件,并返回第一个匹配的绝对路径。若文件不存在,则返回 false

在VSCode里运行,输出结果是:

__DIR__ : C:\xampp\htdocs\dir2
get_include_path() : C:\xampp\php\PEAR
getcwd() : C:\xampp\htdocs\dir2
realpath('../dir1/1.php') : C:\xampp\htdocs\dir1\1.php
stream_resolve_include_path('../dir1/1.php') : C:\xampp\htdocs\dir1\1.php
123

如果在命令行里,在 dir2 目录下运行:

PS C:\xampp\htdocs\dir2> php .\test0504_3.php
Xdebug: [Step Debug] Time-out connecting to debugging client, waited: 200 ms. Tried: localhost:9003 (through xdebug.client_host/xdebug.client_port).
__DIR__ : C:\xampp\htdocs\dir2
get_include_path() : C:\xampp\php\PEAR
getcwd() : C:\xampp\htdocs\dir2
realpath('../dir1/1.php') : C:\xampp\htdocs\dir1\1.php
stream_resolve_include_path('../dir1/1.php') : C:\xampp\htdocs\dir1\1.php
123

可见和在VSCode运行是一样的。

注:输出结果里有个连接超时,这是因为 php.ini 里配置了Xdebug。在命令行运行php,会导致Xdebug连接debug client的错误(localhost:9003)。不过并不影响代码运行。加上 -n 选项,表示不使用 php.ini 配置,就不会提示这个信息了。

运行时加上 -n 选项(不使用 php.ini 配置文件):

PS C:\xampp\htdocs\dir2> php -n .\test0504_3.php
__DIR__ : C:\xampp\htdocs\dir2
get_include_path() : .;C:\php\pear
getcwd() : C:\xampp\htdocs\dir2
realpath('../dir1/1.php') : C:\xampp\htdocs\dir1\1.php
stream_resolve_include_path('../dir1/1.php') : C:\xampp\htdocs\dir1\1.php
123

可见,加不加 -n ,影响的是 include_path

如果在 dir2 以外的目录里运行,就会出错。比如在 C:\ 目录运行:

PS C:\> php -n C:\xampp\htdocs\dir2\test0504_3.php
__DIR__ : C:\xampp\htdocs\dir2
get_include_path() : .;C:\php\pear
getcwd() : C:\
realpath('../dir1/1.php') :
stream_resolve_include_path('../dir1/1.php') :Warning: require(../dir1/1.php): Failed to open stream: No such file or directory in C:\xampp\htdocs\dir2\test0504_3.php on line 8Fatal error: Uncaught Error: Failed opening required '../dir1/1.php' (include_path='.;C:\php\pear') in C:\xampp\htdocs\dir2\test0504_3.php:8
Stack trace:
#0 {main}thrown in C:\xampp\htdocs\dir2\test0504_3.php on line 8

加不加 -n 选项都会报错,因为二者的 include_path 虽然不同,但都没找到所需文件。

可见,当前工作目录是 C:\ 时,require语句出错了,因为找不到 ../dir1/1.php 文件。

题外话

如果不是在 dir2 目录里,而是在其父目录 htdocs 目录里创建 test0504_2.php 文件,并修改相对路径,如下:

<?phpecho "__DIR__ : " . __DIR__ . PHP_EOL;echo "get_include_path() : " . get_include_path() . PHP_EOL;echo "getcwd() : " . getcwd() . PHP_EOL;echo "realpath('dir1/1.php') : " . realpath('dir1/1.php') . PHP_EOL; echo "stream_resolve_include_path('dir1/1.php') : " . stream_resolve_include_path('dir1/1.php') . PHP_EOL;require 'dir1/1.php';echo $aaa . PHP_EOL;
?>

则不会报错:

PS C:\> php -n C:\xampp\htdocs\test0504_2.php
C:\
123

明明当前工作目录还是 C:\ ,使用相对路径 dir1/1.php 为什么不报错呢?

这会不会与XAMPP或者 php.ini 有关呢?但我尝试停止了Apache,而且加上 -n 选项,甚至把 php.ini 里Xdebug相关的配置都删掉了,但仍然是这样的行为。

我问了DeepSeek,它也答不出个所以然来,大概意思是说:

  • 对于非 ../ 开头的相对路径(如 dir1/1.php ),某些PHP版本会"智能"地尝试从脚本所在目录解析
  • 对于 ../ 开头的路径,PHP出于安全考虑会更严格地仅基于当前工作目录解析

总结

不管怎么样,使用相对路径总是不靠谱的,还是使用绝对路径吧。

// 在任何文件中都这样写
require __DIR__ . '/dir1/1.php';  // 当前脚本文件在 htdocs 目录下
require __DIR__ . '/../dir1/1.php'; // 当前脚本文件在 htdocs/dir2 目录下

这里使用了魔术常量 __DIR__ ,表示脚本文件的绝对路径。

通过使用 __DIR__ 再加上目标文件的相对路径,就得到了目标文件的绝对路径,这样做可以确保:

  • 不受工作目录影响
  • 不受 include_path 设置影响
  • 不受-n参数影响

其它

Windows和Linux的路径分隔符是不同的:

  • Windows: \
  • Linux: /

在上面的代码中,路径分隔符用的都是 / 。在Windows下运行也是没问题的。所以,不管什么操作系统,统一都用 / 好了。

注:如果需要,可以使用 DIRECTORY_SEPARATOR ,以适配不同操作系统,比如 'dir' . DIRECTORY_SEPARATOR . 'file.php' 。不过一般没必要这么做,直接用 / 就行。

参考

  • https://www.php.net/docs.php

相关文章:

  • 基于STM32的心电图监测系统设计
  • 【前端】【面试】在 Vue-React 的迁移重构工作中,从状态管理角度来看,Vuex 迁移到 Redux 最大的挑战是什么,你是怎么应对的?
  • 力扣面试150题--相同的树
  • 嵌入式按键原理、中断过程与中断程序设计(键盘扫描程序)
  • 【CISCO】什么是静态路由(Static Route)?ip route 192.0.1.0 255.255.255.0 200.0.0.1
  • 高等数学同步测试卷 同济7版 试卷部分 上 做题记录 第四章 不定积分同步测试卷 B卷
  • LeetCode刷题链表
  • Spring AI 实战:第四章、Spring AI多模态之看图说话
  • Go语言实现Kafka消息队列
  • 【图书管理系统】环境介绍、设计数据库和表、配置文件、引入依赖
  • JVM——JVM是怎么实现invokedynamic的?
  • Go语言--语法基础4--基本数据类型--类型转换
  • 4个纯CSS自定义的简单而优雅的滚动条样式
  • 图片压缩与尺寸调整的便捷工具推荐
  • Qt输入控件(QInput Widgets)详解:从基础到实战
  • 【leetcode】队列 + 宽搜,树形结构层序遍历的基础与变化
  • 前端开发,文件在镜像服务器上不存在问题:Downloading binary from...Cannot download...
  • JAVA设计模式——(十)抽象工厂模式(Abstract Factory Pattern)
  • PostgreSQL 的 REINDEX 命令
  • LeetCode 2071 你可以安排的最多任务数目 题解(附带自己的错误做题思路 过了25/49)
  • 巴菲特股东大会4.5万字问答实录:股神60年穿越牛熊的最新心得和人生思考
  • 环球马术冠军赛圆满落幕,是马术盛宴更是中国马产业强大引擎
  • 上千游客深夜滞留张家界大喊退票?当地通报情况并致歉
  • “五一”假期第四天,全社会跨区域人员流动量预计超2.7亿人次
  • 金正恩视察重要坦克厂并强调更迭陆军装备
  • 洪纬读《制造三文鱼》丨毒素缠身的水生鸡