- PHP 教程
- PHP 首页
- PHP 简介
- PHP 安装
- PHP 历史
- PHP 特性
- PHP 语法
- PHP - Hello World
- PHP 注释
- PHP 变量
- PHP echo/print
- PHP var_dump
- PHP $ 和 $$ 变量
- PHP 常量
- PHP 魔术常量
- PHP 数据类型
- PHP 类型转换
- PHP 类型强制转换
- PHP 字符串
- PHP 布尔值
- PHP 整数
- PHP 文件与I/O
- PHP 数学函数
- PHP Heredoc 和 Nowdoc
- PHP 复合类型
- PHP 文件包含
- PHP 日期与时间
- PHP 标量类型声明
- PHP 返回类型声明
- PHP 运算符
- PHP 运算符
- PHP 算术运算符
- PHP 比较运算符
- PHP 逻辑运算符
- PHP 赋值运算符
- PHP 字符串运算符
- PHP 数组运算符
- PHP 条件运算符
- PHP 展开运算符
- PHP 空值合并运算符
- PHP 宇宙飞船运算符
- PHP 控制语句
- PHP 决策
- PHP if…else 语句
- PHP switch 语句
- PHP 循环类型
- PHP for 循环
- PHP foreach 循环
- PHP while 循环
- PHP do…while 循环
- PHP break 语句
- PHP continue 语句
- PHP 函数
- PHP 函数
- PHP 函数参数
- PHP 按值传递
- PHP 按引用传递
- PHP 默认参数
- PHP 具名参数
- PHP 可变参数
- PHP 返回值
- PHP 传递函数
- PHP 递归函数
- PHP 类型提示
- PHP 变量作用域
- PHP 严格类型
- PHP 匿名函数
- PHP 箭头函数
- PHP 可变函数
- PHP 局部变量
- PHP 全局变量
- PHP 超全局变量
- PHP 超全局变量
- PHP $GLOBALS
- PHP $_SERVER
- PHP $_REQUEST
- PHP $_POST
- PHP $_GET
- PHP $_FILES
- PHP $_ENV
- PHP $_COOKIE
- PHP $_SESSION
- PHP 文件处理
- PHP 文件处理
- PHP 打开文件
- PHP 读取文件
- PHP 写入文件
- PHP 文件是否存在
- PHP 下载文件
- PHP 复制文件
- PHP 追加文件
- PHP 删除文件
- PHP 处理CSV文件
- PHP 文件权限
- PHP 创建目录
- PHP 列出文件
- 面向对象PHP
- PHP 面向对象编程
- PHP 类和对象
- PHP 构造函数和析构函数
- PHP 访问修饰符
- PHP 继承
- PHP 类常量
- PHP 抽象类
- PHP 接口
- PHP 特性
- PHP 静态方法
- PHP 静态属性
- PHP 命名空间
- PHP 对象迭代
- PHP 封装
- PHP final 关键字
- PHP 重载
- PHP 克隆对象
- PHP 匿名类
- PHP Web 开发
- PHP Web 概念
- PHP 表单处理
- PHP 表单验证
- PHP 表单邮件/URL
- PHP 完整表单
- PHP 文件包含
- PHP GET 和 POST
- PHP 文件上传
- PHP Cookie
- PHP Session
- PHP Session 选项
- PHP 发送邮件
- PHP 输入过滤
- PHP POST-Redirect-GET (PRG)
- PHP 闪存消息
- PHP 登录示例
- PHP 登录示例
- PHP Facebook 登录
- PHP Paypal 集成
- PHP MySQL 登录
- PHP 高级
- PHP MySQL
- PHP.INI 文件配置
- PHP 数组解构
- PHP 编码规范
- PHP 正则表达式
- PHP 错误处理
- PHP try…catch
- PHP 调试Bug
- PHP 针对C开发者
- PHP 针对Perl开发者
- PHP 框架
- PHP Core PHP 与框架
- PHP 设计模式
- PHP 过滤器
- PHP JSON
- PHP 异常
- PHP 特殊类型
- PHP 哈希
- PHP 加密
- PHP is_null() 函数
- PHP 系统调用
- PHP HTTP 认证
- PHP 交换变量
- PHP Closure::call()
- PHP 过滤后的 unserialize()
- PHP IntlChar
- PHP CSPRNG
- PHP 期望值
- PHP use 语句
- PHP 整数除法
- PHP 已弃用的特性
- PHP 已移除的扩展和SAPI
- PHP PEAR
- PHP CSRF
- PHP FastCGI 进程
- PHP PDO 扩展
- PHP 内置函数
PHP 快速指南
PHP 简介
PHP 最初是一个小型开源项目,随着越来越多的人发现它的实用性,它逐渐发展壮大。Rasmus Lerdorf 于 1994 年发布了第一个 PHP 版本。最初,PHP 的缩写是“Personal Home Page”,但现在代表递归缩写“PHP: Hypertext Preprocessor”。
Lerdorf 从 1993 年开始开发 PHP,他编写了几个用 C 语言编写的通用网关接口 (CGI) 程序,用于维护他的个人主页。后来,他扩展了这些程序以与 Web 表单配合使用并与数据库通信。这个 PHP 实现被称为“Personal Home Page/Forms Interpreter”或 PHP/FI。
如今,PHP 是世界上最流行的用于构建 Web 应用程序的服务器端编程语言。多年来,它经历了多次修订和版本更新。
PHP 版本
PHP 由 Rasmus Lerdorf 于 1994 年开发,最初是一组用 C 语言编写的简单的 CGI 二进制文件。他将这套脚本称为“Personal Home Page Tools”。可以将其视为 PHP 1.0 版本。
1996 年 4 月,Rasmus 推出了 PHP/FI。其中包括对 DBM、mSQL 和 Postgres95 数据库、Cookie、用户定义函数支持的内置支持。PHP/FI 被赋予了2.0 版本状态。
PHP: Hypertext Preprocessor – PHP 3.0 版本是在 Zeev Suraski 和 Andi Gutmans 重写 PHP 解析器并采用当前首字母缩写词时出现的。它为多个数据库、协议和 API 提供了成熟的接口,以及面向对象编程支持和一致的语言语法。
PHP 4.0 于 2000 年 5 月发布,由 Zend Engine 提供支持。它支持许多 Web 服务器、HTTP 会话、输出缓冲、安全的用户输入处理方法以及一些新的语言结构。
PHP 5.0 于 2004 年 7 月发布。它主要由其核心 Zend Engine 2.0 驱动,具有新的对象模型和数十个其他新功能。PHP 的开发团队包括数十名开发人员以及从事 PEAR、PECL 和文档等 PHP 相关和支持项目的人员。
PHP 7.0 于 2015 年 12 月发布。最初被称为 PHP 新一代 (phpng)。开发人员重新设计了 Zend Engine,称为 Zend Engine 3。PHP 7 的一些重要功能包括其改进的性能、减少的内存使用量、返回和标量类型声明以及匿名类。
PHP 8.0 于 2020 年 11 月 26 日发布。这是一个主要版本,与之前的版本相比,有很多显著改进。一个突出的功能是即时编译 (JIT),它可以提供显著的性能改进。最新版本的 PHP 是 8.2.8,于 2023 年 7 月 4 日发布。
PHP 应用领域
PHP 是 Web 上最广泛使用的语言之一。以下是 PHP 的一些应用领域:
PHP 是一种服务器端脚本语言,嵌入在 HTML 中。它用于管理动态内容、数据库、会话跟踪,甚至构建整个电子商务网站。虽然它特别适合 Web 开发,但您也可以构建桌面独立应用程序,因为 PHP 也具有命令行界面。您可以使用 PHP-GTK 扩展在 PHP 中构建 GUI 应用程序。
PHP 广泛用于构建 Web 应用程序,但您并不局限于仅输出 HTML。PHP 的输出能力包括丰富的文件类型,例如图像或 PDF 文件,数据加密和发送电子邮件。您还可以轻松输出任何文本,例如 JSON 或 XML。
PHP 是一种跨平台语言,能够在所有主要的操作系统平台上运行,并与大多数 Web 服务器程序(如 Apache、IIS、lighttpd 和 nginx)一起运行。PHP 还支持使用 LDAP、IMAP、SNMP、NNTP、POP3、HTTP、COM 等协议的其他服务。
以下是 PHP 的一些更重要的特性:
PHP 执行系统函数。它可以创建、打开、读取、写入和关闭文件。
PHP 可以处理表单。它可以从文件收集数据,将数据保存到文件,通过电子邮件发送数据,将数据返回给用户。
您可以通过 PHP 添加、删除、修改数据库中的元素。
访问 Cookie 变量并设置 Cookie。
使用 PHP,您可以限制用户访问网站的某些页面。
它可以加密数据。
PHP 提供大量可重用的类和库,可在“PEAR”和“Composer”上获得。“PEAR”(PHP 扩展和应用程序存储库)是可重用 PHP 库或类的分发系统。“Composer”是 PHP 中的依赖管理工具。
PHP 安装
您可以借助互联网上免费提供的任何在线 PHP 编译器来学习 PHP 的编程基础知识。这将有助于在不将其安装到您的计算机上的情况下熟悉 PHP 的功能。之后,在您的本地机器上安装完整的 PHP 环境。
Tutorialpoint 提供的一个在线 PHP 编译器是“开发者代码练习场”。访问 https://tutorialspoint.com/codingground.htm,输入 PHP 代码并执行。
然而,要学习 PHP 的高级特性,特别是与 Web 概念相关的特性,例如服务器变量、使用后端数据库等,您需要在本地机器上安装 PHP 环境。
为了开发和运行 PHP 网页,您需要在计算机系统上安装三个重要组件。
Web 服务器 − PHP 几乎可以与所有 Web 服务器软件一起工作,包括 Microsoft 的 Internet Information Server (IIS)、NGINX 或 Lighttpd 等。最常用的 Web 服务器软件是免费的 Apache 服务器。在此免费下载 Apache − https://httpd.apache.org/download.cgi
数据库 − PHP 几乎可以与所有数据库软件一起工作,包括 Oracle 和 Sybase,但最常用的是免费的 MySQL 数据库。在此免费下载 MySQL − https://www.mysqlserver.cn/downloads/
PHP 解析器 − 为了处理 PHP 脚本指令,必须安装一个解析器来生成可以发送到 Web 浏览器的 HTML 输出。
虽然可以分别安装这三个组件并正确配置安装,但这对于初学者来说是一个稍微复杂的过程。相反,使用包含预编译的 Apache、MySQL 和 PHP 二进制文件的任何一体化打包发行版比较方便。
XAMPP 安装
有许多预编译的软件包,既有开源的也有专有的发行版。来自 Apache Friends 的 XAMPP (https://www.apachefriends.org/) 是最流行的 PHP 启用 Web 服务器软件包之一。本教程将使用 XAMPP。
XAMPP 是一个易于安装的 Apache 发行版,包含 Apache、MariaDB、PHP 和 Perl。首字母缩写中的字母 X 表示它是一个跨平台软件,可在 Windows、Linux 和 OS X 上使用。请注意,XAMPP 包含 MariaDB,它是 MySQL 的一个分支,其功能没有任何区别。
要下载适合您操作系统的相应安装程序,请访问 https://www.apachefriends.org/download.html,然后下载以下其中一个 −
Windows − https://sourceforge.net/projects/
在 Windows 上使用安装程序是一个完全基于向导的安装。您只需要提供管理员权限和安装目录的位置(默认为“c:\xampp”)。
要在 Linux 上安装 XAMPP,请执行以下步骤 −
步骤 1 − 更改安装程序的权限 −
chmod 755 xampp-linux-*-installer.run
运行安装程序 −
sudo ./xampp-linux-*-installer.run
XAMPP 现在安装在“/opt/lamp”目录下。
步骤 2 − 要启动 XAMPP,只需调用此命令 −
sudo /opt/lampp/lampp start
您现在应该在屏幕上看到类似以下内容 −
Starting XAMPP ... LAMPP: Starting Apache... LAMPP: Starting MySQL... LAMPP started. Ready. Apache and MySQL are running.
您还可以使用图形工具轻松管理服务器。您可以使用以下命令启动此工具 −
cd /opt/lampp sudo ./manager-linux.run (or manager-linux-x64.run)
步骤 3 − 要停止 XAMPP,只需调用此命令 −
sudo /opt/lampp/lampp stop
您现在应该在屏幕上看到类似以下内容 −
Stopping XAMPP ... LAMPP: Stopping Apache... LAMPP: Stopping MySQL... LAMPP stopped.
此外,请注意,有一个图形工具可以轻松启动/停止服务器。您可以使用以下命令启动此工具 −
cd /opt/lampp sudo ./manager-linux.run (or manager-linux-x64.run)
如果您使用的是 OS X,请按照以下步骤操作 −
要开始安装,请打开 DMG 镜像,然后双击该镜像以启动安装过程。
要启动 XAMPP,只需打开 XAMPP 控制面板并启动 Apache、MySQL 和 ProFTPD。XAMPP 控制面板的名称是“manager-osx”。
要停止 XAMPP,只需打开 XAMPP 控制面板并停止服务器。XAMPP 控制面板的名称是“manager-osx”。
XAMPP 控制面板是一个 GUI 工具,可以轻松启动和停止 Apache 服务器和 MySQL。
启动 Apache 模块后,按“Admin”按钮。XAMPP 主页显示如下所示 −
PHP 解析器安装
在继续之前,务必确保您的机器上已正确设置环境,以便使用 PHP 开发 Web 程序。
在浏览器的地址栏中输入以下地址。
http://127.0.0.1/info.php
如果显示的页面显示与 PHP 安装相关的信息,则表示您已正确安装 PHP 和 Web 服务器。否则,您必须按照给定的步骤在计算机上安装 PHP。
本节将指导您在以下四个平台上安装和配置 PHP −
Apache 配置
如果您使用 Apache 作为 Web 服务器,则本节将指导您编辑 Apache 配置文件。
请在此处查看 − Apache 服务器中的 PHP 配置
PHP.INI 文件配置
PHP 配置文件 php.ini 是影响 PHP 功能的最终也是最直接的方法。
请在此处查看 − PHP.INI 文件配置
Windows IIS 配置
要配置 Windows 计算机上的 IIS,您可以参考 IIS 参考手册(随 IIS 提供)。
现在,您已经在本地机器上拥有了一个完整的 PHP 开发环境。
PHP 历史
PHP 最初是一个小型开源项目,随着越来越多的人发现它的实用性,它逐渐发展壮大。Rasmus Lerdorf 在 1994 年发布了第一个版本的 PHP。当时,PHP 代表 Personal Home Page(个人主页),因为他用它来维护自己的个人主页。后来,他添加了数据库支持,并将其称为“Personal Home Page/Forms Interpreter”(个人主页/表单解释器)或 PHP/FI,可用于构建简单的动态 Web 应用程序。
Zeev Suraski 和 Andi Gutmans 在 1997 年重写了解析器,并构成了PHP 3的基础。该语言的名称也更改为递归首字母缩写 PHP:Hypertext Preprocessor(超文本预处理器)。他们也是 Zend Engine 的作者,Zend Engine 是 PHP 的编译器和运行时环境。Zend Engine 驱动的PHP 4于 2000 年 5 月发布。
PHP 5于 2004 年发布,其中包含许多新特性,例如 OOP 支持、PHP 数据对象 (PDO) 和许多性能增强。
PHP 7是 2015 年开发的一个新的主要 PHP 版本。它包含新的语言特性,最值得注意的是,引入了函数的返回类型声明,补充了现有的参数类型声明,并支持参数和返回类型声明中的标量类型(整数、浮点数、字符串和布尔值)。
PHP 8 的新特性
PHP 8 是最新的主要版本,于 2020 年 11 月发布。一些新的特性和显著变化包括
即时 (JIT) 编译
PHP 8 的 JIT 编译器比常见的 Web 开发用例对数学类型操作提供了显著的性能改进。JIT 编译器为将来将某些代码从 C 移动到 PHP 提供了潜力。
“match”表达式
新引入的“match”表达式比 switch 语句更简洁。因为 match 是一个表达式,所以它的结果可以赋值给变量或从函数返回。
PHP 8 – 类型更改和添加
PHP 8 引入了联合类型、新的静态返回类型和新的混合类型。PHP 8 还提供了属性(类似于其他编程语言中的“注释”),有助于向 PHP 类添加元数据。
此外,PHP 标准库也进行了许多更改和添加。PHP 8.2.9 是最新可用的稳定版本。
PHP 发布历史中的重要里程碑总结在下表中 −
版本 | 描述 |
---|---|
版本 1.0 |
正式称为“Personal Home Page Tools (PHP Tools)”。这是第一次使用“PHP”这个名称。 |
版本 2.0 |
正式称为“PHP/FI 2.0”。这是第一个实际上可以称为 PHP 的版本,它是一种独立的语言,具有许多延续至今的特性。 |
版本 3.0 |
开发从一个人转向多人。 Zeev Suraski 和 Andi Gutmans 重写了这个版本的底层。 |
版本 4.0 |
添加了更高级的两阶段解析/执行标签解析系统,称为 Zend 引擎。 |
版本 5.0 |
Zend Engine II,具有新的对象模型。 |
版本 5.1 |
在重新设计的 PHP 引擎中引入编译器变量,从而提高了性能。 添加了 PHP 数据对象 (PDO) 作为访问数据库的一致接口。 |
版本 6.x |
已放弃的 PHP 版本,该版本计划包含原生 Unicode 支持。 |
版本 7.0 |
|
版本 7.3 |
灵活的 Heredoc 和 Nowdoc 语法 |
版本 8.0 |
|
PHP 特性
PHP(超文本预处理器)是一种开源服务器端脚本语言,主要用于 Web 开发。PHP 可以嵌入到 HTML 代码中。
PHP 主要用于服务器端脚本,它在 Web 服务器上运行脚本,然后将它们处理的 HTML 转发到客户端的 Web 浏览器。这使得程序员可以设计动态网页,这些网页可以管理会话、处理表单、与数据库通信以及执行在线应用程序所需的各种其他任务。
PHP 的特性
多年来,PHP 集成了许多特性。它不断升级,增加了新特性和代码修订。本章将重点介绍 PHP 的一些关键特性。
PHP 简单易学
与 C、Java 和 Perl 相比,PHP 的语法相对简单,开发人员很容易理解,特别是那些已经熟悉其他编程语言的开发人员。由于其丰富的预定义函数,可以快速开发 Web 应用程序。
PHP 是开源的
PHP 是一种免费且开源的语言,这意味着我们可以免费下载它,任何人都可以使用、修改和分发它。这促进了庞大而活跃的开发者社区的形成,他们通过论坛、教程和文档来支持和贡献其发展。
PHP 具有跨平台兼容性
包括 Windows、Linux、macOS 和 UNIX 在内的众多操作系统;以及 MongoDB、PostgreSQL、MySQL 等不同的数据库都与 PHP 兼容。
由于这种跨平台互操作性,基于 PHP 的应用程序可以在多个环境中运行,无需任何修改。
PHP 中的服务器端脚本
PHP 主要用于服务器端脚本编写,它在 Web 服务器上运行脚本,然后将其处理的 HTML 转发到客户端的 Web 浏览器。它帮助开发者处理表单提交和跨多个请求的用户会话管理。
PHP 支持与数据库轻松集成
PHP 为各种 DBMS 提供强大的数据库交互支持。它提供了许多内置函数来实现数据库连接。
PHP 还包含数据库抽象层,它集成应用程序和数据库之间的通信。这使得开发者可以轻松设计数据库驱动的 Web 应用程序。
PHP 提供广泛的库支持
PHP 为各种功能提供了广泛的库,例如图像处理、加密、PDF 生成、解析 XML 和 JSON、处理会话和 Cookie 等等。
PHP 中的安全功能
PHP 提供了大量用于数据加密的内置函数。开发者还可以利用第三方应用程序来增强安全性。
PHP 使用Sha1和MD5等安全算法来加密字符串。此外,诸如filter_var和strip_tags之类的函数也有助于为用户维护安全的环境。PHP 还支持 HTTPS 等安全通信协议。
PHP 中高效的内存和会话管理
PHP 由于其高效的内存管理和会话管理而成为一种可靠的语言。它避免了不必要的内存分配。
PHP 代码在其自身的内存空间中运行,这使得它比其他脚本语言更快,效率更高。在 PHP 中,数据库连接也非常快速。
PHP 拥有活跃的社区和支持
由于 PHP 是一个开源平台,它拥有一个充满活力的开发者社区,他们积极参与其开发、分享知识、提供支持并创建第三方工具和框架。
由于这个活跃的社区支持,PHP 保持最新状态,开发者可以轻松地从其他社区成员那里寻求帮助,以防他们在编写 PHP 代码时遇到任何错误或异常。
PHP 语法
PHP 的语法规则与 C 语言非常相似。PHP 是一种服务器端脚本语言。PHP 代码存储为扩展名为“.php”的文本文件。“.php”文件本质上是一个网页,其中包含一个或多个嵌入在 HTML 脚本中的 PHP 代码块。但是,它必须使用 HTTP 协议 URL 在浏览器中打开。换句话说,如果双击 PHP 文件图标,它将在本地使用文件协议打开。例如,如果在 Apache 服务器的文档根文件夹中打开“index.php”文件,它可能只会显示 PHP 代码的文本。但是,如果启动 Apache 服务器并打开 URLhttps://127.0.0.1/index.php,它将显示 Apache 主页。
“.php”文件可能包含 HTML、CSS 和 JavaScript 代码块以及 PHP 代码。因此,PHP 解析器必须区分 PHP 代码和其他元素。当“.php”文件在 Web 浏览器中打开时,HTML 引擎呈现 HTML/CSS/JavaScript 部分,并在遇到 PHP 标记中包含的语句后立即退出 HTML 块。PHP 解析器解释器处理此块并将响应返回到浏览器。
PHP 定义了两种使用标记将 PHP 代码从 HTML 中分离出来的方法:标准 PHP 标记和简短打开(SGML 风格)标记。
标准 PHP 标记
最普遍有效的 PHP 标记样式是:
<?php One or more PHP statements ?>
如果您使用此样式,您可以确信您的标记将始终被正确解释。
简短打开(SGML 风格)标记
简短或简短打开标记如下所示:
<?php One or more PHP statements ?>
简短标记正如预期的那样是简短的选择。您必须执行以下两件事之一才能使 PHP 识别这些标记:
在构建 PHP 时选择“--enable-short-tags”配置选项。
将 php.ini 文件中的“short_open_tag”设置设置为 on。
short_open_tag=on
必须禁用此选项才能使用 PHP 解析 XML,因为 XML 标记使用相同的语法。
ASP 风格的标记的使用:
<%...%>
和HTML 脚本标记:
<script language = "PHP">...</script>
已被弃用。
从 HTML 中转义
PHP 解析器忽略一对开闭标记之外的所有内容。因此,PHP 文件可以包含混合内容。这允许 PHP 嵌入到 HTML 文档中:
<p>This is a HTML statement</p> <?php echo This is a PHP statement.'; ?> <p>This is another HTML statement.</p>
下面显示了一个使用条件的稍微高级的转义示例:
<?php if ($expression == true): ?> This HTML statement will be rendered. <?php else: ?> Otherwise this HTML statement will be rendered. <?php endif; ?>
即使这些块在 PHP 开/闭标记之外,PHP 也会跳过条件不满足的块。
对于输出大量文本,退出 PHP 解析模式通常比通过 echo 或 print 发送所有文本更高效。
PHP 的基本语法
PHP 的基本语法与 C 和 C++ 的语法非常相似。
语句是用分号结尾的表达式
PHP 中的语句是任何后跟分号 (;) 的表达式。任何用 PHP 标记括起来的有效 PHP 语句序列都是一个有效的 PHP 程序。
这是一个典型的 PHP 语句,在本例中,它将一个字符字符串赋值给名为“$greeting”的变量:
$greeting = "Welcome to PHP!";
文本编辑器中的物理行在 PHP 代码中没有任何意义。一行中可能有多个以分号结尾的语句。另一方面,如果需要,PHP 语句可能会超过一行。
表达式是标记的组合
PHP 最小的构建块是不可分割的标记,例如数字 (3.14159)、字符串 ("two")、变量 ($two)、常量 (TRUE) 以及构成 PHP 本身语法的特殊单词,例如 "if"、"else"、"while"、"for" 等等。
大括号构成代码块
尽管语句不能像表达式那样组合,但是您可以始终将语句序列放在任何语句可以出现的地方,方法是用一对大括号将它们括起来。
这里,以下两个语句是等效的:
if (3 == 2 + 1) print("Good - I haven't totally lost my mind.
"); if (3 == 2 + 1) { print("Good - I haven't totally"); print("lost my mind.
"); }
PHP 区分大小写
PHP 是一种区分大小写的语言。各种 PHP 标识符(如变量、函数、类等)都区分大小写。因此,变量“$age”与“$Age”不同。类似地,名为“myfunction()”的函数与名为“MyFunction()”的另一个函数不同。
PHP - Hello World
按照惯例,学习者在学习新语言或框架时,会将“Hello World”程序作为他们的第一个程序。目的是验证要使用的软件是否已正确安装并按预期工作。要在 PHP 中运行“Hello World”程序,您应该在使用的操作系统上安装了 Apache 服务器以及 PHP 模块。
PHP 是一种服务器端编程语言。PHP 代码必须位于 Web 服务器的文档根目录中。Web 服务器文档根目录是系统上运行的 Web 服务器的根目录。此根目录下的文档可供连接到 Web 服务器的任何系统访问(前提是用户具有权限)。如果文件不在此根目录下,则无法通过 Web 服务器访问它。
在本教程中,我们使用 XAMPP 服务器软件来编写 PHP 代码。默认的文档根目录在 Windows 上通常是“C:\xampp\htdocs\”,在 Linux 上是“/opt/lamp/htdocs/”。但是,您可以通过修改 Apache 服务器的配置文件“httpd.conf”中的 DocumentRoot 设置来更改默认文档根目录。
在 Windows 操作系统上,从 XAMPP 控制面板启动 Apache 服务器。
浏览到“htdocs”目录。将以下脚本保存为其中的“hello.php”。
<?php echo "Hello World!"; ?>
在浏览器中打开一个新标签页,并将https://127.0.0.1/hello.php作为 URL 输入。您应该在浏览器窗口中看到“Hello World”消息。
PHP 脚本可能包含 HTML 和 PHP 代码的混合。
<!DOCTYPE html> <html> <body> <h1>My PHP Website</h1> <?php echo "Hello World!"; ?> </body> </html>
“Hello World”消息将呈现为纯文本。但是,您可以将 HTML 标记放在“Hello World”字符串中。浏览器将相应地解释这些标记。
在下面的代码中,“echo”语句呈现“Hello World”,使其成为<h1>标题,文本位于页面中心。
<?php echo "<h1 align='center'>Hello World!</h1>"; ?>
从命令提示符运行 PHP 脚本
您可以从命令提示符运行 PHP 脚本。假设您的“hello.php”文件包含以下内容。
<?php echo "Hello PHP!!!!!"; ?>
将 PHP 可执行文件的路径添加到操作系统的路径环境变量中。例如,在典型的 Windows XAMPP 安装中,PHP 可执行文件“php.exe”位于“c:\xampp\php”目录中。将此目录添加到 PATH 环境变量字符串中。
现在在命令提示符下运行此脚本:
C:\xampp\htdocs>php hello.php
您将获得以下输出:
Hello PHP!!!!!
PHP 注释
任何计算机程序(例如 PHP 程序)中的注释都是某种解释性文本,语言编译器/解释器会忽略它。其目的是帮助用户理解程序算法中使用的逻辑。
虽然在代码中放置注释不是必需的,但它是一种强烈推荐的做法。注释也用作程序文档。当需要调试和修改代码时,注释也很有用。
PHP 中有两种注释格式:
单行注释
多行注释
单行注释
它们通常用于与局部代码相关的简短解释或说明。PHP 使用两种表示法在程序中插入单行注释。
使用“#”的单行注释
PHP 代码中以“#”符号开头的行被视为单行注释。
<?php # Single line comment starting with # symbol echo 'Hello World'; ?>
使用“//”的单行注释
PHP 也支持 C 语言风格的单行注释,使用“//”符号。以双斜杠开头的行被视为注释。
<?php // Single line comment starting with // symbol echo 'Hello World'; ?>
以“#”或“//”符号开头的注释不需要关闭。这些符号的有效性持续到物理行结束。
换句话说,即使没有注释结束标记,PHP 解析器也会将下一行视为 PHP 语句,而不是注释。
多行注释
多行注释通常用于提供伪代码算法和必要的更详细的解释。
多行注释的风格与 C 语言相同。“/*”和“*/”符号之间嵌入的一行或多行被视为注释。
PHP 中多行注释的示例
这是一个多行注释的示例。
<?php /* This is a multiline comment example program to add two numbers Variables used - $x for first number, $y for second number */ $x=10; $y=20; print "Total = ". $x+$y; ?>
请注意,您甚至可以将单行放在“/* .. */”符号内。但是,如果程序中存在“/*”符号,则必须具有相应的注释结束标记“*/”。否则,将显示如下错误:
PHP Parse error: Unterminated comment starting line 3 in /home/cg/root/65ded9eeb52fc/main.php on line 3
PHP 变量
PHP 中的变量是命名的内存位置,用于保存属于某种数据类型的数据。
PHP 使用在变量名前添加美元符号 ($) 的约定。
PHP 中的变量名称区分大小写。
PHP 中的变量名遵循与其他标签相同的规则。有效的变量名以字母或下划线开头,后跟任意数量的字母、数字或下划线。
根据命名约定,“$name”、“$rate_of_int”、“$Age”、“$mark1”是 PHP 中有效变量名的示例。
无效变量名:“name”(没有 $ 前缀)、“$rate of int”(不允许使用空格)、“$Age#1”(无效字符 #)、“$11”(名称不以字母开头)。
变量使用“=”运算符赋值,变量位于左侧,要计算的表达式位于右侧。
无需指定变量的类型
PHP 是一种动态类型语言。无需指定变量的类型。相反,变量的类型由赋给它的值决定。变量的值是其最近一次赋值的值。
请看以下示例:
<?php $x = 10; echo "Data type of x: " . gettype($x) . "\n"; $x = 10.55; echo "Data type of x now: " . gettype($x) . ""; ?>
它将产生以下输出:
Data type of x: integer Data type of x now: double
变量的自动类型转换
PHP 在必要时可以很好地自动将类型从一种转换为另一种。在以下代码中,PHP 将字符串变量“y”转换为“int”以与另一个整数变量进行加法运算,并打印 30 作为结果。
请看以下示例:
<?php $x = 10; $y = "20"; echo "x + y is: ", $x+$y; ?>
它将产生以下输出:
x + y is: 30
按值赋值变量
在 PHP 中,变量总是按值赋值。如果将表达式赋给变量,则原始表达式的值将被复制到其中。如果表达式中任何变量的值在赋值后发生更改,则不会对赋值值产生任何影响。
<?php $x = 10; $y = 20; $z = $x+$y; echo "(before) z = ". $z . "\n"; $y=5; echo "(after) z = ". $z . ""; ?>
它将产生以下输出:
(before) z = 30 (after) z = 30
按引用方式给 PHP 变量赋值
您也可以使用按引用方式给 PHP 变量赋值。在这种情况下,新变量只是引用或成为原始变量的别名或指向原始变量。对新变量的更改会影响原始变量,反之亦然。
要按引用赋值,只需在被赋值变量(源变量)的开头添加一个与号 (&)。
请看以下示例:
<?php $x = 10; $y = &$x; $z = $x+$y; echo "x=". $x . " y=" . $y . " z = ". $z . "\n"; $y=20; $z = $x+$y; echo "x=". $x . " y=" . $y . " z = ". $z . ""; ?>
它将产生以下输出:
x=10 y=10 z = 20 x=20 y=20 z = 40
变量作用域
作用域可以定义为变量在其声明的程序中具有的可用范围。PHP 变量可以是四种作用域类型之一:
变量命名
变量命名的规则是:
变量名必须以字母或下划线字符开头。
变量名可以包含数字、字母、下划线,但不能使用+、-、%、(、) 、& 等字符。
变量没有大小限制。
PHP echo/print
在 PHP 中,echo 和print 语句都用于在浏览器或 PHP 控制台上呈现输出。两者都不是函数,而是语言结构。因此,两者都不应使用括号。
PHP 中的“echo”语句
echo 语句使用以下语法:
echo(string ...$expressions): void
echo 语句输出一个或多个表达式,不添加额外的换行符或空格。
示例
这是一个关于 echo 语句如何在 PHP 中工作的示例:
<?php $name = "Rajesh"; echo "Hello " . $name . " How are you?" ?>
它将产生以下输出:
Hello Rajesh How are you?
由于双引号字符串与 PHP 中的单引号字符串类似,因此以下语句产生相同的输出。
echo 'Hello ' . $name . ' How are you?';
示例
双引号字符串输出变量的值。因此,以下语句在打印输出之前插入“$name”变量的值。
<?php $name = "Rajesh"; echo "Hello $name How are you?"; ?>
它将产生以下输出:
Hello Rajesh How are you?
示例
但是,单引号字符串将按原样输出“$name”。
<?php $name = "Rajesh"; echo 'Hello $name How are you?'; ?>
它将产生以下输出:
Hello $name How are you?
传递给 echo 语句的字符串可以作为多个参数单独传递,也可以连接在一起作为单个参数传递。因此,以下两个语句都是有效的:
echo 'Hello ', 'how ', 'are ', 'you?', "\n"; echo 'Hello ' . 'how ' . 'are ' . 'you?' . "\n";
示例
请注意,如果未使用换行符,则两个连续的 echo 语句的输出将呈现于同一行。请看以下示例:
<?php echo "hello"; echo "world"; ?>
它将产生以下输出:
helloworld
PHP 中的“print”语句
print 语句类似于 echo,但它输出一个表达式。
print(string $expression): int
与 echo 一样,print 也是一种语言结构。其参数是一个表达式,但不放在括号中。
主要区别在于 PHP 中的 print 语句只接受一个参数,并且总是返回 1。
示例
请看以下示例:
<?php $name = "Rajesh"; print "Hello " . $name . " How are you?\n"; print "Hello $name How are you?"; ?>
它将产生以下输出:
Hello Rajesh How are you? Hello Rajesh How are you?
使用 Print/Echo 输出多行字符串
echo 和 print 语句都可以输出跨越多行的多行字符串。请看以下示例:
<?php print " Multi-line string can be output by echo as well as print statement in PHP "; ?>
它将产生以下输出:
Multi-line string can be output by echo as well as print statement in PHP
如果我们将print替换为echo,输出将保持不变。
PHP var_dump() 函数
PHP 中的内置函数之一是 var_dump() 函数。此函数显示结构化信息,例如作为此函数参数给出的一个或多个表达式的类型和值。
var_dump(mixed $value, mixed ...$values): void
此函数在输出中返回对象的全部公共、私有和受保护属性。关于数组和对象的转储信息正确缩进以显示递归结构。
对于内置的整数、浮点数和布尔变量,var_dump() 函数显示参数变量的类型和值。
示例 1
例如,这是一个整数变量:
<?php $x = 10; var_dump ($x); ?>
转储信息如下:
int(10)
示例 2
让我们看看它对浮点变量的行为:
<?php $x = 10.25; var_dump ($x); ?>
var_dump() 函数返回以下输出:
float(10.25)
示例 3
如果表达式是布尔值:
<?php $x = true; var_dump ($x); ?>
它将产生以下输出:
bool(true)
示例 4
对于字符串变量,var_dump() 函数还会返回字符串的长度。
<?php $x = "Hello World"; var_dump ($x); ?>
它将产生以下输出:
string(11) "Hello World"
这里我们可以使用`
` HTML 标签来显示预格式化的文本。``元素中的文本以等宽字体显示,并且文本保留空格和换行符。`”。<?php echo "<pre>"; $x = "Hello World"; var_dump ($x); echo "</pre>" ?>它将产生以下输出:
string(11) "Hello World"示例 5 - 使用 var_dump() 研究数组结构
var_dump() 函数可用于研究数组结构。在以下示例中,我们有一个数组,其中数组的一个元素是另一个数组。换句话说,我们有嵌套数组的情况。
<?php $x = array("Hello", false, 99.99, array(10, 20,30)); var_dump ($x); ?>它将产生以下输出:
array(4) { [0]=> string(5) "Hello" [1]=> bool(false) [2]=> float(99.99) [3]=> array(3) { [0]=> int(10) [1]=> int(20) [2]=> int(30) } }示例 6
由于"$x"在上一个示例中是索引数组,因此会转储从“0”开始的索引及其值。如果数组是关联数组,则会转储键值对信息。
<?php $x = array( "Hello", false, 99.99, array(1=>10, 2=>20,3=>30) ); var_dump($x); ?>在这里,您将获得以下输出:
array(4) { [0]=> string(5) "Hello" [1]=> bool(false) [2]=> float(99.99) [3]=> array(3) { [1]=> int(10) [2]=> int(20) [3]=> int(30) } }当使用 var_dump() 显示数组值时,无需使用结束标签“`
示例 7
var_dump() 函数还可以显示表示类的对象的属性。在以下示例中,我们声明了一个具有两个私有属性“x”和“y”的 Point 类。类构造函数使用传递给它的参数初始化对象“p”。
var_dump() 函数提供有关对象属性及其对应值的信息。
<?php class Point { private int $x; private int $y; public function __construct(int $x, int $y = 0) { $this->x = $x; $this->y = $y; } } $p = new Point(4, 5); var_dump($p) ?>它将产生以下输出:
object(Point)#1 (2) { ["x":"Point":private]=> int(4) ["y":"Point":private]=> int(5) }PHP 中还有一个类似的内置函数用于生成转储,名为get_defined_vars()。
var_dump(get_defined_vars());它会将所有已定义的变量转储到浏览器。
PHP $ 和 $$ 变量
我们知道 PHP 使用在变量名前添加“$”符号的约定。PHP 还允许通过在名称前添加两个美元符号($$)来声明动态变量。变量变量(或动态变量)可以动态设置和使用。
普通变量的声明如下:
$a = 'good';动态变量取普通变量的值,并将其视为变量的名称。在上面的示例中,“good”可以通过使用两个美元符号“$$”作为变量名:
$$a = 'morning';现在我们有两个变量:“$a”的内容为“good”,“$$a”的内容为“morning”。因此,以下 echo 语句将产生相同的输出:
echo "$a {$$a}"; echo "$a $good";两者产生相同的输出:
good morning示例 1
请看以下示例:
<?php $a = 'good'; $$a = 'morning'; echo "$a {$$a}\n"; echo "$a $good"; ?>它将产生以下输出:
good morning good morning示例 2
让我们看另一个例子:
<?php $x = "foo"; $$x = "bar"; echo "Value of x = " .$x . "\n"; echo 'Value of $$x = ' . $$x . "\n"; echo 'Value of foo = ' . $foo; ?>在这里,您将获得以下输出:
Value of x = foo Value of $$x = bar Value of foo = bar使用多个“$”符号
请注意,“$”符号的使用不限于两个。可以添加任意数量的美元符号。
假设有一个变量“$x”,其值为“a”。接下来,我们定义 $$x='as',那么“$$x”和“$a”将具有相同的值。同样,语句 $$$x='and' 有效地声明了一个“$as”变量,其值为'and'。
示例
这是一个完整的示例,它显示了多个“$”符号的使用。
<?php $php = "a"; $lang = "php"; $World = "lang"; $Hello = "World"; $a = "Hello"; echo '$a= ' . $a; echo "\n"; echo '$$a= ' . $$a; echo "\n"; echo '$$$a= ' . $$$a; echo "\n"; echo '$$$$a= ' . $$$$a; echo "\n"; echo '$$$$$a= ' . $$$$$a; ?>运行此代码时,将产生以下输出:
$a= Hello $$a= World $$$a= lang $$$$a= php $$$$$a= a将动态变量与数组一起使用
将动态变量与数组一起使用可能会导致某些模棱两可的情况。对于数组“a”,如果您编写 $$a[1],则解析器需要知道您是指“$a[1]”作为变量,还是想要“$$a”作为变量,然后从该变量获取[1]索引。
为了解决这种歧义,对于第一种情况,使用${$a[1]};对于第二种情况,使用${$a}[1]。
示例
请看以下示例:
<?php $vars = array("hw", "os", "lang"); $var_hw="Intel"; $var_lang="PHP"; $var_os="Linux"; foreach ($vars as $var) echo ${"var_$var"} . "\n"; print "$var_hw\n$var_os\n$var_lang"; ?>它将产生以下输出:
Intel Linux PHP Intel Linux PHP需要注意的是,此技术不能与 PHP 的超全局数组(PHP 中的几个预定义变量是“超全局”变量,这意味着它们在整个脚本的所有作用域中都可用)一起在函数或类方法中使用。“$this”是 PHP 中的一个特殊变量,不能动态引用。
PHP 常量
PHP 中的常量是简单值的名称或标识符。常量的值在 PHP 脚本执行期间不能更改。
默认情况下,PHP 常量区分大小写。
按照约定,常量标识符始终为大写。
常量名以字母或下划线开头,后跟任意数量的字母、数字或下划线。
无需在常量前写美元符号 ($) ,但是必须在变量前使用美元符号。
PHP 中有效和无效常量名的示例
以下是一些 PHP 中有效和无效常量名的示例:
// Valid constant names define("ONE", "first thing"); define("TWO2", "second thing"); define("THREE_3", "third thing"); define("__THREE__", "third value"); // Invalid constant names define("2TWO", "second thing");
PHP 中常量和变量的区别
常量不能通过简单的赋值来定义;它们只能使用 define() 函数来定义。
常量可以在任何地方定义和访问,而无需考虑变量作用域规则。
一旦设置了常量,就不能重新定义或取消定义它们。
定义命名常量
PHP 库中的 define() 函数用于在运行时定义命名常量。
define(string $const_name, mixed $value, bool $case = false): bool
参数
const_name - 常量的名称。
value - 常量的值。它可以是标量值(int、float、string、bool 或 null),也可以接受数组值。
case - 如果设置为 true,则常量将被定义为不区分大小写。默认行为区分大小写,即 CONSTANT 和 Constant 代表不同的值。
define() 函数在成功时返回“true”,失败时返回“false”。
示例 1
以下示例演示了 define() 函数的工作方式:
<?php define("CONSTANT", "Hello world."); echo CONSTANT; // echo Constant; ?>
第一个 echo 语句输出 CONSTANT 的值。你将得到以下输出:
Hello world.
但是,当你取消第二个 echo 语句的注释时,它将显示以下错误:
Fatal error: Uncaught Error: Undefined constant "Constant" in hello.php: on line 5
如果将 case 参数设置为 False,PHP 不会区分大小写常量。
示例 2
你也可以使用数组作为常量的值。来看下面的例子:
<?php define( $name="LANGS", $value=array('PHP', 'Java', 'Python') ); var_dump(LANGS); ?>
它将产生以下输出:
array(3) { [0]=> string(3) "PHP" [1]=> string(4) "Java" [2]=> string(6) "Python" }
使用 constant() 函数
echo 语句输出已定义常量的值。你也可以使用 constant() 函数。它返回按名称指示的常量的值。
constant(string $name): mixed
如果你需要检索常量的值,但不知道它的名称,则 constant() 函数很有用。例如,它存储在变量中或由函数返回。
<?php define("MINSIZE", 50); echo MINSIZE; echo PHP_EOL; echo constant("MINSIZE"); // same thing as the previous line ?>
它将产生以下输出:
50 50
使用 defined() 函数
PHP 库提供了一个 defined() 函数,用于检查是否存在给定的命名常量。来看下面的例子:
<?php define('MAX', 100); if (defined('MAX')) { echo MAX; } ?>
它将产生以下输出:
100
PHP 还具有一个名为“get_defined_constants()”的函数,它返回所有已定义常量及其值的关联数组。
PHP 魔术常量
PHP 中的魔术常量是预定义的常量。它们可用于运行它们的任何脚本,并且它们的值取决于使用它们的位置。所有这些“魔术”常量都在编译时解析,这与在运行时解析的常规常量不同。
PHP 中有九个魔术常量。这些特殊常量不区分大小写。
__LINE__
它返回文件的当前行号。以下示例显示了如何使用此魔术常量。
<?php $x="Hello World"; echo "$x. The current Line number is " . __LINE__ . "."; ?>
它将产生以下输出:
Hello World. The current Line number is 5.
__FILE__
此魔术常量返回文件的完整路径和文件名。如果在 include 内部使用,则返回包含文件的名称。来看下面的示例:
<?php $x="Hello World"; echo "$x. Current PHP script name is " . __FILE__ . "."; ?>
它将产生以下输出:
Hello World. Current PHP script name is C:\xampp\htdocs\hello.php.
__DIR__
此魔术常量返回文件的目录。如果在 include 内部使用,则返回包含文件的目录。这等效于“dirname(__FILE__)”。此目录名称不包含尾部斜杠,除非它是根目录。请参见以下示例:
<?php $x="Hello World"; echo "$x. Directory of the Current PHP script name is " . __DIR__ . "."; ?>
它将在浏览器上显示以下输出:
Hello World. Directory of the Current PHP script name is C:\xampp\htdocs.
__FUNCTION__
此魔术常量返回使用该常量的函数名,或者对于匿名函数返回 {closure}。以下示例显示了它的工作原理:
<?php function hello(){ $x="Hello World"; echo "$x. The function name is ". __FUNCTION__ . ""; } hello(); ?>
它将产生以下输出:
Hello World. The function name is hello
如果此魔术常量在函数外部使用,则将输出为空。
__CLASS__
此常量返回类的名称。类名包含其声明的命名空间。请参见以下示例:
<?php class myclass { public function __construct() { echo "Inside the constructor of ". __CLASS__ . PHP_EOL; } function getClassName(){ echo "from an instance method of " . __CLASS__ . ""; } } $obj = new myclass; $obj->getClassName(); ?>
它将产生以下输出:
Inside the constructor of myclass from an instance method of myclass
__METHOD__
__METHOD__ 常量返回类方法名。以下示例显示了它的工作原理:
<?php class myclass { public function __construct() { echo "Calling " . __METHOD__ . " of " . __CLASS__ ."<br>"; } function mymethod(){ echo "Calling " . __METHOD__ . " of " . __CLASS__ .""; } } $obj = new myclass; $obj->mymethod(); ?>
它将产生以下输出:
Calling myclass::__construct of myclass Calling myclass::mymethod of myclass
__TRAIT__
它返回 trait 名称。trait 名称包含其声明的命名空间。在 PHP 中,trait 是代码重用的机制。trait 类似于类,但仅用于以细粒度和一致的方式分组功能。无法单独实例化 trait。
来看下面的示例:
<?php trait mytrait { public function hello() { echo "Hello World from " . __TRAIT__ .""; } } class myclass { use mytrait; } $obj = new myclass(); $obj->hello(); ?>
它将产生以下输出:
Hello World from mytrait
__NAMESPACE__
此常量返回当前命名空间的名称。在 PHP 中,命名空间允许我们在不同的上下文中使用相同名称的类/函数/常量,而不会产生任何冲突,从而封装这些项。命名空间是根据类/函数的相关性对它们进行逻辑分组。
以下示例显示了如何使用此魔术常量:
<?php namespace myspace; class myclass { public function __construct() { echo "Name of the class: " . __CLASS__ . " in " . __NAMESPACE__ . ""; } } $class_name = __NAMESPACE__ . '\myclass'; $a = new $class_name; ?>
它将产生以下输出:
Name of the class: myspace\myclass in myspace
ClassName::class
与其他魔术常量不同,此魔术常量不以双下划线(__)开头和结尾。它返回完全限定的类名。
以下示例显示了如何使用此魔术常量:
<?php namespace myspace; class myclass { public function __construct() { echo "Name of the class: " . myclass::class ; } } use myspace; $a = new myclass; ?>
它将产生以下输出:
Name of the class: myspace\myclass
PHP – 数据类型
术语“数据类型”指的是将数据分类到不同的类别中。PHP 总共有八种数据类型,我们用它们来构建我们的变量:
整数 - 没有小数点的整数,例如 4195。
双精度浮点数 - 浮点数,例如 3.14159 或 49.1。
布尔值 - 只有两个可能的值,真或假。
NULL - 只具有一个值的特殊类型:NULL。
字符串 - 字符序列,例如 'PHP supports string operations.'。
数组 - 其他值的命名和索引集合。
对象 - 程序员定义类的实例,可以打包其他类型的变量和特定于类的函数。
资源 - 保持对 PHP 外部资源(例如数据库连接)的引用的特殊变量。
前五个是简单类型,接下来的两个(数组和对象)是复合类型。复合类型可以打包任意类型和任意数量的其他值,而简单类型则不能。
在本章中,让我们详细讨论这些 PHP 的内置数据类型。
PHP 中的整数数据类型
没有小数点的整数(例如 4195)在 PHP 中属于int 类型。整数数据类型是最简单的类型。它们对应于简单的整数,包括正数和负数。
int 是集合 Z = {..., -2, -1, 0, 1, 2, ...} 中的一个数。
int 可以用十进制(基数 10)、十六进制(基数 16)、八进制(基数 8)或二进制(基数 2)表示法表示。
要使用八进制表示法,数字前面要加上“0o”或“0O”。要使用十六进制表示法,数字前面要加上“0x”。要使用二进制表示法,数字前面要加上“0b”。
下面是一些示例:
十进制整数 - 201, 4195, -15
八进制整数 - 0010, 0O12, -0O21
十六进制整数 - 0x10, -0x100
二进制整数 - 0b10101, -0b100
整数可以赋值给变量,也可以用于表达式,如下所示:
$int_var = 12345; $another_int = -12345 + 12345;
PHP 中的双精度浮点数数据类型
双精度浮点数变量表示浮点数(也称为“浮点数”、“双精度浮点数”或“实数”),它们是带有小数部分的数。小数部分位于整数部分之后,由小数点符号 (.) 分隔。
注意 - 双精度浮点数变量可以是正数、负数或零。
$var1 = 1.55 $var2 =-123.0
科学浮点记数法
PHP 还允许使用科学记数法来表示小数点后有更多位数的浮点数。“E”或“e”符号用于分隔整数和小数部分。
− 1.2e3, 2.33e-4, 7E-10, 1.0E5
默认情况下,双精度浮点数以所需的最小小数位数打印。来看下面的示例:
<?php $many = 2.2888800; $many_2 = 2.2111200; $few = $many + $many_2; print("$many + $many_2 = $few"); ?>
它产生以下输出:
2.28888 + 2.21112 = 4.5
PHP 中的布尔数据类型
bool 类型只有两个值;它可以是真或假。bool 类型用于表达真值。
$bool1 = true; $bool2 = false;
你也可以使用整数“1”和“0”来表示真和假布尔值:
$bool3 = 1; $bool4 = 0;
通常,返回 bool 值的运算符的结果将传递给控制结构,例如if、while 或do-while。例如,
if (TRUE) print("This will always print."); else print("This will never print.");
将其他数据类型解释为布尔值
以下是一组规则,你可以使用它们将其他数据类型解释为布尔值:
如果该值为数字,则仅当该值等于零时才为假,否则该值为真。
如果该值为字符串,则如果字符串为空(没有字符)或为字符串“0”,则为假,否则为真。
NULL 类型的值始终为假。
如果该值为数组,则如果它不包含其他值,则为假;否则为真。对于对象,包含值意味着具有已赋值的成员变量。
有效的资源为真(尽管某些在成功时返回资源的函数在不成功时将返回 FALSE)。
注意 - 不要使用双精度浮点数作为布尔值。
以下每个变量在其用作布尔上下文时都具有嵌入在其名称中的真值。
$true_num = 3 + 0.14159; $true_str = "Tried and true" $true_array[49] = "An array element"; $false_array = array(); $false_null = NULL; $false_num = 999 - 999; $false_str = "";
PHP 中的字符串数据类型
字符串是字符序列,例如 'PHP supports string operations.'。
在 PHP 中,字符与字节相同。这意味着 PHP 只支持 256 个字符集,因此不提供原生 Unicode 支持。
PHP 支持单引号和双引号字符串的形成。以下两种表示在 PHP 中都是有效的:
$string_1 = "This is a string in double quotes"; $string_2 = 'This is a somewhat longer, singly quoted string';
以下是一些更多字符串类型的示例:
$string_39 = "This string has thirty-nine characters"; $string_0 = ""; // a string with zero characters
单引号字符串几乎按字面意思处理,而双引号字符串则用其值替换变量,并对某些字符序列进行特殊解释。
<?php $variable = "name"; $literally = 'My $variable will not print!'; print($literally); print "\n"; $literally = "My $variable will print!"; print($literally); ?>
运行此代码时,将产生以下输出:
My $variable will not print! My name will print
字符串长度没有人工限制。在可用内存的范围内,你应该能够创建任意长的字符串。
由双引号分隔的字符串(如“this”)将通过 PHP 以以下两种方式预处理:
以反斜杠 (\) 开头的某些字符序列将被替换为特殊字符。
变量名(以$开头)将被其值的字符串表示形式替换。
转义序列替换为:
\n 将被换行符替换
\r 将被回车符替换
\t 将被制表符替换
\$ 将被美元符号本身 ($) 替换
\" 将被单个双引号 (") 替换
\\ 将被单个反斜杠 (\) 替换
PHP 还具有Heredoc 和Nowdoc 字符串数据类型的表示形式。
字符串数据类型的 Heredoc 表示形式
你可以使用 heredoc 将多行赋给单个字符串变量:
<?php $channel =<<<_XML_ <channel> <title>What's For Dinner</title> <link>http://menu.example.com/ </link> <description>Choose what to eat tonight.</description> </channel> _XML_; echo <<< END This uses the "here document" syntax to output multiple lines with variable interpolation. Note that the here document terminator must appear on a line with just a semicolon. no extra whitespace! END; print $channel; ?>
运行此代码时,它将产生以下输出:
This uses the "here document" syntax to output multiple lines with variable interpolation. Note that the here document terminator must appear on a line with just a semicolon. no extra whitespace! <channel> <title>What's For Dinner</title> <link>http://menu.example.com/ </link> <description>Choose what to eat tonight.</description> </channel>
字符串数据类型的 Nowdoc 表示形式
Heredoc 标识符的所有规则也适用于 nowdoc 标识符。nowdoc 的指定方式与heredoc 相同,但在 nowdoc 内没有解析。你可以使用 nowdoc 结构嵌入大型文本块,而无需使用任何转义字符。
nowdoc 使用与 heredoc 相同的 <<< 序列标识,但标识符用单引号括起来,例如 <<<'EOT'。Nowdoc 应用于单引号字符串的方式与 heredoc 应用于双引号字符串的方式相同。
请看以下示例:
<?php echo <<<'IDENTIFIER' As the cat cleared its throat with a refined "Meow", the squirrel chirped excitedly about its latest discovery of a hidden stash of peanut treasure! IDENTIFIER; ?>
运行代码并检查其输出:
As the cat cleared its throat with a refined "Meow", the squirrel chirped excitedly about its latest discovery of a hidden stash of peanut treasure!
PHP 中的 Null 数据类型
在 PHP 中,null 表示只具有一个值:NULL 的特殊类型。未定义和 unset() 变量将解析为值“null”。
程序员通常使用PHP中的Null数据类型来初始化变量或指示值缺失。
要为变量赋予NULL值,只需这样赋值:
$my_var = NULL;
特殊常量NULL按照惯例大写,但实际上它**不区分大小写**;你也可以这样写:
$my_var = null;
已赋值为NULL的变量具有以下属性:
在布尔上下文中计算结果为FALSE。
使用IsSet()函数测试时返回FALSE。
**注意** - PHP中变量的数据类型是在运行时根据赋值给它们的值确定的。
PHP中的数组数据类型
PHP中的数组是有序映射,一个键与一个或多个值关联。PHP数组使用array()函数定义,或者使用简写法,其中数据放在方括号中。
让我们看看以下**关联数组**的示例:
使用array()函数
$arr = array( "foo" => "bar", "bar" => "foo", );
使用简写法
$arr = [ "foo" => "bar", "bar" => "foo", ];
PHP中的数组也可以使用“键值对”语法定义。这被称为**索引数组**。
$arr = array("foo", "bar", "hello", "world");
在**多维数组**中,主数组中的每个元素也可以是一个数组。并且,子数组中的每个元素可以是一个数组,以此类推。多维数组中的值使用多个索引访问。
**注意** - 在PHP中,复合数据类型用于存储数据集合,包括数组和对象。
PHP中的对象数据类型
对象类型是程序员定义类的实例,它可以打包其他类型的值和特定于类的函数。
要创建一个新对象,请使用**new语句**来实例化一个类:
class foo { function bar() { echo "Hello World."; } } $obj = new foo; $obj->bar();
PHP中的资源数据类型
资源是持有对PHP外部资源(例如文件流或数据库连接)的引用的特殊变量。
这是一个**文件资源**的示例:
$fp = fopen("foo.txt", "w");
属于上述任何类型的数据都存储在变量中。但是,由于PHP是一种动态类型语言,因此无需指定变量的类型,因为这将在运行时确定。
示例:gettype()函数
gettype()函数有助于找出存储在变量中的数据类型:
<?php $x = 10; echo gettype($x) . "\n"; $y = 10.55; echo gettype($y) . "\n"; $z = [1,2,3,4,5]; echo gettype($z); ?>
运行此代码时,将产生以下输出:
integer double array
PHP 类型转换
术语“类型转换”指的是将一种类型的数据转换为另一种类型。由于PHP是一种弱类型语言,因此解析器在执行某些操作时会将某些数据类型强制转换为其他类型。例如,如果字符串包含数字,则如果它是加法运算中涉及的操作数之一,则将其转换为整数。
隐式类型转换
这是一个强制或隐式类型转换的示例:
<?php $a = 10; $b = '20'; $c = $a+$b; echo "c = " . $c; ?>
在这种情况下,$b是一个字符串变量,转换为整数以启用加法。它将产生以下**输出**:
c = 30
让我们再举一个例子。在这里,整数变量$a被转换为字符串,以便与字符串变量连接。
<?php $a = 10; $b = '20'; $c = $a.$b; echo "c = " . $c; ?>
它将产生以下输出:
c = 1020
除了这种强制类型转换之外,还有其他方法可以显式地将一种类型的数据转换为另一种类型。您可以为此目的使用PHP的类型转换运算符或类型转换函数。
类型转换运算符
要将一种类型的表达式转换为另一种类型,需要在表达式之前将后者的数据类型放在括号中。
$var = (type)expr;
PHP中的一些类型转换运算符是:
(int) 或 (integer) 转换为整数
(bool) 或 (boolean) 转换为布尔值
(float) 或 (double) 或 (real) 转换为浮点数
(string) 转换为字符串
(array) 转换为数组
(object) 转换为对象
转换为整数
您可以轻松地将浮点值转换为整数。让我们看看下面的**示例**:
<?php $a = 9.99; $b = (int)$a; var_dump($b); ?>
它将产生以下输出:
int(9)
请注意,浮点值不会四舍五入到最接近的整数;而是只返回整数部分。
字符串到整数转换
(int)运算符也把字符串转换为整数。如果字符串只包含数字,则转换很简单。
<?php $a = "99"; $b = (int)$a; var_dump($b); ?>
在这里,您将获得以下输出:
int(99)
即使字符串包含浮点数,(int)运算符也只返回整数部分。
现在让我们来看另一个例子来理解一个特殊情况。**如果字符串是字母数字的,则使用(int)进行转换的方式不同**。
如果字符串以数字开头,后跟非数字字符,则只考虑初始数字。
如果字符串以非数字字符开头,而数字在中间,则转换运算符返回“0”。
来看下面的示例:
<?php $a = "10 Rs."; $b = (int)$a; var_dump($b); $a = "$100"; $b = (int)$a; var_dump($b); ?>
它将产生以下输出:
int(10) int(0)
转换为浮点类型
您可以使用(float)或(double)转换运算符将变量或表达式显式转换为浮点数。
<?php $a = 100; $b = (double)$a; var_dump($b); ?>
它将产生以下输出:
float(100)
包含任何有效数字表示的字符串都可以使用转换运算符转换为浮点类型。
<?php $a = "100"; $b = (double)$a; var_dump($b); $a = "9.99"; $b = (float)$a; var_dump($b); ?>
在这里,您将获得以下输出:
float(100) float(9.99)
即使字符串包含浮点数的科学计数法,它也会转换为浮点数。让我们看看下面的例子:
<?php $a = "1.23E01"; $b = (double)$a; var_dump($b); $a = "5.5E-5"; $b = (float)$a; var_dump($b); ?>
它将产生以下输出:
float(12.3) float(5.5E-5)
浮点数后面的所有非数字字符都将被忽略。类似地,如果字符串以任何非数字字符开头,则字符串将转换为“0”。请参见以下**示例**:
<?php $a = "295.95 only"; $b = (double)$a; var_dump($b); $a = "$2.50"; $b = (float)$a; var_dump($b); ?>
它将产生以下输出:
float(295.95) float(0)
转换为字符串类型
通过使用转换运算符,任何计算结果为浮点数或整数的表达式都可以转换为字符串类型。下面给出一些例子:
<?php $a = 100; $b = (string)$a; var_dump($b); $x = 55.50; $y = (string)$x; var_dump($y); ?>
您将获得以下**输出**:
string(3) "100" string(4) "55.5"
转换为布尔类型
任何非零数字(整数或浮点数)都将使用(bool)运算符转换为true。计算结果为“0”的表达式返回false。字符串总是转换为true。
来看下面的示例:
<?php $a = 100; $b = (bool)$a; $x = 0; $y = (bool)$x; $m = "Hello"; $n = (bool)$m; var_dump($b); var_dump($y); var_dump($n); ?>
它将产生以下输出:
bool(true) bool(false) bool(true)
类型转换函数
PHP包含以下用于执行类型转换的内置函数:
intval()
floatval()
strval()
让我们详细讨论这些内置函数。
intval()函数
此函数获取变量的整数值。
intval(mixed $value, int $base = 10): int
**$base**参数默认为10,这意味着该值将转换为十进制数。
如果值是浮点数,则intval()函数返回一个整数,丢弃小数部分。
数字的字符串表示返回相应的整数,如果存在小数部分,则丢弃小数部分。
如果该值是带有有效八进制数的字符串,并且基数为8,则intval()函数返回相应的八进制数。
**当基数为“0”时**,值的转换将基于字符前缀进行。
如果值以0X或0x开头,则返回十六进制数。
如果值以0B或0b开头,则返回二进制数。
如果值以0开头,则函数返回八进制数。
对于true布尔值,intval()函数返回1;对于false布尔值,返回0。
示例
以下示例显示了intval()函数的工作方式:
<?php echo intval(42). PHP_EOL; echo intval(4.2). PHP_EOL; echo intval('42') . PHP_EOL; echo intval(042) . PHP_EOL; # 0ctal number echo intval('042', 0) . PHP_EOL; # 0ctal number echo intval('42', 8) . PHP_EOL; # octal echo intval(0x1A) . PHP_EOL; # Hexadecimal echo intval('0x1A', 16) . PHP_EOL; # Hexadecimal echo intval('0x1A', 0) . PHP_EOL; # Hexadecimal echo intval(false) . PHP_EOL; echo intval(true) . PHP_EOL; ?>
它将产生以下输出:
42 4 42 34 34 34 26 26 26 0 1
floatval()函数
floatval()函数获取表达式的浮点值。
floatval(mixed $value): float
该值可以是任何标量变量。包含非数字字符的字符串返回“0”。包含数字表示或以数字表示开头的子字符串的字符串返回相应的数字。以下**示例**显示了floatval()函数的工作方式:
<?php echo floatval(42). PHP_EOL; echo floatval(4.2). PHP_EOL; echo floatval('42') . PHP_EOL; echo floatval('99.90 Rs') . PHP_EOL; echo floatval('$100.50') . PHP_EOL; echo floatval('ABC123!@#') . PHP_EOL; echo (true) . PHP_EOL; ; echo (false) . PHP_EOL; ?>
它将产生以下输出:
42 4.2 42 99.9 0 0 1
**doubleval()**函数是floatval()函数的别名,因此返回类似的结果。
strval()函数
strval()函数获取变量的字符串值。此函数不对返回的值进行任何格式化。
strval(mixed $value): string
要转换为字符串的值可以是任何标量类型、null或实现__toString()方法的对象。让我们看看下面的**示例**:
<?php echo strval(42). PHP_EOL; echo strval(4.2). PHP_EOL; echo strval(4.2E5) . PHP_EOL; echo strval(NULL) . PHP_EOL; echo (true) . PHP_EOL; echo (false) . PHP_EOL; ?>
它将产生以下输出:
42 4.2 420000 1
以下**示例**定义了一个实现**__toString()方法**的类。
<?php class myclass { public function __toString() { return __CLASS__; } } echo strval(new myclass); ?>
在这里,您将获得以下输出:
myclass
PHP 类型强制转换
PHP被称为动态类型语言。PHP中变量的类型会动态变化。此功能在PHP中称为“类型转换”。
在C、C++和Java中,您需要在后续代码中使用变量之前声明变量及其类型。变量只能取与声明类型匹配的值。
PHP既不需要也不支持变量的显式类型声明。因此,PHP变量的类型由赋给它的值决定,而不是相反。此外,当变量被赋予不同类型的值时,它的类型也会改变。
示例 1
看看PHP中以下变量赋值。
<?php $var = "Hello"; echo "The variable \$var is of " . gettype($var) . " type" .PHP_EOL; $var = 10; echo "The variable \$var is of " . gettype($var) . " type" .PHP_EOL; $var = true; echo "The variable \$var is of " . gettype($var) . " type" .PHP_EOL; $var = [1,2,3,4]; echo "The variable \$var is of " . gettype($var) . " type" .PHP_EOL; ?>
它将产生以下输出:
The variable $var is of string type The variable $var is of integer type The variable $var is of boolean type The variable $var is of array type
您可以看到“$var”的类型根据赋给它的值动态变化。PHP的这个特性叫做“类型转换”。
示例 2
类型转换也发生在表达式计算过程中。在这个例子中,包含数字的字符串变量会自动转换为整数,以计算加法表达式。
<?php $var1=100; $var2="100"; $var3=$var1+$var2; var_dump($var3); ?>
这是它的**输出**:
int(200)
示例 3
如果字符串以数字开头,则在执行计算时,将忽略任何尾随的非数字字符。但是,PHP解析器会发出如下所示的通知:
<?php $var1=100; $var2="100 days"; $var3=$var1+$var2; var_dump($var3); ?>
您将获得以下**输出**:
int(200) PHP Warning: A non-numeric value encountered in /home/cg/root/53040/main.php on line 4
类型转换与类型转换
请注意,PHP中的“类型转换”与“类型转换”略有不同。
在类型转换中,PHP会在必要时自动将类型从一种转换为另一种。例如,如果将整数值赋给变量,则它将成为整数。
另一方面,当用户显式定义他们想要转换到的数据类型时,就会发生类型转换。
示例
类型转换强制变量用作某种类型。以下脚本显示了不同类型转换运算符的示例:
<?php $var1=100; $var2=(boolean)$var1; $var3=(string)$var1; $var4=(array)$var1; $var5=(object)$var1; var_dump($var2, $var3, $var4, $var5); ?>
它将产生以下输出:
bool(true) string(3) "100" array(1) { [0]=> int(100) } object(stdClass)#1 (1) { ["scalar"]=> int(100) }
示例
也可以通过将变量包含在双引号字符串中来将其转换为字符串:
<?php $var1=100.50; $var2=(string)$var1; $var3="$var1"; var_dump($var2, $var3); ?>
在这里,您将获得以下输出:
string(5) "100.5" string(5) "100.5"
PHP 字符串
字符串是一系列字符,例如“PHP支持字符串操作”。PHP中的字符串是字节数组和表示缓冲区长度的整数。在PHP中,字符与字节相同。这意味着PHP只支持256个字符集,因此不提供原生Unicode支持。
PHP支持单引号和双引号字符串的形成。'这是一个简单的字符串'和"这是一个简单的字符串"这两种表示方式都是有效的。PHP还具有字符串数据类型的Here文档和Nowdoc表示。
单引号字符串
用单引号(字符')括起来的一系列字符是字符串。
$str = 'this is a simple string';
示例
如果要包含文字单引号,请用反斜杠(\)转义它。
<?php $str = 'This is a \'simple\' string'; echo $str; ?>
它将为您提供以下**输出**:
This is a 'simple' string
示例
要指定文字反斜杠,请将其加倍(\\)。
<?php $str = 'The command C:\\*.* will delete all files.'; echo $str; ?>
这是它的**输出**:
The command C:\*.* will delete all files.
示例
诸如“\r”或“\n”之类的转义序列将被逐字对待,并且不会解释它们的特殊含义。如果变量出现在单引号字符串中,它们也不会被展开。
<?php $str = 'This will not expand: \n a newline'; echo $str . PHP_EOL; $x=100; $str = 'Value of x = $x'; echo $str; ?>
它将产生以下输出:
This will not expand: \n a newline Value of x = $x
双引号字符串
用双引号(" ")括起来的一系列字符是另一种字符串表示。
$str = "this is a simple string";
单引号字符串和双引号字符串是等效的,只是它们对转义序列的处理方式不同。PHP将解释某些用于特殊字符的转义序列。例如,“\r”和“\n”。
序列 | 含义 |
---|---|
\n | 换行符(LF或ASCII中的0x0A(10)) |
\r | 回车符(CR或ASCII中的0x0D(13)) |
\t | 水平制表符(HT或ASCII中的0x09(9)) |
\v | 垂直制表符(VT或ASCII中的0x0B(11)) |
\e | 转义符(ESC或ASCII中的0x1B(27)) |
\f | 换页符(FF或ASCII中的0x0C(12)) |
\\ | 反斜杠 |
\$ | 美元符号 |
\" | 双引号 |
如何在PHP中转义八进制和十六进制字符?
PHP支持将八进制数和十六进制数转义为其ASCII字符。例如,P的ASCII字符在十进制中为80。十进制80转换为八进制为120。类似地,十进制80转换为十六进制为50。
要转义八进制字符,在其前面加上“\”;要转义十六进制字符,在其前面加上“\x”。
<?php $str = "\120\110\120"; echo "PHP with Octal: ". $str; echo PHP_EOL; $str = "\x50\x48\x50"; echo "PHP with Hexadecimal: ". $str; ?>
检查输出 -
PHP with Octal: PHP PHP with Hexadecimal: PHP
与单引号字符串一样,转义任何其他字符都将导致反斜杠也被打印出来。双引号字符串最重要的特性是变量名将被展开。
示例
PHP 中的双引号字符串会展开变量名(PHP 变量以 $ 符号开头)。要在 PHP 字符串中实际表示“$”符号,请使用反斜杠“\”对其进行转义。
<?php $price = 200; echo "Price = \$ $price"; ?>
您将获得以下**输出**:
Price = $ 200
字符串连接运算符
要将两个字符串变量连接在一起,PHP 使用点 (.) 运算符 -
<?php $string1="Hello World"; $string2="1234"; echo $string1 . " " . $string2; ?>
在这里,您将获得以下输出:
Hello World 1234
在上面的例子中,我们使用了两次连接运算符。这是因为我们必须插入第三个字符串。在两个字符串变量之间,我们添加了一个包含单个字符(一个空格)的字符串,以分隔这两个变量。
PHP 的标准库包含许多用于字符串处理的函数。你可以在 PHP 的官方文档中找到它们(https://php.net/manual/en/ref.strings.php)。
strlen() 函数
strlen() 函数用于查找字符串的长度。
示例
让我们找到字符串“Hello world!”的长度 -
<?php echo strlen("Hello world!"); ?>
它将产生以下输出:
12
字符串的长度经常用于循环或其他函数中,当知道字符串何时结束很重要时(例如,在循环中,我们希望在字符串的最后一个字符之后停止循环)。
strpos() 函数
strpos() 函数用于在一个字符串中搜索字符串或字符。
如果在字符串中找到匹配项,此函数将返回第一个匹配项的位置。
如果找不到匹配项,它将返回 FALSE。
示例
让我们看看是否可以在我们的字符串中找到字符串“world” -
<?php echo strpos("Hello world!","world"); ?>
它将产生以下输出:
6
如你所见,字符串“world”在我们字符串中的位置是“6”。之所以是“6”而不是“7”,是因为字符串中的第一个位置是“0”而不是“1”。
PHP 布尔值
在 PHP 中,“bool”是内置标量数据类型之一。它用于表示真值,可以是 True 或 False。布尔文字使用 PHP 常量 True 或 False。这些常量不区分大小写,例如 true、TRUE 或 True 是同义词。
你可以按如下方式声明 bool 类型的变量 -
$a = true;
示例
逻辑运算符(<、>、==、!= 等)返回布尔值。
<?php $gender="Male"; var_dump ($gender=="Male"); ?>
它将产生以下输出:
bool(true)
控制语句中的布尔值
布尔值用于构建控制语句,例如if、while、for和foreach。这些语句的行为取决于布尔运算符返回的真/假值。
以下条件语句使用if关键字前面括号中表达式的布尔值 -
$mark=60; if ($mark>50) echo "pass"; else echo "fail";
将值转换为布尔值
使用 (bool) 类型转换运算符将值转换为 bool。当值在逻辑上下文中使用时,它将自动解释为 bool 类型的值。
非零数字被认为是 true,只有 0(+0.0 或 -0.0)是 false。非空字符串表示 true,空字符串 "" 等效于 false。类似地,空数组返回 false。
示例
看一下下面的例子 -
<?php $a = 10; echo "$a: "; var_dump((bool)$a); $a = 0; echo "$a: "; var_dump((bool)$a); $a = "Hello"; echo "$a: "; var_dump((bool)$a); $a = ""; echo "$a: "; var_dump((bool)$a); $a = array(); echo "$a: "; var_dump((bool)$a); ?>
它将产生以下输出:
10: bool(true) 0: bool(false) Hello: bool(true) : bool(false) Array: bool(false)
整数是 PHP 中的内置标量类型之一。字面值中没有小数点的整数在 PHP 中属于“int”类型。整数可以用十进制(基数 10)、十六进制(基数 16)、八进制(基数 8)或二进制(基数 2)表示法表示。
要使用八进制表示法,数字前要加“0o”或“0O”(PHP 8.1.0 及更早版本)。从 PHP 8.1.0 开始,以“0”为前缀且没有小数点的数字是八进制数。
要使用十六进制表示法,请在数字前加“0x”。要使用二进制表示法,请在数字前加“0b”。
示例
请看以下示例:
<?php $a = 1234; echo "1234 is an Integer in decimal notation: $a\n"; $b = 0123; echo "0o123 is an integer in Octal notation: $b\n"; $c = 0x1A; echo "0xaA is an integer in Hexadecimal notation: $c\n"; $d = 0b1111; echo "0b1111 is an integer in binary notation: $d\n"; ?>
它将产生以下输出:
1234 is an Integer in decimal notation: 1234 0o123 is an integer in Octal notation: 83 0xaA is an integer in Hexadecimal notation: 26 0b1111 is an integer in binary notation: 15
从 PHP 7.4.0 开始,整数字面值可以使用下划线 (_) 作为数字之间的分隔符,以提高字面值的易读性。这些下划线将被 PHP 的扫描器删除。
示例
请看以下示例:
<?php $a = 1_234_567; echo "1_234_567 is an Integer with _ as separator: $a\n"; ?>
它将产生以下输出:
1_234_567 is an Integer with _ as separator: 1234567
PHP 不支持无符号 int。int 的大小取决于平台。在 32 位系统上,最大值约为 20 亿。64 位平台的最大值通常约为 9E18。
可以使用常量 PHP_INT_SIZE确定int的大小,使用常量 PHP_INT_MAX确定最大值,使用常量 PHP_INT_MIN确定最小值。
如果整数恰好超过int类型的范围,或者任何运算结果都超过int类型的范围,它将被解释为浮点数。
示例
请看以下示例:
<?php $x = 1000000; $y = 50000000000000 * $x; var_dump($y); ?>
它将产生以下输出:
float(5.0E+19)
PHP 没有整数除法的运算符。因此,整数和浮点数之间的除法运算始终产生浮点数。要获得整数除法,可以使用内置函数intval()。
示例
请看以下示例:
<?php $x = 10; $y = 3.5; $z = $x/$y; var_dump ($z); $z = intdiv($x, $y); var_dump ($z); ?>
它将产生以下输出:
float(2.857142857142857) int(3)
PHP 整数
整数是 PHP 中的内置标量类型之一。字面值中没有小数点的整数在 PHP 中属于“int”类型。整数可以用十进制(基数 10)、十六进制(基数 16)、八进制(基数 8)或二进制(基数 2)表示法表示。
要使用八进制表示法,数字前要加“0o”或“0O”(PHP 8.1.0 及更早版本)。从 PHP 8.1.0 开始,以“0”为前缀且没有小数点的数字是八进制数。
要使用十六进制表示法,请在数字前加“0x”。要使用二进制表示法,请在数字前加“0b”。
示例
看一下下面的例子 -
<?php $a = 1234; echo "1234 is an Integer in decimal notation: $a\n"; $b = 0123; echo "0o123 is an integer in Octal notation: $b\n"; $c = 0x1A; echo "0xaA is an integer in Hexadecimal notation: $c\n"; $d = 0b1111; echo "0b1111 is an integer in binary notation: $d"; ?>
它将产生以下输出:
1234 is an Integer in decimal notation: 1234 0o123 is an integer in Octal notation: 83 0xaA is an integer in Hexadecimal notation: 26 0b1111 is an integer in binary notation: 15
从 PHP 7.4.0 开始,整数字面值可以使用下划线 (_) 作为数字之间的分隔符,以提高字面值的易读性。这些下划线将被 PHP 的扫描器删除。
示例
看一下下面的例子 -
<?php $a = 1_234_567; echo "1_234_567 is an Integer with _ as separator: $a"; ?>
它将产生以下输出:
1_234_567 is an Integer with _ as separator: 1234567
PHP 不支持无符号 int。int 的大小取决于平台。在 32 位系统上,最大值约为 20 亿。64 位平台的最大值通常约为 9E18。
可以使用常量 PHP_INT_SIZE确定int的大小,使用常量 PHP_INT_MAX确定最大值,使用常量 PHP_INT_MIN确定最小值。
如果整数恰好超过int类型的范围,或者任何运算结果都超过int类型的范围,它将被解释为浮点数。
示例
看一下下面的例子 -
<?php $x = 1000000; $y = 50000000000000 * $x; var_dump($y); ?>
它将产生以下输出:
float(5.0E+19)
PHP 没有整数除法的运算符。因此,整数和浮点数之间的除法运算始终产生浮点数。要获得整数除法,可以使用内置函数intval()。
示例
看一下下面的例子 -
<?php $x = 10; $y = 3.5; $z = $x/$y; var_dump ($z); $z = intdiv($x, $y); var_dump ($z); ?>
它将产生以下输出:
float(2.857142857142857) int(3)
PHP 文件与I/O
本章将解释以下与文件相关的函数 -
- 打开文件
- 读取文件
- 写入文件
- 关闭文件
打开和关闭文件
PHP 的fopen()函数用于打开文件。它需要两个参数,首先是文件名,然后是操作模式。
文件模式可以指定为表中的六个选项之一。
序号 | 模式和用途 |
---|---|
1 |
r 只读方式打开文件。 将文件指针置于文件开头。 |
2 |
r+ 以读写方式打开文件。 将文件指针置于文件开头。 |
3 |
w 只写方式打开文件。 将文件指针置于文件开头。 并将文件截断为零长度。如果文件不存在, 则尝试创建文件。 |
4 |
w+ 只读写方式打开文件。 将文件指针置于文件开头。 并将文件截断为零长度。如果文件不存在, 则尝试创建文件。 |
5 |
a 只写方式打开文件。 将文件指针置于文件末尾。 如果文件不存在,则尝试创建文件。 |
6 |
a+ 只读写方式打开文件。 将文件指针置于文件末尾。 如果文件不存在,则尝试创建文件。 |
如果尝试打开文件失败,则fopen返回false值,否则返回文件指针,该指针用于进一步读取或写入该文件。
对打开的文件进行更改后,务必使用fclose()函数关闭它。fclose()函数需要一个文件指针作为参数,然后在关闭成功时返回true,失败时返回false。
读取文件
使用fopen()函数打开文件后,可以使用名为fread()的函数读取它。此函数需要两个参数。这些参数必须是文件指针和以字节表示的文件长度。
可以使用filesize()函数查找文件长度,该函数以文件名作为参数,并返回以字节表示的文件大小。
因此,以下是使用 PHP 读取文件所需的步骤。
使用fopen()函数打开文件。
使用filesize()函数获取文件长度。
使用fread()函数读取文件内容。
使用fclose()函数关闭文件。
示例
以下示例将文本文件的内容分配给一个变量,然后在网页上显示这些内容。
<html> <head> <title>Reading a file using PHP</title> </head> <body> <?php $filename = "tmp.txt"; $file = fopen( $filename, "r" ); if( $file == false ) { echo ( "Error in opening file" ); exit(); } $filesize = filesize( $filename ); $filetext = fread( $file, $filesize ); fclose( $file ); echo ( "File size : $filesize bytes" ); echo ( "<pre>$filetext</pre>" ); ?> </body> </html>
它将产生以下结果 -
写入文件
可以使用 PHP 的fwrite()函数写入新文件或将文本追加到现有文件。此函数需要两个参数,指定一个文件指针和要写入的数据字符串。可以选择包含第三个整数参数来指定要写入数据的长度。如果包含第三个参数,则写入将在达到指定的长度后停止。
示例
以下示例创建一个新的文本文件,然后在其中写入一个简短的文本标题。关闭此文件后,使用file_exist()函数确认其存在,该函数以文件名作为参数
<?php $filename = "/home/user/guest/newfile.txt"; $file = fopen( $filename, "w" ); if( $file == false ) { echo ( "Error in opening new file" ); exit(); } fwrite( $file, "This is a simple test\n" ); fclose( $file ); ?> <html> <head> <title>Writing a file using PHP</title> </head> <body> <?php $filename = "newfile.txt"; $file = fopen( $filename, "r" ); if( $file == false ) { echo ( "Error in opening file" ); exit(); } $filesize = filesize( $filename ); $filetext = fread( $file, $filesize ); fclose( $file ); echo ( "File size : $filesize bytes" ); echo ( "$filetext" ); echo("file name: $filename"); ?> </body> </html>
它将产生以下结果 -
我们在PHP 文件系统函数章节中介绍了所有与文件输入输出相关的函数。
PHP 数学函数
为了启用数学运算,PHP 具有数学(算术)运算符和许多数学函数。本章将通过示例解释以下数学函数。
PHP abs() 函数
abs() 函数是 PHP 解释器中的内置函数。此函数接受任何数字作为参数,并返回一个正值,忽略其符号。任何数字的绝对值始终为正。
abs( mixed $num)
PHP abs() 函数返回num的绝对值。如果 num 的数据类型是浮点数,则其返回类型也将是浮点数。对于整数参数,返回类型为整数。
示例
看一下下面的例子 -
<?php $num=-9.99; echo "negative float number: " . $num . "\n"; echo "absolute value : " . abs($num) . "\n"; $num=25.55; echo "positive float number: " . $num . "\n"; echo "absolute value : " . abs($num). "\n"; $num=-45; echo "negative integer number: " . $num . "\n"; echo "absolute value : " . abs($num) . "\n"; $num=25; echo "positive integer number: " . $num . "\n"; echo "absolute value : " . abs($num); ?>
它将产生以下输出:
negative float number: -9.99 absolute value : 9.99 positive float number: 25.55 absolute value : 25.55 negative integer number: -45 absolute value : 45 positive integer number: 25 absolute value : 25
PHP ceil() 函数
ceil() 函数是 PHP 解释器中的内置函数。此函数接受任何浮点数作为参数,并将其向上舍入到下一个最高的整数。此函数始终返回一个浮点数,因为浮点数的范围大于整数的范围。
ceil ( float $num ) : float
PHP ceil() 函数返回大于或等于给定参数的最小整数。
示例 1
以下代码将 5.78 舍入到其下一个最高的整数 6
<?php $arg=5.78; $val=ceil($arg); echo "ceil(" . $arg . ") = " . $val; ?>
它将产生以下输出:
ceil(5.78) = 6
示例 2
以下示例显示如何找到 15.05 的下一个最高整数。
<?php $arg=15.05; $val=ceil($arg); echo "ceil(" . $arg . ") = " . $val; ?>
它将产生以下输出:
ceil(15.05) = 16
示例 3
对于负数,它将舍入到 0。
<?php $arg=-3.95; $val=ceil($arg); echo "ceil(" . $arg . ") = " . $val; ?>
它将产生以下输出:
ceil(-3.95) = -3
PHP exp() 函数
exp()函数计算 e 的指数,即欧拉数。PHP 有一个预定义的常量 M_E,它表示欧拉数,等于 2.7182818284590452354。因此,exp(x) 返回 2.7182818284590452354x
此函数始终返回浮点数。
exp ( float $arg ) : float
PHP exp() 函数返回欧拉数 e 提升到给定的arg。请注意,e是自然对数的底数。exp() 函数是自然对数的逆函数。
示例 1
PHP 中的预定义常量之一是M_LN2,它代表 loge2,等于 0.69314718055994530942。因此,此值的 exp() 将返回 2。
<?php echo "exp(" . M_LN2 . ") = " . exp(M_LN2); ?>
它将产生以下输出:
exp(0.69314718055995) = 2
示例 2
M_LN10 是另一个预定义常量,代表 loge10。此程序计算 exp(M_LN10) 并返回 10。
<?php echo "exp(" . M_LN10 . ") = " . exp(M_LN10); ?>
它将产生以下输出:
exp(2.302585092994) = 10
PHP floor() 函数
floor() 函数是 PHP 解释器中的另一个内置函数。此函数接受任何浮点数作为参数,并将其向下舍入到下一个最低的整数。此函数始终返回一个浮点数,因为浮点数的范围大于整数的范围。
floor ( float $num ) : float
PHP floor() 函数返回小于或等于给定参数的最大整数。
示例 1
以下示例显示如何将 15.05 舍入到其下一个最高的整数 15
<?php $arg=15.05; $val=floor($arg); echo "floor(" . $arg . ") = " . $val; ?>
它将产生以下输出:
floor(15.05) = 15
示例 2
以下示例显示如何找到 5.78 的下一个最低整数。
<?php $arg=5.78; $val=floor($arg); echo "floor(" . $arg . ") = " . $val; ?>
它将产生以下输出:
floor(5.78) = 5
示例 3
负数将舍入远离 0。
<?php $arg=-3.95; $val=floor($arg); echo "floor(" . $arg . ") = " . $val; ?>
它将产生以下输出:
floor(-3.95) = -4
PHP intdiv() 函数
intdiv() 函数返回两个整数参数的整数商。如果 x/y 的结果是“i”作为除法和“r”作为余数,则 -
x = y*i+r
在这种情况下,intdiv(x,y) 返回“i”
intdiv ( int $x , int $y ) : int
“x”参数构成除法表达式的分子部分,“y”参数构成除法表达式的分母部分。
PHP intdiv() 函数返回“x”除以“y”的整数商。如果两个参数都是正数或两个参数都是负数,则返回值为正。
示例 1
下面的例子显示,如果分子小于分母,则 intdiv() 函数返回 0。
<?php $x=10; $y=3; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r . "\n"; $r=intdiv($y, $x); echo "intdiv(" . $y . "," . $x . ") = " . $r; ?>
它将产生以下输出:
intdiv(10,3) = 3 intdiv(3,10) = 0
示例 2
在下面的例子中,intdiv() 函数返回一个负整数,因为分子或分母是负数。
<?php $x=10; $y=3; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r . "\n"; $x=10; $y=-3; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r . "\n"; $x=-10; $y=3; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r . "\n"; $x=-10; $y=-3; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r ; ?>
它将产生以下输出:
intdiv(10,3) = 3 intdiv(10,-3) = -3 intdiv(-10,3) = -3 intdiv(-10,-3) = 3
示例 3
在下面的例子中,分母为 0。这将导致 DivisionByZeroError 异常。
<?php $x=10; $y=0; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r . "\n"; ?>
它将产生以下输出:
PHP Fatal error: Uncaught DivisionByZeroError: Division by zero
示例 4
两个参数中的小数部分将被忽略。PHP intdiv() 函数只应用于整数部分。
<?php $x=2.90; $y=1.90; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r . ""; ?>
它将产生以下输出:
intdiv(2.9,1.9) = 2
PHP log10() 函数
log10() 函数计算一个数的以 10 为底的对数。以 10 为底的对数也称为常用对数或常用算法。log10(x) 函数计算 log10x。它与自然对数的关系如下所示:
log10x=logex/loge10 ; So that log10100=loge100/loge10 = 2
在 PHP 中,log10 由log10() 函数表示
log10 ( float $arg ) : float
PHP log10() 函数返回arg 的以 10 为底的对数。
示例 1
以下代码计算 100 的以 10 为底的对数
<?php $arg=100; echo "log10(" . $arg. ")=" . log10($arg) . ""; ?>
它将产生以下输出:
log10(100)=2
示例 2
以下代码计算欧拉数M_E 的以 10 为底的对数。结果等于预定义常量M_LOG10E
<?php $arg=M_E; echo "log10(" . $arg. ")=" . log10($arg) . "\n"; echo "predefined constant M_LOG10E=" . M_LOG10E; ?>
它将产生以下输出:
log10(2.718281828459)=0.43429448190325 predefined constant M_LOG10E=0.43429448190325
示例 3
以下代码计算 log100 并返回 -∞。
<?php $arg=0; echo "log10(" . $arg. ")=" . log10($arg) . ""; ?>
它将产生以下输出:
log10(0)=-INF
示例 4
类似地,sqrt(-1) 返回 NAN。因此,它的 log10() 也返回 NAN。
<?php $arg=sqrt(-1); echo "log10(" . $arg. ")=" . log10($arg) . ""; ?>
它将产生以下输出:
log10(NAN)=NAN
PHP max() 函数
max() 函数返回数组中的最大元素,或者两个或多个逗号分隔的参数中的最大值。
max ( array $values ) : mixed
或者:
max ( mixed $value1 [, mixed $... ] ) : mixed
如果只有一个参数,则它应该是一个值数组,这些值可以是相同或不同类型的。
如果给出两个或多个参数,则它们应该是任何可比较的相同或不同类型的值。
PHP max() 函数返回数组参数或值序列中的最大值。标准比较运算符适用。如果多个不同类型的数值评估结果相等(例如 0 和 'PHP'),则返回函数的第一个参数。
示例 1
以下代码返回数值数组中的最大值。
<?php $arg=array(23, 5.55, 142, 56, 99); echo "array="; foreach ($arg as $i) echo $i . ","; echo "\n"; echo "max = " . max($arg); ?>
它将产生以下输出:
array=23,5.55,142,56,99, max = 142
示例 2
以下代码返回字符串数组中的最大值。
<?php $arg=array("Java", "Angular", "PHP", "C", "Kotlin"); echo "array="; foreach ($arg as $i) echo $i . ","; echo "\n"; echo "max = " . max($arg); ?>
它将产生以下输出:
array=Java,Angular,PHP,C,Kotlin, max = PHP
示例 3
在下面的例子中,一系列字符串值被提供给 max() 函数。让我们看看它的行为:
<?php $val1="Java"; $val2="Angular"; $val3="PHP"; $val4="C"; $val5="Kotlin"; echo "values=" . $val1 . "," . $val2 . "," . $val3 . "," . $val4 . "," . $val5 . "\n"; echo "max = " . max($val1, $val2, $val3,$val4,$val5); ?>
它将产生以下输出:
values=Java,Angular,PHP,C,Kotlin max = PHP
示例 4
在这个例子中,给定的数组是混合数据类型的集合。
<?php $arg=array(23, "Java", 142, 1e2, 99); echo "array="; foreach ($arg as $i) echo $i . ","; echo "\n"; echo "max = " . max($arg); ?>
它将产生以下输出:
array=23,Java,142,100,99, max = 142
PHP min() 函数
min() 函数返回数组中的最小元素,或者两个或多个逗号分隔的参数中的最小值。
min ( array $values ) : mixed
或者:
min ( mixed $value1 [, mixed $... ] ) : mixed
如果只有一个参数,则它应该是一个值数组,这些值可以是相同或不同类型的
如果给出两个或多个参数,则它们应该是任何可比较的相同或不同类型的值
PHP min() 函数返回数组参数或值序列中的最小值。标准比较运算符适用。如果多个不同类型的数值评估结果相等(例如 0 和 'PHP'),则返回函数的第一个参数
示例 1
以下代码返回数值数组中的最小值。
<?php $arg=array(23, 5.55, 142, 56, 99); echo "array="; foreach ($arg as $i) echo $i . ","; echo "\n"; echo "min = " . min($arg); ?>
它将产生以下输出:
array=23,5.55,142,56,99, min = 5.55
示例 2
以下代码返回字符串数组中的最小值。
<?php $arg=array("Java", "Angular", "PHP", "C", "Kotlin"); echo "array="; foreach ($arg as $i) echo $i . ","; echo "\n"; echo "min = " . min($arg); ?>
它将产生以下输出:
array=Java,Angular,PHP,C,Kotlin, min = Angular
示例 3
在这个例子中,一系列字符串值被提供给 min() 函数。
<?php $val1="Java"; $val2="Angular"; $val3="PHP"; $val4="C"; $val5="Kotlin"; echo "values=" . $val1 . "," . $val2 . "," . $val3 . "," . $val4 . "," . $val5 . "\n"; echo "min = " . min($val1, $val2, $val3,$val4,$val5); ?>
它将产生以下输出:
values=Java,Angular,PHP,C,Kotlin min = Angular
示例 4
在这个例子中,给定的数组是混合数据类型的集合。
<?php $arg=array(23, "Java", 142, 1e2, 99); echo "array="; foreach ($arg as $i) echo $i . ","; echo "\n"; echo "min = " . min($arg); ?>
它将产生以下输出:
array=23,Java,142,100,99, min = 23
PHP pow() 函数
pow() 函数用于计算某个数的幂。它返回 xy 计算结果,也称为 x 的 y 次幂。PHP 还提供 "**" 作为幂运算符。
因此,pow(x,y) 返回 xy,这与 x**y 相同。
pow ( number $base , number $exp ) : number
第一个参数是要提升的底数。第二个参数是底数需要提升的幂。
PHP pow() 函数返回底数的 exp 次幂。如果两个参数都是非负整数,则结果将作为整数返回,否则将作为浮点数返回。
示例 1
下面的例子使用 pow() 函数计算 10 的 2 次幂:
<?php echo "pow(10,2) = " . pow(10,2); echo " using ** operator " . 10**2; ?>
它将产生以下输出:
pow(10,2) = 100 using ** operator 100
示例 2
任何数的 0 次幂都等于 1。这在下面的例子中得到了验证:
<?php $x=10; $y=0; echo "pow(" . $x, "," . $y . ")=". pow($x,$y); ?>
它将产生以下输出:
pow(10,0)=1
示例 3
下面的例子展示了如何使用 pow() 函数计算 100 的平方根:
<?php $x=100; $y=0.5; echo "pow(" . $x, "," . $y . ")=". pow($x,$y) . "\n"; echo "using sqrt() function : ". sqrt(100); ?>
它将产生以下输出:
pow(100,0.5)=10 using sqrt() function : 10
示例 4
此示例演示如何使用 pow() 函数计算圆的面积。
<?php $radius=5; echo "radius = " . $radius . " area = " . M_PI*pow(5,2); ?>
它将产生以下输出:
radius = 5 area = 78.539816339745
PHP round() 函数
round() 函数在将任何浮点数四舍五入到所需的精度级别时非常有用。正精度参数会导致数字在小数点后四舍五入;而负精度则在小数点前四舍五入。默认精度为“0”。
例如,round(10.6) 返回 11,round(10.2) 返回 10。该函数始终返回浮点数。
此函数还有一个可选参数,称为mode,它接受后面描述的预定义常量之一。
round ( float $value , int $precision , int $mode ) : float
参数
值 - 要四舍五入的浮点数。
精度 - 要四舍五入的小数位数。默认为 0。正精度在小数点后四舍五入给定数字。负精度在小数点前四舍五入给定数字。
模式 - 以下预定义常量之一。
序号 | 常量 & 说明 |
---|---|
1 | PHP_ROUND_HALF_UP 当数字正好是中间值时,将其四舍五入到远离 0 的方向。因此,1.5 变成 2,-1.5 变成 -2 |
2 | PHP_ROUND_HALF_DOWN 当数字正好是中间值时,将其四舍五入到 0 的方向。因此 1.5 变成 1,-1.5 变成 -1 |
3 | PHP_ROUND_HALF_EVEN 将数字四舍五入到最接近的偶数值 |
4 | PHP_ROUND_HALF_ODD 将数字四舍五入到最接近的奇数值 |
PHP round() 函数返回一个浮点数,该浮点数通过将值四舍五入到所需的精度来获得。
示例 1
以下代码将给定数字四舍五入到正精度值:
<?php $arg=1234.567; echo "round(" . $arg . ") = " . round($arg) . "\n"; echo "round(" . $arg . ",1) = " . round($arg,1) . "\n"; echo "round(" . $arg . ",2) = " . round($arg,2) . ""; ?>
它将产生以下输出:
round(1234.567) = 1235 round(1234.567,1) = 1234.6 round(1234.567,2) = 1234.57
示例 2
以下代码将数字四舍五入到负精度值:
<?php $arg=1234.567; echo "round(" . $arg . ") = " . round($arg) . "\n"; echo "round(" . $arg . ",-1) = " . round($arg,-1) . "\n"; echo "round(" . $arg . ",-2) = " . round($arg,-2) . ""; ?>
它将产生以下输出:
round(1234.567) = 1235 round(1234.567,-1) = 1230 round(1234.567,-2) = 1200
示例 3
以下代码使用 UP 和 DOWN 模式常量进行四舍五入:
<?php echo "round(3.45,HALF_UP) = " . round(3.45,0, PHP_ROUND_HALF_UP) . "\n"; echo "round(3.75 HALF_UP) = " . round(3.75, 1, PHP_ROUND_HALF_DOWN) . ""; ?>
它将产生以下输出:
round(3.45,HALF_UP) = 3 round(3.75 HALF_UP) = 3.7
示例 4
以下代码使用 ODD 和 EVEN 模式进行四舍五入:
<?php echo "round( 3.45,HALF_ODD) = " . round(3.45,0, PHP_ROUND_HALF_ODD) . "\n"; echo "round(3.78 HALF_EVEN) = " . round(3.78, 0, PHP_ROUND_HALF_EVEN) . ""; ?>
它将产生以下输出:
round(3.45,HALF_ODD) = 3 round(3.78, HALF_EVEN) = 4
PHP sqrt() 函数
sqrt() 函数返回正浮点数的平方根。由于负数的平方根未定义,因此它返回 NAN。这是最常用的函数之一。此函数始终返回浮点数。
sqrt (float $arg) : float
PHP sqrt() 函数返回给定 arg 数的平方根。对于负数,函数返回 NAN。
示例 1
以下代码计算 100 的平方根:
<?php $arg = 100; echo "Square root of " . $arg . "=" . sqrt($arg) . ""; ?>
它将产生以下输出:
Square root of 100=10
示例 2
对于 sqrt(2)、1/sqrt(2) 和 sqrt(3),PHP 分别具有特殊的预定义常量 M_SQRT2、M_SQRT1_2 和 M_SQRT3。
<?php echo "sqrt(2) = " . sqrt(2) . "\n"; echo "M_SQRT2 = " . M_SQRT2. "\n"; echo "sqrt(3) = " . sqrt(3) . "\n"; echo "M_SQRT3 = " . M_SQRT3 . "\n"; echo "1/sqrt(2)) = " . 1/sqrt(2) . "\n"; echo "M_SQRT1_2 = " . M_SQRT1_2 . ""; ?>
它将产生以下输出:
sqrt(2) = 1.4142135623731 M_SQRT2 = 1.4142135623731 sqrt(3) = 1.7320508075689 M_SQRT3 = 1.7320508075689 1/sqrt(2)) = 0.70710678118655 M_SQRT1_2 = 0.70710678118655
示例 3
数学常量 M_SQRTPI 和 M_2_SQRTPI 分别表示 sqrt(Π) 和 2/sqrt(Π) 的值。
<?php echo "sqrt(pi) = " . sqrt(M_PI) . "\n"; echo "M_SQRTPI = " . M_SQRTPI. "\n"; echo "2/sqrt(pi) = " . 2/sqrt(M_PI) . "\n"; echo "M_2_SQRTPI = " . M_2_SQRTPI . ""; ?>
它将产生以下输出:
sqrt(pi) = 1.7724538509055 M_SQRTPI = 1.7724538509055 2/sqrt(pi) = 1.1283791670955 M_2_SQRTPI = 1.1283791670955
示例 4
sqrt(-1) 未定义,因此它返回 NAN。
<?php echo "sqrt(-1) = " . sqrt(-1) . ""; ?>
它将产生以下输出:
sqrt(-1) = NAN
预定义数学常量
除了上述数学函数外,PHP 还具有以下预定义数学常量列表:
常量 | 值 | 描述 |
---|---|---|
M_PI | 3.14159265358979323846 | π |
M_E | 2.7182818284590452354 | 欧拉数 e |
M_LOG2E | 1.4426950408889634074 | log2 e |
M_LOG10E | 0.43429448190325182765 | log10 e |
M_LN2 | 0.69314718055994530942 | loge 2 |
M_LN10 | M_LN10 2.30258509299404568402 loge 10 | loge 10 |
M_PI_2 | 1.57079632679489661923 | pi/2 |
M_PI_4 | 0.78539816339744830962 | pi/4 |
M_1_PI | 0.31830988618379067154 | 1/pi |
M_2_PI | 0.63661977236758134308 | 2/pi |
M_SQRTPI | 1.77245385090551602729 | sqrt(pi) |
M_2_SQRTPI | 1.12837916709551257390 | 2/sqrt(pi) |
M_SQRT2 | 1.41421356237309504880 | sqrt(2) |
M_SQRT3 | 1.73205080756887729352 | sqrt(3) |
M_SQRT1_2 | 0.70710678118654752440 | 1/sqrt(2) |
M_LNPI | 1.14472988584940017414 | loge(pi) |
M_EULER | 0.57721566490153286061 | 欧拉常数 |
PHP_ROUND_HALF_UP | 1 | 四舍五入到上 |
PHP_ROUND_HALF_DOWN | 2 | 四舍五入到下 |
PHP_ROUND_HALF_EVEN | 3 | 四舍五入到偶数 |
PHP_ROUND_HALF_ODD | 4 | 四舍五入到奇数 |
NAN | NAN | 非数字 |
INF | INF | 无穷大 |
PHP Heredoc 和 Nowdoc
PHP 提供了两种替代方法来声明单引号或双引号字符串,它们的形式为heredoc 和nowdoc 语法。
单引号字符串不解释转义字符,也不展开变量。
另一方面,如果声明的双引号字符串本身包含双引号字符,则需要使用“\”符号对其进行转义。heredoc 语法提供了一种方便的方法。
PHP 中的 Heredoc 字符串
PHP 中的 heredoc 字符串非常类似于双引号字符串,只是没有双引号。这意味着它们不需要转义引号并展开变量。
Heredoc 语法
$str = <<<IDENTIFIER place a string here it can span multiple lines and include single quote ' and double quotes " IDENTIFIER;
首先,以“<<<”运算符开头。在这个运算符之后,提供一个标识符,然后是一个换行符。字符串本身紧随其后,然后是相同的标识符来关闭引号。字符串可以跨越多行,并包含单引号(')或双引号(")。
结束标识符可以通过空格或制表符缩进,在这种情况下,缩进将从 doc 字符串中的所有行中去除。
示例
标识符只能包含字母数字字符和下划线,并且必须以下划线或非数字字符开头。结束标识符除了分号(;)之外,不应包含任何其他字符。此外,结束标识符之前和之后必须只有换行符。
请看以下示例:
<?php $str1 = <<<STRING Hello World PHP Tutorial by TutorialsPoint STRING; echo $str1; ?>
它将产生以下输出:
Hello World PHP Tutorial by TutorialsPoint
示例
结束标识符可以在编辑器的第一列之后是否包含缩进。如果有缩进,则将被删除。但是,结束标识符的缩进不能超过正文的任何行。否则,将引发 ParseError。请查看以下示例及其输出:
<?php $str1 = <<<STRING Hello World PHP Tutorial by TutorialsPoint STRING; echo $str1; ?>
它将产生以下输出:
PHP Parse error: Invalid body indentation level (expecting an indentation level of at least 16) in hello.php on line 3
示例
heredoc 中的引号不需要转义,但仍然可以使用 PHP 转义序列。Heredoc 语法也展开变量。
<?php $lang="PHP"; echo <<<EOS Heredoc strings in $lang expand vriables. The escape sequences are also interpreted. Here, the hexdecimal ASCII characters produce \x50\x48\x50 EOS; ?>
它将产生以下输出:
Heredoc strings in PHP expand vriables. The escape sequences are also interpreted. Here, the hexdecimal ASCII characters produce PHP
PHP 中的 Nowdoc 字符串
PHP 中的 nowdoc 字符串类似于 heredoc 字符串,只是它不展开变量,也不解释转义序列。
<?php $lang="PHP"; $str = <<<'IDENTIFIER' This is an example of Nowdoc string. it can span multiple lines and include single quote ' and double quotes " IT doesn't expand the value of $lang variable IDENTIFIER; echo $str; ?>
它将产生以下输出:
This is an example of Nowdoc string. it can span multiple lines and include single quote ' and double quotes " IT doesn't expand the value of $lang variable
nowdoc 的语法类似于 heredoc 的语法,只是跟随“<<<”运算符的标识符需要用单引号括起来。nowdoc 的标识符也遵循 heredoc 标识符的规则。
Heredoc 字符串类似于不带转义的双引号字符串。Nowdoc 字符串类似于不带转义的单引号字符串。
PHP 复合类型
PHP 中的数据类型可以是“标量类型”或“复合类型”。整数、浮点数、布尔值和字符串类型是标量类型,而数组和对象类型则归类为复合类型。多个类型的值可以一起存储在复合类型的单个变量中。
在 PHP 中,对象和数组是两种复合数据类型。
数组是其他数据类型的元素的有序集合,这些元素不一定是相同类型的。
对象是内置类或用户自定义类的实例,由属性和方法组成。
PHP中的数组
数组是一种数据结构,它在一个变量中存储一个或多个数据值。PHP中的数组是有序映射,它将值与其键关联。
PHP中有两种声明数组的方法。一种是使用内置的`array()`函数,另一种是将数组元素放在方括号内。
仅包含值的数组称为**索引数组**。每个值都由从0开始的索引标识。
如果数组是键值对的集合,则称为**关联数组**。对的键部分可以是数字或字符串,而值部分可以是任何类型。
PHP中的`array()`函数
内置的`array()`函数使用给定的参数并返回数组类型的对象。一个或多个用逗号分隔的参数是数组中的元素。
array(mixed ...$values): array
括号中的每个值可以是单个值(可以是数字、字符串、任何对象甚至另一个数组),也可以是键值对。“=>”符号表示键与其值之间的关联。
示例
看一下下面的例子 -
$arr1 = array(10, "asd", 1.55, true); $arr2 = array("one"=>1, "two"=>2, "three"=>3); $arr3 = array( array(10, 20, 30), array("Ten", "Twenty", "Thirty"), array("physics"=>70, "chemistry"=>80, "maths"=>90) );
使用方括号 []
除了`array()`函数外,还可以将用逗号分隔的数组元素放在方括号内来声明数组对象。在这种情况下,元素也可以是单个值、字符串或另一个数组。
$arr1 = [10, "asd", 1.55, true]; $arr2 = ["one"=>1, "two"=>2, "three"=>3]; $arr3 = [ [10, 20, 30], ["Ten", "Twenty", "Thirty"], ["physics"=>70, "chemistry"=>80, "maths"=>90] ];
访问数组元素
要访问给定数组中的任何元素,可以使用`array[key]`语法。对于索引数组,将索引放在方括号内,因为索引本身就是键。
<?php $arr1 = [10, 20, 30]; $arr2 = array("one"=>1, "two"=>2, "three"=>3); var_dump($arr1[1]); var_dump($arr2["two"]); ?>
它将产生以下输出:
int(20) int(2)
PHP中的数组遍历
您还可以使用`foreach`循环来迭代索引数组。
<?php $arr1 = [10, 20, 30, 40, 50]; foreach ($arr1 as $val){ echo "$val\n"; } ?>
它将产生以下输出:
10 20 30 40 50
请注意,PHP内部将索引数组视为关联数组,其中索引被视为键。可以使用`var_dump()`输出数组来验证此事实。
我们可以使用`foreach`语法将索引数组的每个元素解包到键和值变量中。
<?php $arr1 = [10, 20, 30, 40, 50]; foreach ($arr1 as $key => $val){ echo "arr1[$key] = $val" . "\n"; } ?>
它将产生以下输出:
arr1[0] = 10 arr1[1] = 20 arr1[2] = 30 arr1[3] = 40 arr1[4] = 50
`foreach`循环也用于遍历关联数组,尽管任何其他类型的循环也可以通过一些操作来使用。
让我们来看一下`foreach`循环的实现,其中每个键值对都解包到两个变量中。
<?php $capitals = array( "Maharashtra"=>"Mumbai", "Telangana"=>"Hyderabad", "UP"=>"Lucknow", "Tamilnadu"=>"Chennai" ); foreach ($capitals as $k=>$v) { echo "Capital of $k is $v" . "\n"; } ?>
它将产生以下输出:
Capital of Maharashtra is Mumbai Capital of Telangana is Hyderabad Capital of UP is Lucknow Capital of Tamilnadu is Chennai
PHP中的对象
在PHP中,对象是一种复合数据类型。它是内置类或用户自定义类的实例。下面是一个简单的PHP类。
class SayHello { function hello() { echo "Hello World"; } }
要声明一个类的对象,我们需要使用`new`运算符。
$obj=new SayHello;
我们现在可以调用它的方法了。
<?php class SayHello { function hello() { echo "Hello World". PHP_EOL; } } $obj=new SayHello; var_dump(gettype($obj)); $obj->hello(); ?>
它将产生以下输出:
string(6) "object" Hello World
stdClass
PHP提供`stdClass`作为通用的空类,它对于动态添加属性和强制转换很有用。`stdClass`的对象最初为null。我们可以动态地向其中添加属性。
<?php $obj=new stdClass; $obj->name="Deepak"; $obj->age=21; $obj->marks=75; print_r($obj); ?>
它将产生以下输出:
stdClass Object ( [name] => Deepak [age] => 21 [marks] => 75 )
PHP中的数组到对象的转换
PHP中的数组可以按如下方式强制转换为对象:
<?php $arr=array("name"=>"Deepak", "age"=>21, "marks"=>75); $obj=(object)$arr; print_r($obj); ?>
它将产生以下输出:
stdClass Object ( [name] => Deepak [age] => 21 [marks] => 75 )
PHP中的对象到数组的转换
相反,对象可以转换为数组。请看下面的例子:
<?php $obj=new stdClass; $obj->name="Deepak"; $obj->age=21; $obj->marks=75; $arr=(array)$obj; print_r($arr); ?>
它将产生以下输出:
Array ( [name] => Deepak [age] => 21 [marks] => 75 )
PHP中标量类型到对象类型的转换
任何标量类型的变量也可以通过类型转换转换为对象。标量变量的值将成为对象标量属性的值。
<?php $name="Deepak"; $age=21; $percent=75.50; $obj1=(object)$name; print_r($obj1); $obj2=(object)$age; print_r($obj2); $obj3=(object)$percent; print_r($obj3); ?>
它将产生以下输出:
stdClass Object ( [scalar] => Deepak ) stdClass Object ( [scalar] => 21 ) stdClass Object ( [scalar] => 75.5 )
PHP 文件包含
PHP中的`include`语句类似于Java或Python中的`import`语句以及C/C++中的`#include`指令。但是,PHP中`include`语句的工作方式略有不同。
Java/Python中的`import`或C/C++中的`#include`仅将一个或多个语言结构(例如在一个文件中定义的函数或类)加载到当前文件中。相反,PHP中的`include`语句将另一个文件中的所有内容都引入到现有的PHP脚本中。它可以是PHP代码、文本文件、HTML标记等。
PHP中的“include”语句
这是一个关于PHP中`include`语句如何工作的典型示例:
myfile.php
<?php # some PHP code ?>
test.php
<?php include 'myfile.php'; # PHP script in test.php ?>
`include`关键字在PHP中非常方便,尤其是在您需要在一个项目中跨多个PHP脚本使用相同的PHP代码(函数或类)或HTML标记时。一个例子是创建应该出现在Web应用程序所有页面上的菜单。
假设您想为您的网站创建一个通用菜单。然后,创建一个包含以下内容的文件“menu.php”。
<a href="https://tutorialspoint.com/index.htm">Home</a> - <a href="https://tutorialspoint.com/ebxml">ebXML</a> - <a href="https://tutorialspoint.com/ajax">AJAX</a> - <a href="https://tutorialspoint.com/perl">PERL</a> <br />
现在创建任意数量的页面并包含此文件以创建页眉。例如,现在您的“test.php”文件可以包含以下内容:
<html> <body> <?php include("menu.php"); ?> <p>This is an example to show how to include PHP file!</p> </body> </html>
假设这两个文件都位于XAMPP服务器的文档根文件夹中。访问**https://127.0.0.1/test.php** URL。它将产生以下**输出**:
当PHP解析器遇到`include`关键字时,它会尝试在执行当前脚本的同一目录中查找指定的文件。如果找不到,则搜索“php.ini”的“include_path”设置中的目录。
包含文件时,它包含的代码将继承包含该语句的行所在的变量作用域。调用文件中该行中可用的任何变量都将从那时起在被调用文件中可用。但是,包含文件中定义的所有函数和类都具有全局作用域。
示例
在下面的示例中,我们有一个“myname.php”脚本,其中声明了两个变量。它包含在另一个脚本test.php中。这些变量加载在全局作用域中。
myname.php
<?php $color = 'green'; $fruit = 'apple'; ?>
test.php
<?php include "myname.php"; echo "<h2>$fname $lname</h2>"; ?>
当浏览器访问**https://127.0.0.1/test.php**时,它显示:
Ravi Teja
但是,如果文件包含在函数内,则变量仅是函数局部作用域的一部分。
myname.php
<?php $color = 'green'; $fruit = 'apple'; ?>
test.php
<?php function showname() { include "myname.php"; } echo "<h2>$fname $lname</h2>"; ?>
现在,当浏览器访问**https://127.0.0.1/test.php**时,它会显示未定义变量警告:
Warning: Undefined variable $fname in C:\xampp\htdocs\test.php on line 7 Warning: Undefined variable $lname in C:\xampp\htdocs\test.php on line 7
include_once语句
就像`include`一样,PHP也具有`include_once`关键字。唯一的区别是,如果某个文件中的代码已被包含,则不会再次包含它,并且`include_once`返回true。顾名思义,该文件只会包含一次。
`include_once`可用于在脚本的特定执行过程中可能会多次包含和评估同一文件的情况,因此它可以帮助避免函数重新定义、变量值重新赋值等问题。
PHP – include与require
PHP中的`require`关键字与`include`关键字非常相似。两者之间的区别在于,`require`失败时会产生致命的E_COMPILE_ERROR级别错误。
换句话说,`require`将停止脚本,而`include`仅发出警告(E_WARNING),允许脚本继续执行。
require_once关键字
`require_once`关键字类似于`require`,但略有不同。如果您使用`require_once`,则PHP将检查文件是否已被包含,如果已包含,则不会再次包含同一文件。
PHP 日期与时间
PHP的内置库具有广泛的函数,有助于以编程方式处理和操作日期和时间信息。PHP中的日期和时间对象可以通过传入日期/时间信息的字符串表示或从当前系统的时钟来创建。
PHP提供`DateTime`类,该类定义了许多方法。在本章中,我们将详细了解PHP中可用的各种与日期和时间相关的方法。
PHP中的日期/时间功能实现ISO 8601日历,该日历实现了格里高利历之前使用的当前闰日规则。日期和时间信息在内部存储为64位数字。
使用time()获取时间戳
PHP的`time()`函数为您提供了关于当前日期和时间所需的所有信息。它不需要参数,但返回一个整数。
time(): int
`time()`返回的整数表示自1970年1月1日格林尼治标准时间午夜以来经过的秒数。这个时刻被称为UNIX纪元,自那时以来经过的秒数称为时间戳。
<?php print time(); ?>
它将产生以下输出:
1699421347
我们可以将时间戳转换为人类更容易理解的形式。
使用getdate()转换时间戳
`getdate()`函数可以选择性地接受时间戳并返回一个包含日期信息的关联数组。如果您省略时间戳,它将使用`time()`返回的当前时间戳。
下表列出了`getdate()`返回的数组中包含的元素。
序号 | 键与描述 | 示例 |
---|---|---|
1 | seconds 分钟后的秒数 (0-59) |
20 |
2 | minutes 小时后的分钟数 (0-59) |
29 |
3 | hours 一天中的小时数 (0-23) |
22 |
4 | mday 月份中的天数 (1-31) |
11 |
5 | wday 星期几 (0-6) |
4 |
6 | mon 一年中的月份 (1-12) |
7 |
7 | year 年份 (4位数字) |
1997 |
8 | yday 一年中的天数 (0-365) |
19 |
9 | weekday 星期几 |
星期四 |
10 | month 一年中的月份 |
一月 |
11 | 0 Timestamp |
948370048 |
现在您可以完全控制日期和时间。您可以根据需要格式化此日期和时间。
示例
请看以下示例:
<?php $date_array = getdate(); foreach ( $date_array as $key => $val ){ print "$key = $val\n"; } $formated_date = "Today's date: "; $formated_date .= $date_array['mday'] . "-"; $formated_date .= $date_array['mon'] . "-"; $formated_date .= $date_array['year']; print $formated_date; ?>
它将产生以下输出:
seconds = 0 minutes = 38 hours = 6 mday = 8 wday = 3 mon = 11 year = 2023 yday = 311 weekday = Wednesday month = November 0 = 1699421880 Today's date: 8-11-2023
使用date()转换时间戳
`date()`函数返回一个表示日期的格式化字符串。您可以使用必须传递给它的字符串参数来对`date()`返回的格式进行极大的控制。
date(string $format, ?int $timestamp = null): string
`date()`可以选择性地接受时间戳,如果省略,则使用当前日期和时间。您在传递给`date()`的格式字符串中包含的任何其他数据都将包含在返回值中。
下表列出了格式字符串可以包含的代码:
序号 | 格式与描述 | 示例 |
---|---|---|
1 | a 'am' 或 'pm' 小写 |
pm |
2 | A 'AM' 或 'PM' 大写 |
PM |
3 | d 月份中的天数,带前导零的数字 |
20 |
4 | D 星期几 (三个字母) |
Thu |
5 | F 月份名称 |
一月 |
6 | h 小时 (12小时制 - 带前导零) |
12 |
7 | H 小时 (24小时制 - 带前导零) |
22 |
8 | g 小时 (12小时制 - 无前导零) |
12 |
9 | G 小时 (24小时制 - 无前导零) |
22 |
10 | i 分钟 (0-59) |
23 |
11 | j 月份中的天数 (无前导零) |
20 |
12 | l (小写 'L') 星期几 |
星期四 |
13 | L 闰年 ('1' 表示是,'0' 表示否) |
1 |
14 | m 一年中的月份 (数字 - 带前导零) |
1 |
15 | M 一年中的月份 (三个字母) |
Jan |
16 | r RFC 2822 格式的日期 |
Thu, 21 Dec 2000 16:01:07 +0200 |
17 | n 一年中的月份 (数字 - 无前导零) |
2 |
18 | s 小时的秒数 |
20 |
19 | U 时间戳 |
948372444 |
20 | y 年份 (两位数字) |
06 |
21 | Y 年份 (四位数字) |
2006 |
22 | z 一年中的天数 (0-365) |
206 |
23 | Z 与格林尼治标准时间的偏移量(秒) |
+5 |
示例
请看以下示例:
<?php print date("m/d/y G.i:s \n", time()) . PHP_EOL; print "Today is "; print date("j of F Y, \a\\t g.i a", time()); ?>
它将产生以下输出:
11/08/23 11.23:08 Today is 8 2023f November 2023, at 11.23 am
希望您已经很好地理解了如何根据您的要求格式化日期和时间。为了您的参考,所有日期和时间函数的完整列表在PHP 日期和时间函数中给出。
PHP 标量类型声明
PHP 从 5 版本开始就提供了类型提示的功能。**类型提示**指的是在函数定义中提供参数数据类型的做法。在 PHP 7 之前,函数类型提示只能使用数组、可调用对象和类。PHP 7 及以后版本,还可以为标量数据类型(例如 int、string、bool 等)的参数插入类型提示。
PHP 是一种动态(且弱)类型语言。因此,在定义函数时,不需要声明参数的类型,而像 C 或 Java 这样的静态类型语言则需要。
PHP 函数的典型定义如下:
function addition($x, $y) { echo "First number: $x Second number: $y Addition: " . $x+$y; }
这里,我们假设参数 $x 和 $y 是数值型的。但是,即使传递给函数的值不是数值型的,PHP 解析器也会尽可能地将变量转换为兼容的类型。
如果传递的值之一是数字的字符串表示,而另一个是数值型变量,PHP 会将字符串变量转换为数值型以执行加法运算。
示例
看一下下面的例子 -
<?php function addition($x, $y) { echo "First number: " . $x; echo "\nSecond number: " . $y; echo "\nAddition: " . $x+$y; } $x="10"; $y=20; addition($x, $y); ?>
它将产生以下输出:
First number: 10 Second number: 20 Addition: 30
但是,如果上面的例子中 $x 是一个不包含有效数值表示的字符串,则会遇到错误。
<?php function addition($x, $y) { echo "First number: " . $x; echo "\nSecond number: " . $y; echo "\nAddition: " . $x+$y; } $x="Hello"; $y=20; addition($x, $y); ?>
运行这段代码,看看它如何显示**错误**。
PHP 7 中的标量类型声明
PHP 7 版本引入的一项新功能允许定义参数数据类型可以在括号内指定的函数。
PHP 7 引入了以下标量类型声明:
Int
Float
Bool
String
接口
数组
可调用对象
旧版本的 PHP 只允许使用数组、可调用对象和类类型作为类型提示。此外,在旧版本的 PHP(PHP 5)中,致命错误是可恢复的错误,而新版本(PHP 7)则返回一个可抛出的错误。
标量类型声明以两种模式实现:
**强制模式** - 强制模式是默认模式,无需指定。
**严格模式** - 必须显式提示严格模式。
强制模式
前面例子中定义的 addition() 函数现在可以通过合并类型声明来改写,如下所示:
function addition(int $x, int $y) { echo "First number: $x Second number: $y Addition: " . $x+$y; }
请注意,如果字符串包含整数,解析器仍然会转换不兼容的类型,即字符串为整数,与之前一样。
示例
看一下下面的例子 -
<?php function addition(int $x, int $y) { echo "First number: " . $x; echo "\nSecond number: " . $y; echo "\nAddition: " . $x+$y; } $x="10"; $y=20; echo addition($x, $y); ?>
它将产生以下输出:
First number: 10 Second number: 20 Addition: 30
显然,这是因为 PHP 是一种弱类型语言,PHP 会尝试将字符串类型的变量强制转换为整数。PHP 7 引入了一种严格模式功能来解决这个问题。
严格模式
为了应对 PHP 的弱类型检查,引入了严格模式。此模式通过**declare 语句**启用:
declare (strict_types=1);
此语句应放在 PHP 脚本的顶部(通常就在 PHP 标记下方)。这意味着标量的类型严格性是在每个文件的基础上配置的。
在弱模式下,strict_types 标志为 0。将其设置为 1 会强制 PHP 解析器检查传递的参数和值的兼容性。在上面的代码中添加此语句并检查结果。它将显示以下错误消息:
Fatal error: Uncaught TypeError: addition(): Argument #1 ($x) must be of type int, string given, called in add.php on line 12 and defined in add.php:4 Stack trace: #0 add.php(12): addition('10', 20) #1 {main} thrown in add.php on line 4
示例
这是函数定义中标量类型声明的另一个示例。启用严格模式后,如果将不兼容的类型作为参数传递,则会引发致命错误。
<?php // Strict mode // declare(strict_types = 1); function sum(int ...$ints) { return array_sum($ints); } print(sum(2, '3', 4.1)); ?>
取消此代码顶部**declare**语句的注释并运行它。现在它将产生一个**错误**:
Fatal error: Uncaught TypeError: sum(): Argument #2 must be of type int, string given, called in add.php on line 9 and defined in add.php:4 Stack trace: #0 add.php(9): sum(2, '3', 4.1) #1 {main} thrown in add.php on line 4
类型提示功能主要由 IDE 用于提示用户函数声明中使用的参数的预期类型。以下屏幕截图显示了 VS Code 编辑器在您键入时弹出的函数原型。
PHP 返回类型声明
PHP 7 版本将标量类型声明功能扩展到函数的返回值。根据这项新规定,返回类型声明指定函数应返回的值的类型。我们可以为返回类型声明以下类型:
int
float
bool
string
接口
数组
可调用对象
要实现返回类型声明,函数定义如下:
function myfunction(type $par1, type $param2): type { # function body return $val; }
PHP 解析器默认情况下是强制类型转换。您需要声明 "strict_types=1" 以强制更严格地验证要返回的变量类型与定义中使用的类型。
示例
在下面的例子中,division() 函数的返回类型定义为 int。
<?php function division(int $x, int $y): int { $z = $x/$y; return $z; } $x=20.5; $y=10; echo "First number: " . $x; echo "\nSecond number: " . $y; echo "\nDivision: " . division($x, $y); ?>
由于类型检查未设置为 strict_types=1,即使其中一个参数是非整数,除法也会进行。
First number: 20.5 Second number: 10 Division: 2
但是,一旦在脚本顶部添加 strict_types 的声明,程序就会引发致命错误消息。
Fatal error: Uncaught TypeError: division(): Argument #1 ($x) must be of type int, float given, called in div.php on line 12 and defined in div.php:3 Stack trace: #0 div.php(12): division(20.5, 10) #1 {main} thrown in div.php on line 3
VS Code 甚至在运行代码之前就会警告错误,在错误位置显示错误行:
示例
要使 division() 函数返回 float 而不是 int,请将分子转换为 float,然后查看 PHP 如何引发致命错误:
<?php // declare(strict_types=1); function division(int $x, int $y): int { $z = (float)$x/$y; return $z; } $x=20; $y=10; echo "First number: " . $x; echo "\nSecond number: " . $y; echo "\nDivision: " . division($x, $y); ?>
取消此代码顶部**declare**语句的注释并运行它以检查其输出。它将显示错误:
First number: 20 Second number: 10PHP Fatal error: Uncaught TypeError: division(): Return value must be of type int, float returned in /home/cg/root/14246/main.php:5 Stack trace: #0 /home/cg/root/14246/main.php(13): division() #1 {main} thrown in /home/cg/root/14246/main.php on line 5
PHP - 运算符类型
PHP 中的运算符是什么?
与任何编程语言一样,PHP 也具有运算符,它们是预定义的符号(有时是**关键字**),用于对一个或多个操作数执行某些常用的操作。
例如,表达式 "4 + 5" 等于 9。这里 "4" 和 "5" 称为**操作数**,"+" 称为**运算符**。
PHP 中有以下几种运算符:
算术运算符
比较运算符
逻辑运算符
赋值运算符
字符串运算符
数组运算符
条件(或三元)运算符
本章将概述如何在 PHP 中使用这些运算符。在后续章节中,我们将更仔细地研究每个运算符及其工作方式。
PHP 中的算术运算符
我们使用算术运算符对给定的操作数执行加、减、乘、除等数学运算。算术运算符(不包括增量和减量运算符)始终作用于两个操作数,但是这些操作数的类型应该相同。
下表突出显示了 PHP 支持的算术运算符。假设变量 “$a” 包含 42,变量 “$b” 包含 20:
运算符 | 描述 | 示例 |
---|---|---|
+ | 将两个操作数相加 | $a + $b = 62 |
- | 从第一个操作数中减去第二个操作数 | $a - $b = 22 |
* | 将两个操作数相乘 | $a * $b = 840 |
/ | 将分子除以分母 | $a / $b = 2.1 |
% | 模运算符和整数除法后的余数 | $a % $b = 2 |
++ | 增量运算符,将整数值增加一 | $a ++ = 43 |
-- | 减量运算符,将整数值减少一 | $a -- = 42 |
PHP 中的比较运算符
您可以使用比较运算符比较两个操作数并找到它们之间的关系。它们根据比较的结果返回布尔值(true 或 false)。
下表突出显示了 PHP 支持的比较运算符。假设变量 $a 包含 10,变量 $b 包含 20,则:
运算符 | 描述 | 示例 |
---|---|---|
== | 检查两个操作数的值是否相等,如果相等则条件为 true。 | ($a == $b) 为 false |
!= | 检查两个操作数的值是否不相等,如果不相等则条件为 true。 | ($a != $b) 为 true |
> | 检查左操作数的值是否大于右操作数的值,如果是则条件为 true。 | ($a > $b) 为 false |
< | 检查左操作数的值是否小于右操作数的值,如果是则条件为 true。 | ($a < $b) 为 true |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为 true。 | ($a >= $b) 为 false |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为 true。 | ($a <= $b) 为 true |
PHP 中的逻辑运算符
您可以使用 PHP 中的逻辑运算符对多个表达式一起执行逻辑运算。逻辑运算符始终返回布尔值,true 或 false。
逻辑运算符通常与条件语句和循环一起使用,根据布尔条件返回决策。您还可以将它们组合起来,在处理复杂表达式时操作布尔值。
下表突出显示了 PHP 支持的逻辑运算符。
假设变量 $a 包含 10,变量 $b 包含 20,则:
运算符 | 描述 | 示例 |
---|---|---|
and | 称为逻辑 AND 运算符。如果两个操作数都为 true,则条件为 true。 | (A and B) 为 true |
or | 称为逻辑 OR 运算符。如果两个操作数中的任何一个非零,则条件为 true。 | (A or B) 为 true |
&& | 称为逻辑 AND 运算符。如果两个操作数都非零,则条件为 true。 | (A && B) 为 true |
|| | 称为逻辑 OR 运算符。如果两个操作数中的任何一个非零,则条件为 true。 | (A || B) 为 true |
! | 称为逻辑 NOT 运算符。用于反转其操作数的逻辑状态。如果条件为 true,则逻辑 NOT 运算符将使其为 false。 | !(A && B) 为 false |
PHP 中的赋值运算符
您可以使用 PHP 中的赋值运算符为给定的变量分配或更新新值。赋值运算符的右侧保存值,赋值运算符的左侧是将为其赋值的变量。
双方的数据类型应该相同,否则会报错。赋值运算符的结合性是从右到左。PHP 支持两种类型的赋值运算符:
简单赋值运算符 − 这是最常用的运算符。它用于为变量或常量赋值。
复合赋值运算符 − 赋值运算符 (=) 与其他运算符(如 +、*、/ 等)的组合。
下表重点介绍了 PHP 支持的赋值运算符:
运算符 | 描述 | 示例 |
---|---|---|
= | 简单赋值运算符,将右侧操作数的值赋给左侧操作数 | C = A + B 将 A + B 的值赋给 C |
+= | 加法与赋值运算符,它将右侧操作数加到左侧操作数上,并将结果赋给左侧操作数 | C += A 等效于 C = C + A |
-= | 减法与赋值运算符,它从左侧操作数中减去右侧操作数,并将结果赋给左侧操作数 | C -= A 等效于 C = C - A |
*= | 乘法与赋值运算符,它将右侧操作数乘以左侧操作数,并将结果赋给左侧操作数 | C *= A 等效于 C = C * A |
/= | 除法与赋值运算符,它将左侧操作数除以右侧操作数,并将结果赋给左侧操作数 | C /= A 等效于 C = C / A |
%= | 取模与赋值运算符,它使用两个操作数取模,并将结果赋给左侧操作数 | C %= A 等效于 C = C % A |
PHP 中的字符串运算符
PHP 中有两个运算符用于处理字符串数据类型:
“.”(点)运算符是 PHP 的连接运算符。它连接两个字符串操作数(右侧字符串的字符附加到左侧字符串),并返回一个新的字符串。
PHP 还具有“.=”运算符,可以称为连接赋值运算符。它通过附加右侧操作数的字符来更新其左侧的字符串。
$third = $first . $second; $leftstring .= $rightstring;
PHP 中的数组运算符
PHP 定义了以下一组符号,用作数组数据类型的运算符:
符号 | 示例 | 名称 | 结果 |
---|---|---|---|
+ | $a + $b | 联合 | $a 和 $b 的联合。 |
== | $a == $b | 相等 | 如果 $a 和 $b 具有相同的键/值对,则为 TRUE。 |
=== | $a === $b | 恒等 | 如果 $a 和 $b 具有相同的键/值对,顺序相同且类型相同,则为 TRUE。 |
!= | $a != $b | 不相等 | 如果 $a 不等于 $b,则为 TRUE。 |
<> | $a <> $b | 不相等 | 如果 $a 不等于 $b,则为 TRUE。 |
!== | $a !== $b | 非恒等 | 如果 $a 与 $b 不相同,则为 TRUE。 |
PHP 中的条件运算符
PHP 中还有一个运算符称为条件运算符。它也称为三元运算符。它首先计算表达式的真假值,然后根据计算结果执行两个给定语句中的一个。
运算符 | 描述 | 示例 |
---|---|---|
? : | 条件表达式 | 如果条件为真?则值为 X:否则值为 Y |
PHP 中的运算符类别
我们上面讨论的所有运算符都可以分为以下几类:
一元前缀运算符,位于单个操作数之前。
二元运算符,它接受两个操作数并执行各种算术和逻辑运算。
条件运算符(三元运算符),它接受三个操作数并根据第一个表达式的计算结果计算第二个或第三个表达式。
赋值运算符,它将值赋给变量。
PHP 中的运算符优先级
运算符的优先级决定了表达式中运算符的执行顺序。例如,在“2+6/3”中,首先执行 6/3 的除法,然后执行“2+2”的加法,因为除法运算符“/”比加法运算符“+”优先级高。
要强制某个运算符在其他运算符之前调用,应使用括号。在这个例子中,(2+6)/3 首先执行加法,然后执行除法。
某些运算符可能具有相同的优先级。在这种情况下,结合性顺序(左或右)决定操作顺序。具有相同优先级但非结合性的运算符不能彼此相邻使用。
下表列出了 PHP 运算符,按优先级递减排列:
运算符 | 用途 |
---|---|
clone new | clone 和 new |
** | 指数 |
++ -- | 增量/减量 |
~(int) (float) (string) (array) (object) (bool) | 类型转换 |
instanceof | 类型 |
! | 逻辑 |
* / | 乘法/除法 |
% | 取模 |
+ - . | 算术和字符串 |
<< >> | 按位移位 |
< <= > >= | 比较 |
== != === !== <> <=> | 比较 |
& | 按位与/引用 |
^ | 按位异或 |
| | 按位或 |
&& | 逻辑与 |
|| | 逻辑或 |
?? | 空值合并 |
? : | 三元 |
= += -= *= **= /= .= %= &= |= ^= <<= >>= ??= | 赋值运算符 |
yield from | yield from |
yield | yield |
and | 逻辑 |
xor | 逻辑 |
or | 逻辑 |
PHP - 算术运算符示例
在 PHP 中,算术运算符用于对数值执行数学运算。下表重点介绍了 PHP 支持的算术运算符。假设变量“$a”保存 42,变量“$b”保存 20:
运算符 | 描述 | 示例 |
---|---|---|
+ | 将两个操作数相加 | $a + $b = 62 |
- | 从第一个操作数中减去第二个操作数 | $a - $b = 22 |
* | 将两个操作数相乘 | $a * $b = 840 |
/ | 将分子除以分母 | $a / $b = 2.1 |
% | 模运算符和整数除法后的余数 | $a % $b = 2 |
++ | 增量运算符,将整数值增加一 | $a ++ = 43 |
-- | 减量运算符,将整数值减少一 | $a -- = 42 |
示例
以下示例演示如何在 PHP 中使用这些算术运算符:
<?php $a = 42; $b = 20; $c = $a + $b; echo "Addtion Operation Result: $c \n"; $c = $a - $b; echo "Substraction Operation Result: $c \n"; $c = $a * $b; echo "Multiplication Operation Result: $c \n"; $c = $a / $b; echo "Division Operation Result: $c \n"; $c = $a % $b; echo "Modulus Operation Result: $c \n"; $c = $a++; echo "Increment Operation Result: $c \n"; $c = $a--; echo "Decrement Operation Result: $c"; ?>
它将产生以下输出:
Addtion Operation Result: 62 Substraction Operation Result: 22 Multiplication Operation Result: 840 Division Operation Result: 2.1 Modulus Operation Result: 2 Increment Operation Result: 42 Decrement Operation Result: 43
PHP - 比较运算符示例
在 PHP 中,比较运算符用于比较两个值并确定它们之间的关系。这些运算符根据比较结果返回布尔值 True 或 False。
下表突出显示了 PHP 支持的比较运算符。假设变量 $a 包含 10,变量 $b 包含 20,则:
运算符 | 描述 | 示例 |
---|---|---|
== | 检查两个操作数的值是否相等,如果相等则条件为 true。 | ($a == $b) 为 false |
!= | 检查两个操作数的值是否不相等,如果不相等则条件为 true。 | ($a != $b) 为 true |
> | 检查左操作数的值是否大于右操作数的值,如果是则条件为 true。 | ($a > $b) 为 false |
< | 检查左操作数的值是否小于右操作数的值,如果是则条件为 true。 | ($a < $b) 为 true |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为 true。 | ($a >= $b) 为 false |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为 true。 | ($a <= $b) 为 true |
此外,这些运算符还可以与逻辑运算符(&&、||、!)结合使用,形成复杂的条件,用于在 PHP 程序中进行决策。
示例
以下示例演示如何在 PHP 中使用这些比较运算符:
<?php $a = 42; $b = 20; if ($a == $b) { echo "TEST1 : a is equal to b \n"; } else { echo "TEST1 : a is not equal to b \n"; } if ($a > $b) { echo "TEST2 : a is greater than b \n"; } else { echo "TEST2 : a is not greater than b \n"; } if ($a < $b) { echo "TEST3 : a is less than b \n"; } else { echo "TEST3 : a is not less than b \n"; } if ($a != $b) { echo "TEST4 : a is not equal to b \n"; } else { echo "TEST4 : a is equal to b \n"; } if ($a >= $b) { echo "TEST5 : a is either greater than or equal to b \n"; } else { echo "TEST5 : a is neither greater than nor equal to b \n"; } if ($a <= $b) { echo "TEST6 : a is either less than or equal to b \n"; } else { echo "TEST6 : a is neither less than nor equal to b"; } ?>
它将产生以下输出:
TEST1 : a is not equal to b TEST2 : a is greater than b TEST3 : a is not less than b TEST4 : a is not equal to b TEST5 : a is either greater than or equal to b TEST6 : a is neither less than nor equal to b
PHP - 逻辑运算符示例
在 PHP 中,逻辑运算符用于组合条件语句。这些运算符允许您通过组合多个条件来创建更复杂的条件。
逻辑运算符通常用于条件语句(例如if、while和for循环)中,根据特定条件控制程序执行流程。
下表突出显示了 PHP 支持的逻辑运算符。
假设变量 $a 包含 10,变量 $b 包含 20,则:
运算符 | 描述 | 示例 |
---|---|---|
and | 称为逻辑 AND 运算符。如果两个操作数都为 true,则条件为 true。 | (A and B) 为 true |
or | 称为逻辑 OR 运算符。如果两个操作数中的任何一个非零,则条件为 true。 | (A or B) 为 true |
&& | 称为逻辑与运算符。如果左侧和右侧操作数均为真,则 AND 运算符返回 true。 | (A && B) 为 true |
|| | 称为逻辑 OR 运算符。如果两个操作数中的任何一个非零,则条件为 true。 | (A || B) 为 true |
! | 称为逻辑 NOT 运算符。用于反转其操作数的逻辑状态。如果条件为 true,则逻辑 NOT 运算符将使其为 false。 | !(A && B) 为 false |
示例
以下示例演示如何在 PHP 中使用这些逻辑运算符:
<?php $a = 42; $b = 0; if ($a && $b) { echo "TEST1 : Both a and b are true \n"; } else { echo "TEST1 : Either a or b is false \n"; } if ($a and $b) { echo "TEST2 : Both a and b are true \n"; } else { echo "TEST2 : Either a or b is false \n"; } if ($a || $b) { echo "TEST3 : Either a or b is true \n"; } else { echo "TEST3 : Both a and b are false \n"; } if ($a or $b) { echo "TEST4 : Either a or b is true \n"; } else { echo "TEST4 : Both a and b are false \n"; } $a = 10; $b = 20; if ($a) { echo "TEST5 : a is true \n"; } else { echo "TEST5 : a is false \n"; } if ($b) { echo "TEST6 : b is true \n"; } else { echo "TEST6 : b is false \n"; } if (!$a) { echo "TEST7 : a is true \n"; } else { echo "TEST7 : a is false \n"; } if (!$b) { echo "TEST8 : b is true \n"; } else { echo "TEST8 : b is false"; } ?>
它将产生以下输出:
TEST1 : Either a or b is false TEST2 : Either a or b is false TEST3 : Either a or b is true TEST4 : Either a or b is true TEST5 : a is true TEST6 : b is true TEST7 : a is false TEST8 : b is false
PHP - 赋值运算符示例
您可以在 PHP 中使用赋值运算符为变量赋值。赋值运算符是执行算术运算或其他运算的简写符号,同时为变量赋值。“=”运算符将右侧的值赋给左侧的变量。
此外,还有复合赋值运算符,如 +=、-=、*=、/= 和 %=,它们将算术运算与赋值结合起来。例如,“$x += 5”是“$x = $x + 5”的简写,将 $x 的值增加 5。赋值运算符提供了一种简洁的方法来根据变量的当前值更新变量。
下表重点介绍了 PHP 支持的赋值运算符:
运算符 | 描述 | 示例 |
---|---|---|
= | 简单赋值运算符。将右侧操作数的值赋给左侧操作数 | C = A + B 将 A + B 的值赋给 C |
+= | 加法与赋值运算符。它将右侧操作数加到左侧操作数上,并将结果赋给左侧操作数 | C += A 等效于 C = C + A |
-= | 减法与赋值运算符。它从左侧操作数中减去右侧操作数,并将结果赋给左侧操作数 | C -= A 等效于 C = C - A |
*= | 乘法与赋值运算符。它将右侧操作数乘以左侧操作数,并将结果赋给左侧操作数 | C *= A 等效于 C = C * A |
/= | 除法与赋值运算符。它将左侧操作数除以右侧操作数,并将结果赋给左侧操作数 | C /= A 等效于 C = C / A |
%= | 取模与赋值运算符。它使用两个操作数取模,并将结果赋给左侧操作数 | C %= A 等效于 C = C % A |
示例
以下示例演示如何在 PHP 中使用这些赋值运算符:
<?php $a = 42; $b = 20; $c = $a + $b; echo "Addition Operation Result: $c \n"; $c += $a; echo "Add AND Assignment Operation Result: $c \n"; $c -= $a; echo "Subtract AND Assignment Operation Result: $c \n"; $c *= $a; echo "Multiply AND Assignment Operation Result: $c \n"; $c /= $a; echo "Division AND Assignment Operation Result: $c \n"; $c %= $a; echo "Modulus AND Assignment Operation Result: $c"; ?>
它将产生以下输出:
Addition Operation Result: 62 Add AND Assignment Operation Result: 104 Subtract AND Assignment Operation Result: 62 Multiply AND Assignment Operation Result: 2604 Division AND Assignment Operation Result: 62 Modulus AND Assignment Operation Result: 20
PHP – 字符串运算符
PHP 中有两个运算符用于处理字符串数据类型:连接运算符(“.”)和连接赋值运算符(“.=”)。阅读本章以了解这些运算符在 PHP 中的工作方式。
PHP 中的连接运算符
点运算符(“.”)是 PHP 的连接运算符。它连接两个字符串操作数(右侧字符串的字符附加到左侧字符串),并返回一个新的字符串。
$third = $first . $second;
示例
以下示例演示如何在 PHP 中使用连接运算符:
<?php $x="Hello"; $y=" "; $z="PHP"; $str=$x . $y . $z; echo $str; ?>
它将产生以下输出:
Hello PHP
PHP 中的连接赋值运算符
PHP 还具有“.=”运算符,可以称为连接赋值运算符。它通过附加右侧操作数的字符来更新其左侧的字符串。
$leftstring .= $rightstring;
示例
以下示例使用连接赋值运算符。连接两个字符串操作数,返回左侧字符串更新后的内容:
<?php $x="Hello "; $y="PHP"; $x .= $y; echo $x; ?>
它将产生以下输出:
Hello PHP
PHP – 数组运算符
PHP 定义了以下一组符号,用作数组数据类型的运算符:
符号 | 示例 | 名称 | 结果 |
---|---|---|---|
+ | $a + $b | 联合 | $a 和 $b 的联合。 |
== | $a == $b | 相等 | 如果 $a 和 $b 具有相同的键/值对,则为 TRUE。 |
=== | $a === $b | 恒等 | 如果 $a 和 $b 具有相同的键/值对,顺序相同且类型相同,则为 TRUE。 |
!= | $a != $b | 不相等 | 如果 $a 不等于 $b,则为 TRUE。 |
<> | $a <> $b | 不相等 | 如果 $a 不等于 $b,则为 TRUE。 |
!== | $a !== $b | 非恒等 | 如果 $a 与 $b 不相同,则为 TRUE。 |
联合运算符将右侧数组附加到左侧数组。如果两个数组中都存在键,则使用左侧数组中的元素,而忽略右侧数组中匹配的元素。
示例:PHP 中的联合运算符
以下示例演示如何在 PHP 中使用联合运算符:
<?php $arr1=array("phy"=>70, "che"=>80, "math"=>90); $arr2=array("Eng"=>70, "Bio"=>80,"CompSci"=>90); $arr3=$arr1+$arr2; var_dump($arr3); ?>
它将产生以下输出:
array(6) { ["phy"]=> int(70) ["che"]=> int(80) ["math"]=> int(90) ["Eng"]=> int(70) ["Bio"]=> int(80) ["CompSci"]=> int(90) }
示例:当两个数组相等时
如果两个数组具有相同的键值对,则称它们相等。
在下面的示例中,我们有一个索引数组和另一个关联数组,其键对应于第一个数组中元素的索引。因此,两者相等。
<?php $arr1=array(0=>70, 2=>80, 1=>90); $arr2=array(70,90,80); var_dump ($arr1==$arr2); var_dump ($arr2!=$arr1); ?>
它将产生以下输出:
bool(true) bool(false)
示例:当两个数组相同时
当且仅当两个数组都具有相同的键值对集且顺序相同时,它们才相同。
<?php $arr1=array(0=>70, 1=>80, 2=>90); $arr2=array(70,90,80); var_dump ($arr1===$arr2); $arr3=[70,80,90]; var_dump ($arr3===$arr1); ?>
它将产生以下输出:
bool(false) bool(true)
PHP – 条件运算符示例
当需要根据条件设置值时,您将在 PHP 中使用条件运算符。它也称为三元运算符。它首先计算表达式的真假值,然后根据计算结果执行两个给定语句中的一个。
三元运算符提供了一种简洁的方式来编写条件表达式。它们由三部分组成:条件、如果条件计算结果为真则返回的值以及如果条件计算结果为假则返回的值。
运算符 | 描述 | 示例 |
---|---|---|
? : | 条件表达式 | 如果条件为真?则值为 X:否则值为 Y |
语法
语法如下:
condition ? value_if_true : value_if_false
三元运算符特别适用于将if-else语句缩短为一行。您可以使用三元运算符根据条件为变量分配不同的值,而无需多行代码。它可以提高代码的可读性。
但是,您应该谨慎使用三元运算符,否则最终会使代码过于复杂,难以理解。
示例
尝试以下示例以了解条件运算符如何在 PHP 中工作。将以下 PHP 程序复制并粘贴到 test.php 文件中,将其保存在 PHP 服务器的文档根目录中,然后使用任何浏览器浏览它。
<?php $a = 10; $b = 20; /* If condition is true then assign a to result otheriwse b */ $result = ($a > $b ) ? $a :$b; echo "TEST1 : Value of result is $result \n"; /* If condition is true then assign a to result otheriwse b */ $result = ($a < $b ) ? $a :$b; echo "TEST2 : Value of result is $result"; ?>
它将产生以下输出:
TEST1 : Value of result is 20 TEST2 : Value of result is 10
PHP 展开运算符
PHP 将三个点符号 (...) 识别为展开运算符。展开运算符有时也称为splat 运算符。此运算符最早在 PHP 7.4 版本中引入。它可以有效地用于许多情况,例如解包数组。
示例 1
在下面的示例中,$arr1 中的元素在其自身元素列表之后插入到 $arr2 中。
<?php $arr1 = [4,5]; $arr2 = [1,2,3, ...$arr1]; print_r($arr2); ?>
它将产生以下输出:
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 )
示例 2
扩展运算符可以在一个表达式中使用多次。例如,在下面的代码中,通过扩展两个数组的元素来创建一个第三个数组。
<?php $arr1 = [1,2,3]; $arr2 = [4,5,6]; $arr3 = [...$arr1, ...$arr2]; print_r($arr3); ?>
它将产生以下输出:
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [5] => 6 )
示例 3
请注意,可以使用array_merge()函数获得相同的结果,如下所示:
<?php $arr1 = [1,2,3]; $arr2 = [4,5,6]; $arr3 = array_merge($arr1, $arr2); print_r($arr3); ?>
它将产生相同的输出:
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [5] => 6 )
然而,使用(...)运算符效率更高,因为它避免了函数调用的开销。
示例 4
PHP 8.1.0 还引入了另一个特性,允许在解包参数后使用命名参数。无需分别为每个参数提供值,而是使用 ...(三个点)在数组前,将数组中的值解包到相应的参数中。
<?php function myfunction($x, $y, $z=30) { echo "x = $x y = $y z = $z"; } myfunction(...[10, 20], z:30); ?>
它将产生以下输出:
x = 10 y = 20 z = 30
示例 5
在下面的示例中,函数的返回值是一个数组。然后展开并解包数组元素。
<?php function get_squares() { for ($i = 0; $i < 5; $i++) { $arr[] = $i**2; } return $arr; } $squares = [...get_squares()]; print_r($squares); ?>
它将产生以下输出:
Array ( [0] => 0 [1] => 1 [2] => 4 [3] => 9 [4] => 16 )
PHP 空值合并运算符
空值合并运算符是 PHP 7 中引入的众多新特性之一。“合并”的意思是将许多东西组合成一个。此运算符用于替换与isset()函数结合使用的三元运算符。
PHP 中的三元运算符
PHP 有一个由“?”符号表示的三元运算符。三元运算符比较布尔表达式,如果为真则执行第一个操作数,否则执行第二个操作数。
expr ? statement1 : statement2;
示例
让我们使用三元运算符来检查某个变量是否已设置,方法是使用 isset() 函数,如果已声明则返回 true,否则返回 false。
<?php $x = 1; $var = isset($x) ? $x : "not set"; echo "The value of x is $var"; ?>
它将产生以下输出:
The value of x is 1
现在,让我们删除“x”的声明并重新运行代码:
<?php # $x = 1; $var = isset($x) ? $x : "not set"; echo "The value of x is $var"; ?>
代码现在将产生以下输出:
The value of x is not set
空值合并运算符
空值合并运算符由 "??" 符号表示。它充当与 isset() 结合使用三元运算符的便捷快捷方式。如果它的第一个操作数存在且不为空,则返回它;否则返回它的第二个操作数。
$Var = $operand1 ?? $operand2;
第一个操作数检查某个变量是否为空(或是否已设置)。如果它不为空,则返回第一个操作数,否则返回第二个操作数。
示例
请看以下示例:
<?php # $num = 10; $val = $num ?? 0; echo "The number is $val"; ?>
它将产生以下输出:
The number is 0
现在取消注释将$num设置为 10 的第一条语句并重新运行代码:
<?php $num = 10; $val = $num ?? 0; echo "The number is $val"; ?>
它现在将产生以下输出:
The number is 10
空值合并运算符的一个有用应用是检查客户端浏览器是否提供了用户名。
示例
以下代码从 URL 读取 name 变量。如果 URL 中的 name 参数确实有值,则显示他的欢迎消息。如果没有,则用户被称为访客。
<?php $username = $_GET['name'] ?? 'Guest'; echo "Welcome $username"; ?>
假设此脚本“hello.php”位于 PHP 服务器的 htdocs 文件夹中,请在 URL 中输入https://127.0.0.1/hello.php?name=Amar,浏览器将显示以下消息:
Welcome Amar
如果 URL 为https://127.0.0.1/hello.php,浏览器将显示以下消息:
Welcome Guest
空值合并运算符用作检查 isset() 函数的三元运算符的特定情况的替代。因此,以下语句给出类似的结果:
<?php $username = isset($_GET['name']) ? $_GET['name'] : 'Guest'; echo "Welcome $username"; ?>
它现在将产生以下输出:
Welcome Guest
您可以像下面这样链接 "??" 运算符:
<?php $username = $_GET['name'] ?? $_POST['name'] ?? 'Guest'; echo "Welcome $username"; ?>
它现在将产生以下输出:
Welcome Guest
如果变量 $name 未通过 GET 或 POST 方法设置,这将把用户名设置为访客。
PHP 宇宙飞船运算符
太空船运算符是 PHP 7.0 版本中引入的众多新特性之一。它是一个三元比较运算符。
传统的比较运算符(<,>,!=,== 等)返回 true 或 false(相当于 1 或 0)。另一方面,太空船运算符有三个可能的返回值:-1、0 或 1。此运算符可用于整数、浮点数、字符串、数组、对象等。
语法
太空船运算符使用的符号是"<=>"。
$retval = operand1 <=> operand2
这里,如果操作数 1 小于操作数 2,则 $retval 为 -1;如果两个操作数相等,则为 0;如果操作数 1 大于操作数 2,则为 1。
太空船运算符实现为组合比较运算符。传统的比较运算符可以被认为是 <=> 的简写,如下表所示:
运算符 |
<=> 等价物 |
---|---|
$a < $b |
($a <=> $b) === -1 |
$a <= $b |
($a <=> $b) === -1 || ($a <=> $b) === 0 |
$a == $b |
($a <=> $b) === 0 |
$a != $b |
($a <=> $b) !== 0 |
$a >= $b |
($a <=> $b) === 1 || ($a <=> $b) === 0 |
$a > $b |
($a <=> $b) === 1 |
示例 1
以下示例显示如何在 PHP 中使用太空船运算符:
<?php $x = 5; $y = 10; $z = $x <=> $y/2; echo "$x <=> $y/2 = $z"; ?>
它将产生以下输出:
5 <=> 10/2 = 0
示例 2
更改 $x=4 并检查结果:
<?php $x = 4; $y = 10; $z = $x <=> $y/2; echo "$x <=> $y/2 = $z"; ?>
它将产生以下输出:
4 <=> 10/2 = -1
示例 3
更改 $y=7 并再次检查结果:
<?php $x = 7; $y = 10; $z = $x <=> $y/2; echo "$x <=> $y/2 = $z"; ?>
它将产生以下输出:
7 <=> 10/2 = 1
示例 4
当与字符串操作数一起使用时,太空船操作数的工作方式与 strcmp() 函数相同。
<?php $x = "bat"; $y = "ball"; $z = $x <=> $y; echo "$x <=> $y = $z"; ?>
它将产生以下输出:
bat <=> ball = 1
示例 5
更改 $y = "baz" 并检查结果:
<?php $x = "bat"; $y = "baz"; $z = $x <=> $y; echo "$x <=> $y = $z"; ?>
它将产生以下输出:
bat <=> baz = -1
带有布尔操作数的太空船运算符
太空船运算符也适用于布尔操作数:
true <=> false returns 1 false <=> true returns -1 true <=> true as well as false <=> false returns 0
PHP – 决策
默认情况下,计算机程序按顺序遵循简单的输入-处理-输出路径。这种顺序流程可以通过所有计算机编程语言(包括 PHP)提供的决策控制语句来更改。
计算机程序中的决策
决策是预测程序执行期间发生的条件以及根据条件采取的特定操作。
您可以在代码中使用条件语句来做出决策。实现条件逻辑的能力是编程语言的基本要求之一。
典型的决策结构
以下是大多数编程语言中典型的决策结构的通用形式:
PHP 中的决策语句
PHP 支持以下三种决策语句:
if...else 语句 – 如果要在一个条件为真时执行一组代码,而另一个条件为假时执行另一组代码,则使用此语句。
elseif 语句 – 将此语句与 if...else 语句一起使用,如果多个条件之一为真,则执行一组代码
switch 语句 – 如果要选择要执行的多个代码块之一,请使用 Switch 语句。switch 语句用于避免冗长的if..elseif..else 代码块。
几乎所有编程语言(包括 PHP)都定义了 if-else 语句。它允许条件执行代码片段。在 PHP 中使用 if-else 语句的语法类似于 C:
if (expr) statement1 else statement2
此处的表达式是布尔表达式,计算结果为 true 或 false
任何涉及布尔运算符(如 <,>,<=,>=,!= 等)的表达式都是布尔表达式。
如果表达式的结果为 true,则将执行后续语句——它可以是简单语句或复合语句,即包含在一对括号中的语句组。
如果表达式为 false,则忽略后续语句,程序流程从下一条语句继续。
else 语句的使用是可选的。如果程序逻辑需要在表达式(在if 关键字之后)计算结果为 false 时执行另一个语句或一组语句。
elseif 语句是if 和else 的组合。它允许您检查多个表达式的 TRUE 并尽快执行代码块,只要其中一个条件计算结果为 TRUE。与else 语句一样,elseif 语句也是可选的。
switch 语句类似于对相同表达式的if 语句系列。我们将在本教程的后续章节中详细了解这些语句。
PHP if…else 语句
实现条件逻辑的能力是任何编程语言(包括 PHP)的基本要求。PHP 有三个关键字(也称为语言结构)——if、elseif 和else——用于根据不同的条件做出决策。
if 关键字是条件执行代码片段的基本结构。通常,if 关键字与else 关键字一起使用,尽管并非总是强制性的。
如果要在一个条件为真时执行一些代码,而在同一条件为假时执行另一段代码,则使用“if....else”语句。
语法
if 语句在 PHP 中的用法和语法类似于 C 语言。以下是 PHP 中if 语句的语法:
if (expression) code to be executed if expression is true; else code to be executed if expression is false;
if 语句之后总是一个布尔表达式。
如果 PHP 布尔表达式的计算结果为 true,则将执行该布尔表达式之后的语句。
如果布尔表达式的计算结果为 false,则忽略该语句。
如果算法需要在表达式为 false 时执行另一个语句,则将其写在else 关键字之后。
示例
这是一个简单的 PHP 代码,演示了if else 语句的用法。有两个变量 $a 和 $b。代码确定哪个变量更大。
<?php $a=10; $b=20; if ($a > $b) echo "a is bigger than b"; else echo "a is not bigger than b"; ?>
运行上述代码时,它将显示以下输出:
a is not bigger than b
互换“a”和“b”的值并再次运行。现在,您将获得以下输出:
a is bigger than b
示例
以下示例将显示“祝您周末愉快!”如果今天是星期五,否则它将输出“祝您今天愉快!”:
<?php $d = date("D"); if ($d == "Fri") echo "Have a nice weekend!"; else echo "Have a nice day!"; ?>
它将产生以下输出:
Have a nice weekend!
在 PHP 中使用 endif
PHP 代码通常与 HTML 脚本混合使用。我们可以在 PHP 代码的if 部分和else 部分中插入 HTML 代码。PHP 为if 和else 语句提供了另一种语法。将左大括号更改为冒号 (:),将右大括号更改为endif;,以便可以将 HTML 块添加到if 和else 部分。
<?php $d = date("D"); if ($d == "Fri"): ?> <h2>Have a nice weekend!</h2> <?php else: ?> <h2>Have a nice day!</h2> <?php endif ?>
确保上述脚本位于 PHP 服务器的文档根目录中。访问 URLhttps://127.0.0.1/hello.php。如果今天不是星期五,则应在浏览器中显示以下输出:
Have a nice day!
在 PHP 中使用 elseif
如果要在一个或多个条件为真时执行某些代码,则使用elseif 语句。PHP 中的elseif 语言结构是if 和else 的组合。
与else 类似,它指定如果原始if 表达式的计算结果为 false,则要执行的备用语句。
但是,与else 不同的是,它只会在elseif 条件表达式的计算结果为 true 时执行该备用表达式。
if (expr1) code to be executed if expr1 is true; elseif (expr2) code to be executed if expr2 is true; else code to be executed if expr2 is false;
示例
让我们修改上面的代码,以便在星期日、星期五和其他日期显示不同的消息。
<?php $d = date("D"); if ($d == "Fri") echo "<h3>Have a nice weekend!</h3>"; elseif ($d == "Sun") echo "<h3>Have a nice Sunday!</h3>"; else echo "<h3>Have a nice day!</h3>"; ?>
在星期日,浏览器将显示以下输出:
Have a nice Sunday!
示例
这是另一个示例,用于显示if-elselif-else 语句的用法:
<?php $x=13; if ($x%2==0) { if ($x%3==0) echo "<h3>$x is divisible by 2 and 3</h3>"; else echo "<h3>$x is divisible by 2 but not divisible by 3</h3>"; } elseif ($x%3==0) echo "<h3>$x is divisible by 3 but not divisible by 2</h3>"; else echo "<h3>$x is not divisible by 3 and not divisible by 2</h3>"; ?>
上面的代码还使用嵌套if 语句。
对于x 的值为 13、12 和 10,输出将如下所示:
13 is not divisible by 3 and not divisible by 2 12 is divisible by 2 and 3 10 is divisible by 2 but not divisible by 3
PHP switch 语句
PHP 中的 `switch` 语句可以看作是一系列针对同一表达式的 `if…else` 语句的替代方案。假设你需要将一个表达式或变量与许多不同的值进行比较,并根据它等于哪个值来执行不同的代码块。在这种情况下,你会使用多个 `if…elseif…else` 结构。
然而,这种结构会使代码变得相当混乱且难以理解。为了简化此类代码,你可以使用 PHP 中的 `switch case` 结构,它提供了一种更紧凑的替代方案,避免了冗长的 `if..elseif..else` 代码块。
下面的 PHP 脚本使用了 `if elseif` 语句:
if ($x == 0) { echo "x equals 0"; } elseif ($x == 1) { echo "i equals 1"; } elseif ($x == 2) { echo "x equals 2"; }
你可以使用 `switch case` 语句获得相同的结果,如下所示:
switch ($x) { case 0: echo "x equals 0"; break; case 1: echo "x equals 1"; break; case 2: echo "x equals 2"; break; }
`switch` 语句后面跟着一个表达式,该表达式依次与每个 `case` 子句中的值进行比较。如果发现表达式与任何 `case` 匹配,则执行相应的语句块。
`switch` 语句逐行执行花括号内的语句。
如果找到一个 `case` 语句,其表达式的计算结果与 `switch` 表达式的值匹配,则 PHP 开始执行语句,直到 `switch` 块的末尾,或者第一次遇到 `break` 语句。
如果你不在 `case` 语句列表的末尾编写 `break` 语句,PHP 将继续执行下一个 `case` 的语句。
示例
尝试删除上面的代码中的 `break` 语句并运行它。如果 `x` 的值为 0,你会发现输出中包含 "x equals 1" 和 "x equals 2" 行。
<?php $x=0; switch ($x) { case 0: echo "x equals 0 \n"; case 1: echo "x equals 1 \n"; case 2: echo "x equals 2"; } ?>
它将产生以下输出:
x equals 0 x equals 1 x equals 2
因此,务必确保每个 `case` 块以 `break` 语句结尾。
Switch 语句中的默认情况
一个特殊的情况是 `default` 情况。这种情况匹配任何未被其他情况匹配的内容。使用 `default` 是可选的,但如果使用,它必须是花括号内最后一个 `case`。
你可以组合多个 `case` 来模拟多个用 `or` 运算符组合的逻辑表达式。
<?php $x=10; switch ($x) { case 0: case 1: case 2: echo "x between 0 and 2 \n"; break; default: echo "x is less than 0 or greater than 2"; } ?>
要比较的值在 `case` 子句中给出。该值可以是数字、字符串,甚至是函数。但是,你不能在 `case` 子句中使用比较运算符(`<`,`>`,`==` 或 `!=`)作为值。
你可以选择在 `case` 子句中使用分号而不是冒号。如果找不到匹配的 `case`,并且也没有 `default` 分支,则不会执行任何代码,就像没有哪个 `if` 语句为真一样。
switch-endswitch 语句
PHP 允许使用替代语法,用 `switch-endswitch` 语句来界定 `switch` 结构。以下版本的 `switch case` 是可接受的。
<?php $x=0; switch ($x) : case 0: echo "x equals 0"; break; case 1: echo "x equals 1 \n"; break; case 2: echo "x equals 2 \n"; break; default: echo "None of the above"; endswitch ?>
在 Switch…Case 中使用 Break 语句
显然,你不需要编写 `break` 来终止 `default` 情况,因为它是在 `switch` 结构中的最后一个情况。
示例
请看以下示例:
<?php $d = date("D"); switch ($d){ case "Mon": echo "Today is Monday"; break; case "Tue": echo "Today is Tuesday"; break; case "Wed": echo "Today is Wednesday"; break; case "Thu": echo "Today is Thursday"; break; case "Fri": echo "Today is Friday"; break; case "Sat": echo "Today is Saturday"; break; case "Sun": echo "Today is Sunday"; break; default: echo "Wonder which day is this ?"; } ?>
它将产生以下输出:
Today is Monday
PHP – 循环类型
PHP 中的循环用于执行相同的代码块指定次数。PHP 支持以下四种循环类型。
`for` - 循环执行代码块指定次数。
`foreach` - 循环遍历数组中每个元素的代码块。
`while` - 只要指定的条件为真,就循环执行代码块。
`do-while` - 循环执行代码块一次,然后只要指定的条件为真就重复循环。
此外,我们还将解释如何在 PHP 中使用 `continue` 和 `break` 语句来控制循环的执行。
PHP for 循环
当你知道要执行语句或语句块多少次时,可以使用 `for` 语句。
语法
for (initialization; condition; increment){ code to be executed; }
初始化器用于设置循环迭代次数计数器的起始值。可以在这里为此目的声明一个变量,并且传统上将其命名为 `$i`。
示例
以下示例进行五次迭代,并在每次循环通过时更改两个变量的赋值:
<?php $a = 0; $b = 0; for( $i = 0; $i<5; $i++ ) { $a += 10; $b += 5; } echo ("At the end of the loop a = $a and b = $b" ); ?>
它将产生以下输出:
At the end of the loop a = 50 and b = 25
PHP foreach 循环
`foreach` 语句用于遍历数组。对于每次迭代,当前数组元素的值都分配给 `$value`,并且数组指针移动一位,在下一次迭代中将处理下一个元素。
语法
foreach (array as value) { code to be executed; }
示例
尝试以下示例列出数组的值。
<?php $array = array( 1, 2, 3, 4, 5); foreach( $array as $value ) { echo "Value is $value \n"; } ?>
它将产生以下输出:
Value is 1 Value is 2 Value is 3 Value is 4 Value is 5
PHP while 循环
只要测试表达式为真,`while` 语句就会执行代码块。
如果测试表达式为真,则执行代码块。代码执行后,将再次计算测试表达式,循环将继续,直到测试表达式为假。
语法
while (condition) { code to be executed; }
示例
此示例在每次循环迭代中递减变量值,计数器递增直到达到 10,此时计算结果为假,循环结束。
<?php $i = 0; $num = 50; while($i < 10) { $num--; $i++; } echo ("Loop stopped at i = $i and num = $num" ); ?>
它将产生以下输出:
Loop stopped at i = 10 and num = 40
PHP do-while 循环
`do-while` 语句至少执行一次代码块 - 然后只要条件为真就重复循环。
语法
do { code to be executed; } while (condition);
示例
以下示例将至少增加一次 `i` 的值,并且只要 `i` 的值小于 10,它将继续增加变量 `i`:
<?php $i = 0; $num = 0; do { $i++; } while( $i < 10 ); echo ("Loop stopped at i = $i" ); ?>
它将产生以下输出:
Loop stopped at i = 10
PHP break 语句
PHP `break` 关键字用于提前终止循环的执行。
`break` 语句位于语句块内。它给你完全的控制权,无论何时你想退出循环,你都可以出来。退出循环后,将执行循环后的下一个语句。
示例
在下面的示例中,当计数器值达到 3 时,条件测试变为真,循环终止。
<?php $i = 0; while( $i < 10) { $i++; if( $i == 3 )break; } echo ("Loop stopped at i = $i" ); ?>
它将产生以下输出:
Loop stopped at i = 3
PHP continue 语句
PHP `continue` 关键字用于停止循环的当前迭代,但它不会终止循环。
就像 `break` 语句一样, `continue` 语句位于包含循环执行的代码的语句块内,前面是一个条件测试。对于遇到 `continue` 语句的迭代,其余的循环代码将被跳过,并开始下一轮迭代。
示例
在下面的示例中,循环打印数组的值,但对于条件为真的情况,它只是跳过代码并打印下一个值。
<?php $array = array( 1, 2, 3, 4, 5); foreach( $array as $value ) { if( $value == 3 )continue; echo "Value is $value \n"; } ?>
它将产生以下输出:
Value is 1 Value is 2 Value is 4 Value is 5
PHP for 循环
程序默认情况下遵循语句的顺序执行。如果程序流程指向程序中任何较早的语句,则构成循环。PHP 中的 `for` 语句是构成 PHP 脚本中循环的便捷工具。本章将讨论 PHP 的 `for` 语句。
"for" 循环的流程图
下面的流程图解释了 `for` 循环的工作原理:
当你知道要执行语句或语句块多少次时,可以使用 `for` 语句。
"for" 循环的语法
PHP 中 `for` 语句的语法与 C 语言中的 `for` 语句类似。
for (expr1; expr2; expr3){ code to be executed; }
`for` 关键字后面是一个括号,包含三个用分号分隔的表达式。它们中的每一个都可以为空,或者可以包含多个用逗号分隔的表达式。括号后面是一个或多个放在花括号内的语句。它构成循环的主体。
括号中的第一个表达式只在循环开始时执行。它通常充当 **初始化器**,用于设置循环迭代次数计数器的起始值。
在每次迭代开始时,都会计算 `expr2`。如果它的计算结果为真,则循环继续,并且执行主体块中的语句。如果它的计算结果为假,则循环的执行结束。通常,`expr2` 指定计数器的最终值。
`expr3` 在每次迭代结束时执行。在大多数情况下,此表达式递增计数器变量。
示例
`for` 循环最通用的示例如下:
<?php for ($i=1; $i<=10; $i++){ echo "Iteration No: $i \n"; } ?>
这是它的**输出**:
Iteration No: 1 Iteration No: 2 Iteration No: 3 Iteration No: 4 Iteration No: 5 Iteration No: 6 Iteration No: 7 Iteration No: 8 Iteration No: 9 Iteration No: 10
无限 "for" 循环
请注意,括号中的所有三个表达式都是可选的。只有两个分号的 `for` 语句构成一个无限循环。
for (; ;) { Loop body }
要停止无限迭代,需要在循环体中使用 `break` 语句。
递减 "for" 循环
你也可以形成一个递减的 `for` 循环。要有一个从 10 到 1 的 `for` 循环,请将循环变量初始化为 10,中间的表达式在每次迭代开始时计算是否大于 1。每次迭代结束时要执行的最后一个表达式应该将其递减 1。
<?php for ($i=10; $i>=1; $i--){ echo "Iteration No: $i \n"; } ?>
它将产生以下输出:
Iteration No: 10 Iteration No: 9 Iteration No: 8 Iteration No: 7 Iteration No: 6 Iteration No: 5 Iteration No: 4 Iteration No: 3 Iteration No: 2 Iteration No: 1
使用 "for…endfor" 结构
你也可以使用 ":" (冒号) 符号来启动循环块,并在块的末尾放置 `endfor` 语句。
<?php for ($i=1; $i<=10; $i++): echo "Iteration No: $i \n"; endfor; ?>
使用 "for" 循环迭代索引数组
数组中的每个元素都由从 "0" 开始递增的索引标识。如果存在 5 个元素的数组,则其下界为 0,上界为 4(数组大小 -1)。
要获取数组中的元素个数,可以使用 `count()` 函数。因此,我们可以使用以下 `for` 语句迭代索引数组:
<?php $numbers = array(10, 20, 30, 40, 50); for ($i=0; $i<count($numbers); $i++){ echo "numbers[$i] = $numbers[$i] \n"; } ?>
它将产生以下输出:
numbers[0] = 10 numbers[1] = 20 numbers[2] = 30 numbers[3] = 40 numbers[4] = 50
使用 "for" 循环迭代关联数组
PHP 中的关联数组是键值对的集合。箭头符号 (=>) 用于显示键与其值之间的关联。我们使用 `array_keys()` 函数来获取键的数组。
下面的 `for` 循环从代码中定义的关联数组 `$capitals` 中打印每个州的首府:
<?php $capitals = array( "Maharashtra"=>"Mumbai", "Telangana"=>"Hyderabad", "UP"=>"Lucknow", "Tamilnadu"=>"Chennai" ); $keys=array_keys($capitals); for ($i=0; $i<count($keys); $i++){ $cap = $keys[$i]; echo "Capital of $cap is $capitals[$cap] \n"; } ?>
这是它的**输出**:
Capital of Maharashtra is Mumbai Capital of Telangana is Hyderabad Capital of UP is Lucknow Capital of Tamilnadu is Chennai
在 PHP 中使用嵌套 "for" 循环
如果在现有循环的主体内部使用另一个 `for` 循环,则这两个循环被称为嵌套。
对于外循环的计数器变量的每个值,都会完成内循环的所有迭代。
<?php for ($i=1; $i<=3; $i++){ for ($j=1; $j<=3; $j++){ echo "i= $i j= $j \n"; } } ?>
它将产生以下输出:
i= 1 j= 1 i= 1 j= 2 i= 1 j= 3 i= 2 j= 1 i= 2 j= 2 i= 2 j= 3 i= 3 j= 1 i= 3 j= 2 i= 3 j= 3
请注意,字符串是数组的一种形式。 `strlen()` 函数给出字符串中字符的个数。
示例
下面的 PHP 脚本使用两个嵌套循环来打印每行中来自字符串的递增数量的字符。
<?php $str = "TutorialsPoint"; for ($i=0; $i<strlen($str); $i++){ for ($j=0; $j<=$i; $j++){ echo "$str[$j]"; } echo "\n"; } ?>
它将产生以下输出:
T Tu Tut Tuto Tutor Tutori Tutoria Tutorial Tutorials TutorialsP TutorialsPo TutorialsPoi TutorialsPoin TutorialsPoint
PHP foreach 循环
PHP 中的 `foreach` 结构专门用于迭代数组。如果你尝试将其用于具有不同数据类型的变量,PHP 将引发错误。
PHP 中的 `foreach` 循环可以与索引数组和关联数组一起使用。有两种类型的可用语法:
foreach (array as $value) { statements }
上述方法在你想迭代索引数组时很有用。下面的语法更适合关联数组。
foreach (array as $key => $value) { statements }
但是,这两种方法都适用于索引数组,因为数组中项目的索引也充当键。
使用 "foreach" 循环和索引数组
上面的第一种语法在 `foreach` 关键字前面显示一个括号。然后是待遍历的数组的名称,后面跟着 "as" 关键字,然后是一个变量。
当第一次迭代开始时,数组中的第一个元素被分配给变量。循环块结束后,变量取下一个元素的值,并重复循环体中的语句,直到数组中的元素用尽。
`foreach` 循环的典型用法如下:
<?php $arr = array(10, 20, 30, 40, 50); foreach ($arr as $val) { echo "$val \n"; } ?>
示例
PHP 提供了一个非常有用的函数 **array_search()**,它返回给定值的键。由于索引数组中索引本身就是键,因此对于每个 **$val**,array_search() 都返回每个值的从零开始的索引。下面的代码演示了它的工作原理:
<?php $arr = array(10, 20, 30, 40, 50); foreach ($arr as $val) { $index = array_search($val, $arr); echo "Element at index $index is $val \n"; } ?>
它将产生以下输出:
Element at index 0 is 10 Element at index 1 is 20 Element at index 2 is 30 Element at index 3 is 40 Element at index 4 is 50
示例
**foreach** 语法的第二个变体将数组中的每个元素解包到两个变量中:一个用于 **键**,一个用于 **值**。
由于索引数组中索引本身充当键,因此 **$k** 变量依次获取数组中每个元素的递增索引。
<?php $arr = array(10, 20, 30, 40, 50); foreach ($arr as $k=>$v) { echo "Key: $k => Val: $v \n"; } ?>
它将产生以下输出:
Key: 0 => Val: 10 Key: 1 => Val: 20 Key: 2 => Val: 30 Key: 3 => Val: 40 Key: 4 => Val: 50
使用 "foreach" 循环迭代关联数组
关联数组是键值对的集合。要遍历关联数组,可以使用 foreach 语法的第二个变体。数组中的每个元素都被解包到两个变量中,每个变量分别取键及其值。
示例
这是一个示例,其中使用 **foreach** 循环遍历州及其各自首府的数组。
<?php $capitals = array( "Maharashtra"=>"Mumbai", "Telangana"=>"Hyderabad", "UP"=>"Lucknow", "Tamilnadu"=>"Chennai" ); foreach ($capitals as $k=>$v) { echo "Capital of $k is $v \n"; } ?>
它将产生以下输出:
Capital of Maharashtra is Mumbai Capital of Telangana is Hyderabad Capital of UP is Lucknow Capital of Tamilnadu is Chennai
但是,您仍然可以使用 **foreach** 语句的第一个版本,其中仅将数组中每个键值对的值存储在变量中。然后,我们使用之前使用过的 **array_search()** 函数获取与值对应的键。
<?php $capitals = array( "Maharashtra"=>"Mumbai", "Telangana"=>"Hyderabad", "UP"=>"Lucknow", "Tamilnadu"=>"Chennai" ); foreach ($capitals as $pair) { $cap = array_search($pair, $capitals); echo "Capital of $cap is $capitals[$cap] \n"; } ?>
使用 "foreach" 循环迭代二维数组
可以在 PHP 中声明多维数组,其中数组中的每个元素都是另一个数组本身。请注意,外部数组和子数组都可以是索引数组或关联数组。
在下面的示例中,我们有一个二维数组,可以将其称为数组的数组。我们需要嵌套循环来遍历嵌套的数组结构,如下所示:
<?php $twoD = array( array(1,2,3,4), array("one", "two", "three", "four"), array("one"=>1, "two"=>2, "three"=>3) ); foreach ($twoD as $idx=>$arr) { echo "Array no $idx \n"; foreach ($arr as $k=>$v) { echo "$k => $v" . "\n"; } echo "\n"; } ?>
它将产生以下输出:
Array no 0 0 => 1 1 => 2 2 => 3 3 => 4 Array no 1 0 => one 1 => two 2 => three 3 => four Array no 2 one => 1 two => 2 three => 3
PHP while 循环
在 PHP 脚本中创建循环最简单的方法是使用 **while** 结构。PHP 中 **while** 循环的语法类似于 C 语言中的语法。只要 while 语句中的布尔表达式为真,循环体块就会重复执行。
下面的流程图有助于理解 PHP 中 **while** 循环的工作原理:
每次在循环开始时都会检查表达式的值。如果 **while** 表达式从一开始就计算为假,则循环甚至不会运行一次。即使表达式在块的执行过程中变为假,执行也不会停止,直到迭代结束。
**while** 循环的语法可以表示如下:
while (expr){ statements }
示例
以下代码显示了 **while** 循环在 PHP 中如何工作的简单示例。变量 **$x** 在循环开始之前初始化为 1。只要它小于或等于 10,就要求执行循环体。循环体中的 **echo** 语句打印当前迭代次数,并递增 **x** 的值,以便条件最终变为假。
<?php $x = 1; while ($x<=10) { echo "Iteration No. $x \n"; $x++; } ?>
它将产生以下输出:
Iteration No. 1 Iteration No. 2 Iteration No. 3 Iteration No. 4 Iteration No. 5 Iteration No. 6 Iteration No. 7 Iteration No. 8 Iteration No. 9 Iteration No. 10
请注意,测试条件在每次迭代开始时都会被检查。即使条件在循环内变为假,执行也不会停止,直到迭代结束。
示例
在下面的示例中,“x”在每次迭代中递增 3。在第三次迭代中,“x”变为 9。由于测试条件仍然为真,因此进行下一轮迭代,其中“x”变为 12。当条件变为假时,循环停止。
<?php $x = 0; while ($x<=10){ $x+=3; echo "Iteration No. $x \n"; } ?>
它将产生以下输出:
Iteration No. 3 Iteration No. 6 Iteration No. 9 Iteration No. 12
示例
循环变量不需要总是递增。如果循环变量的初始值大于循环应该结束的值,则必须递减它。
<?php $x = 5; while ($x>0) { echo "Iteration No. $x \n"; $x--; } ?>
它将产生以下输出:
Iteration No. 5 Iteration No. 4 Iteration No. 3 Iteration No. 2 Iteration No. 1
使用 "while" 迭代数组
PHP 中的索引数组是元素的集合,每个元素都由从 0 开始的递增索引标识。
您可以通过构造一个 **while** 循环来遍历数组,重复访问第 x 个索引处的元素,直到“x”达到数组的长度。这里,“x”是一个计数器变量,每次迭代都会递增。我们还需要一个 count() 函数来返回数组的大小。
示例
请看以下示例:
<?php $numbers = array(10, 20, 30, 40, 50); $size = count($numbers); $x=0; while ($x<$size) { echo "Number at index $x is $numbers[$x] \n"; $x++; } ?>
它将产生以下输出:
Number at index 0 is 10 Number at index 1 is 20 Number at index 2 is 30 Number at index 3 is 40 Number at index 4 is 50
嵌套 "while" 循环
您可以在另一个 **while** 循环内包含一个 **while** 循环。内外 while 循环都由两个独立的变量控制,这两个变量在每次迭代后都会递增。
示例
<?php $i=1; $j=1; while ($i<=3){ while ($j<=3){ echo "i= $i j= $j \n"; $j++; } $j=1; $i++; } ?>
它将产生以下输出:
i= 1 j= 1 i= 1 j= 2 i= 1 j= 3 i= 2 j= 1 i= 2 j= 2 i= 2 j= 3 i= 3 j= 1 i= 3 j= 2 i= 3 j= 3
请注意,“j”(内部 **while** 循环的计数器变量)在获取所有值后重新初始化为 1,以便对于下一个“i”值,“j”再次从 1 开始。
遍历字符串中的字符
在 PHP 中,字符串可以被认为是字符的索引集合。因此,可以使用一个带有计数器变量的 while 循环(从“0”到字符串长度),一次获取一个字符。
示例
下面的示例计算给定字符串中元音的数量。我们使用 **strlen()** 获取长度,并使用 **str_contains()** 检查字符是否是元音之一。
<?php $line = "PHP is a popular general-purpose scripting language that is especially suited to web development."; $vowels="aeiou"; $size = strlen($line); $i=0; $count=0; while ($i<$size){ if (str_contains($vowels, $line[$i])) { $count++; } $i++; } echo "Number of vowels = $count"; ?>
它将产生以下输出:
Number of vowels = 32
使用 "endwhile" 语句
PHP 还允许您为 **while** 循环使用替代语法。与其将多个语句放在花括号中,不如在条件之后用冒号 (:) 符号标记循环体,并在末尾使用 **endwhile** 语句。
示例
<?php $x = 1; while ($x<=10): echo "Iteration No. $x \n"; $x++; endwhile; ?>
它将产生以下输出:
Iteration No. 1 Iteration No. 2 Iteration No. 3 Iteration No. 4 Iteration No. 5 Iteration No. 6 Iteration No. 7 Iteration No. 8 Iteration No. 9 Iteration No. 10
请注意,**endwhile** 语句以分号结尾。
PHP do…while 循环
"do…while" 循环是 PHP 中可用的另一种循环结构。这种类型的循环类似于 **while** 循环,只是测试条件是在每次迭代结束时检查,而不是在新迭代开始时检查。
**while** 循环在进入循环之前验证真值条件,而在 "do…while" 循环中,真值条件在重新进入循环之前进行验证。因此,"do…while" 循环保证至少有一次迭代,无论真值条件如何。
下图通过使用这两个循环的比较流程图表示法,显示了 "while" 循环和 "do…while" 循环的区别。
构成 "do…while" 循环的 **语法** 与其在 C 语言中的对应部分类似。
do { statements; } while (expression);
示例
这是一个 "do…while" 循环的简单示例,它打印 1 到 5 的迭代次数。
<?php $i=1; do{ echo "Iteration No: $i \n"; $i++; } while ($i<=5); ?>
它将产生以下输出:
Iteration No: 1 Iteration No: 2 Iteration No: 3 Iteration No: 4 Iteration No: 5
示例
以下代码使用 **while** 循环并生成相同的输出:
<?php $i=1; while ($i<=5){ echo "<h3>Iteration No: $i</h3>"; $i++; } ?>
因此,可以说 "do…while" 和 "while" 循环的行为类似。但是,当计数器变量(在本例中为 **$i**)的初始值设置为大于 while 关键字前面的括号中使用的测试表达式中的值的任何值时,差异就会很明显。
示例
在以下代码中,使用了两个循环——**while** 和 "**do…while**"。**while** 循环的计数器变量是 **$i**,"do…while" 循环的计数器变量是 **$j**。两者都初始化为 10(任何大于 5 的值)。
<?php echo "while Loop \n"; $i=10; while ($i<=5){ echo "Iteration No: $i \n"; $i++; } echo "do-while Loop \n"; $j=10; do{ echo "Iteration No: $j \n"; $j++; } while ($j<=5); ?>
它将产生以下输出:
while Loop do - while Loop Iteration No: 10
结果显示 **while** 循环没有执行任何迭代,因为条件在一开始就是假的(**$i** 初始化为 10,大于测试条件 **$i<=5**)。另一方面,"do…while" 循环即使计数器变量 **$j** 初始化为大于测试条件的值,也会进行第一次迭代。
因此,我们可以推断 "do…while" 循环保证至少一次迭代,因为测试条件是在循环块结束时验证的。**while** 循环可能不会进行任何迭代,因为测试条件是在进入循环块之前验证的。
另一个语法上的区别是 "do…while" 中的 **while** 语句以分号结尾。对于 **while** 循环,括号后面跟着一个花括号括起来的循环块。
除此之外,没有其他区别。可以使用这两种类型的循环进行互换。
递减 "do…while" 循环
要设计一个递减计数的 "do…while",请将计数器变量初始化为较高的值,使用递减运算符 (--) 在循环内减少每次迭代的计数器值,并将 **while** 括号中的测试条件设置为运行循环,直到计数器大于所需的最后一个值。
示例
在下面的示例中,计数器从 5 递减到 1。
<?php $j=5; do{ echo "Iteration No: $j \n"; $j--; } while ($j>=1); ?>
它将产生以下输出:
Iteration No: 5 Iteration No: 4 Iteration No: 3 Iteration No: 2 Iteration No: 1
反向遍历字符串
在 PHP 中,字符串可以被视为字符的索引数组。我们可以通过运行递减的 "do…while" 循环来从末尾到开头一次提取和显示一个字符,如下所示:
<?php $string = "TutorialsPoint"; $j = strlen($string); do{ $j--; echo "Character at index $j : $string[$j] \n"; } while ($j>=1); ?>
它将产生以下输出:
Character at index 13 : t Character at index 12 : n Character at index 11 : i Character at index 10 : o Character at index 9 : P Character at index 8 : s Character at index 7 : l Character at index 6 : a Character at index 5 : i Character at index 4 : r Character at index 3 : o Character at index 2 : t Character at index 1 : u Character at index 0 : T
嵌套 "do…while" 循环
像 **for** 循环或 **while** 循环一样,您也可以编写嵌套的 "do…while" 循环。在下面的示例中,上部的 "do…while" 循环使用 **$i** 计数迭代,内部 "do…while" 循环递增 **$j**,并且每次打印 **$i*j** 的乘积,从而打印 1 到 10 的表格。
<?php $i=1; $j=1; do{ print "\n"; do{ $k = sprintf("%4u",$i*$j); print "$k"; $j++; } while ($j<=10); $j=1; $i++; } while ($i<=10); ?>
它将产生以下输出:
1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100
PHP break 语句
PHP 中的 **break** 语句和 **continue** 语句被称为“循环控制语句”。PHP 中的任何类型的循环(**for**、**while** 或 **do-while**)都设计为根据使用的测试条件运行一定次数的迭代。循环块内的 **break** 语句将程序流程带到块之外,放弃可能剩下的其余迭代。
**break** 语句通常有条件地使用。否则,循环会在第一次迭代本身完成之前终止。
**break** 语句的 **语法** 如下:
while(expr){ if (condition){ break; } }
下面的 **流程图** 解释了 **break** 语句的工作原理:
示例
下面的 PHP 代码是使用循环中 **break** 的一个简单示例。**while** 循环预计执行十次迭代。但是,循环内的 **break** 语句在计数器超过 3 时终止它。
<?php $i = 1; while ($i<=10){ echo "Iteration No. $i \n"; if ($i>=3){ break; } $i++; } ?>
它将产生以下输出:
Iteration No. 1 Iteration No. 2 Iteration No. 3
可以在 break 关键字前面提供一个可选的数字参数。它在嵌套循环结构中特别有用。它指示要中断多少个嵌套的封闭结构。默认值为 1,只中断直接封闭的结构。
示例
下面的示例有三个嵌套循环:一个 **for** 循环,其中包含一个 **while** 循环,而 **while** 循环又包含一个 **do-while** 循环。
最里面的循环执行 **break**。它前面的数字“2”将控制从当前作用域带到 **for** 循环,而不是直接的 **while** 循环。
<?php for ($x=1; $x<=3; $x++){ $y=1; while ($y<=3){ $z=1; do { echo "x:$x y:$y z:$z \n"; if ($z==2){ break 2; } $z++; } while ($z<=3); $z=1; $y++; } } ?>
它将产生以下输出:
x:1 y:1 z:1 x:1 y:1 z:2 x:2 y:1 z:1 x:2 y:1 z:2 x:3 y:1 z:1 x:3 y:1 z:2
请注意,每次“z”的值变为 2 时,程序都会跳出“y”循环。因此,“y”的值始终为 1。
PHP continue 语句
与 **break** 语句类似,**continue** 是 PHP 中的另一个“循环控制语句”。与 **break** 语句不同,**continue** 语句跳过当前迭代,并在条件评估以及下一个迭代开始处继续执行。
**continue** 语句可用于任何类型的循环结构,即 **for、foreach、while** 或 **do-while** 循环。像 **break** 一样,**continue** 关键字也通常有条件地使用。
while(expr){ if (condition){ continue; } }
下面的 **流程图** 解释了 **continue** 语句的工作原理:
示例
下面是一个简单的示例,展示了 **continue** 的用法。**for** 循环预计完成十次迭代。但是,每当计数器 id 可被 2 整除时,**continue** 语句都会跳过迭代。
<?php for ($x=1; $x<=10; $x++){ if ($x%2==0){ continue; } echo "x = $x \n"; } ?>
它将产生以下输出:
x = 1 x = 3 x = 5 x = 7 x = 9
示例
**continue** 语句接受一个可选的数字参数,该参数告诉它应该跳过多少层封闭循环的结束。默认值为 1。
<?php for ($i=1; $i<=3; $i++){ for ($j=1; $j<=3; $j++){ for ($k=1; $k<=3; $k++){ if ($k>1){ continue 2; } print "i: $i j:$j k: $k\n"; } } } ?>
它将产生以下输出:
i: 1 j:1 k: 1 i: 1 j:2 k: 1 i: 1 j:3 k: 1 i: 2 j:1 k: 1 i: 2 j:2 k: 1 i: 2 j:3 k: 1 i: 3 j:1 k: 1 i: 3 j:2 k: 1 i: 3 j:3 k: 1
内部 **for** 循环中的 **continue** 语句跳过迭代 2 和 3,并直接跳转到中间循环。因此,输出显示所有“i”和“k”变量的值的“k”都为 1。
PHP 数组
数组是一种数据结构,它在一个变量中存储一个或多个具有某种关系的数据值。例如,如果您想存储一个班级中 10 个学生的成绩,那么与其定义 10 个不同的变量,不如定义一个长度为 10 的数组更容易。
PHP 中的数组与 C 语言中的数组略有不同,因为 PHP 是一种动态类型语言,而 C 是一种静态类型语言。
PHP 中的数组是有序映射,它将值与键关联。
PHP 数组可以用来实现不同的数据结构,例如堆栈、队列、列表(向量)、哈希表、字典等等。
数组元素的值部分可以是其他数组。这个特性可以用来实现树形数据结构和多维数组。
在 PHP 中声明数组有两种方法。一种是使用内置的 array() 函数,另一种是使用更简短的语法,将数组元素放在方括号内。
array() 函数
内置的`array()`函数使用给定的参数并返回数组类型的对象。一个或多个用逗号分隔的参数是数组中的元素。
array(mixed ...$values): array
括号中的每个值可以是单个值(可以是数字、字符串、任何对象甚至另一个数组),也可以是键值对。“=>”符号表示键与其值之间的关联。
示例
$arr1 = array(10, "asd", 1.55, true); $arr2 = array("one"=>1, "two"=>2, "three"=>3); $arr3 = array( array(10, 20, 30), array("Ten", "Twenty", "Thirty"), array("physics"=>70, "chemistry"=>80, "maths"=>90) );
使用方括号 []
除了`array()`函数外,还可以将用逗号分隔的数组元素放在方括号内来声明数组对象。在这种情况下,元素也可以是单个值、字符串或另一个数组。
$arr1 = [10, "asd", 1.55, true]; $arr2 = ["one"=>1, "two"=>2, "three"=>3]; $arr3 = [ [10, 20, 30], ["Ten", "Twenty", "Thirty"], ["physics"=>70, "chemistry"=>80, "maths"=>90] ];
PHP 中的数组类型
有三种不同类型的数组,每个数组值都使用称为数组索引的 ID 进行访问。
索引数组 - 只包含值的数组称为索引数组。每个值都由从“0”开始的位置索引标识。值以线性方式存储和访问。
关联数组 - 如果数组是键值对的集合,则称为关联数组。对的键组件可以是数字或字符串,而值部分可以是任何类型。关联数组根据键值存储元素值,而不是严格的线性索引顺序。
多维数组 - 如果索引数组或关联数组中的每个值本身都是一个数组,则称为多维数组。值使用多个索引进行访问。
注意 - 内置数组函数在函数参考中给出 PHP 数组函数
需要注意的是,PHP 内部将上述任何类型都视为关联数组本身。对于索引数组,其中每个值都有索引,索引本身就是它的键。var_dump() 函数揭示了这一事实。
示例
在这个例子中,arr1 是一个索引数组。但是,var_dump() 显示任何对象的结构化信息,显示每个值都具有其索引作为其键。
<?php $arr1 = [10, "asd", 1.55, true]; var_dump($arr1); ?>
它将产生以下输出:
array(4) { [0]=> int(10) [1]=> string(3) "asd" [2]=> float(1.55) [3]=> bool(true) }
示例
同样的原理也适用于多维索引数组,其中数组中的每个值都是另一个数组。
<?php $arr1 = [ [10, 20, 30], ["Ten", "Twenty", "Thirty"], [1.1, 2.2, 3.3] ]; var_dump($arr1); ?>
它将产生以下输出:
array(3) { [0]=> array(3) { [0]=> int(10) [1]=> int(20) [2]=> int(30) } [1]=> array(3) { [0]=> string(3) "Ten" [1]=> string(6) "Twenty" [2]=> string(6) "Thirty" } [2]=> array(3) { [0]=> float(1.1) [1]=> float(2.2) [2]=> float(3.3) } }
访问数组元素
要访问给定数组中的任何元素,可以使用 array[key] 语法。
示例
对于索引数组,将索引放在方括号内,因为索引本身就是键。
<?php $arr1 = [10, 20, 30]; $arr2 = array("one"=>1, "two"=>2, "three"=>3); var_dump($arr1[1]); var_dump($arr2["two"]); ?>
它将产生以下输出:
int(20) int(2)
我们将在后续章节中更详细地探讨 PHP 数组的类型。
PHP 索引数组
在 PHP 中,数组元素可以是键值对的集合,也可以只包含值。如果数组仅包含值,则称其为索引数组,因为每个元素都由从“0”开始递增的索引标识。
PHP 中的索引数组可以使用 array() 函数或方括号语法创建。
$arr1 = array("a", 10, 9.99, true); $arr2 = ["a", 10, 9.99, true];
数组中的每个元素都有一个位置索引,第一个元素位于索引“0”处。var_dump() 函数显示这些数组的结构化信息如下:
array(4) { [0]=> string(1) "a" [1]=> int(10) [2]=> float(9.99) [3]=> bool(true) }
我们可以使用索引遍历数组,获取给定索引处的值或就地修改元素的值。
遍历 PHP 中的索引数组
任何类型的 PHP 循环都可以用来遍历数组。如果我们想使用for 或while 循环,我们必须使用 count() 函数找到数组中的元素数量,并将其值用作计数for 或while 循环的测试条件。
示例
以下代码使用for 循环列出索引数组中的所有元素。
<?php $numbers = array(10, 20, 30, 40, 50); for ($i=0; $i<count($numbers); $i++){ echo "numbers[$i] = $numbers[$i] \n"; } ?>
它将产生以下输出:
numbers[0] = 10 numbers[1] = 20 numbers[2] = 30 numbers[3] = 40 numbers[4] = 50
您还可以使用while 或do-while 循环遍历索引数组。在这里,我们也需要使用 count() 函数查找数组长度。
示例
以下代码反向遍历给定的索引数组:
<?php $numbers = array(10, 20, 30, 40, 50); $i = count($numbers)-1; while ($i>=0){ echo "numbers[$i] = $numbers[$i] \n"; $i--; } ?>
它将产生以下输出:
numbers[4] = 50 numbers[3] = 40 numbers[2] = 30 numbers[1] = 20 numbers[0] = 10
使用索引访问数组元素
您可以使用array[index] 语法访问数组中的任何值。特定索引处的值可以用新值赋值。因此,数组将就地修改。
示例
以下程序从数组$arr1 中获取值,并将它们以相反的顺序放入$arr2 中。因此,$arr1 中第 0 位的值成为 $arr2 中的最后一个值。
<?php $arr1 = array(10, 20, 30, 40, 50); $size = count($arr1); for ($i=0; $i<$size; $i++){ $arr2[$size-$i-1] = $arr1[$i]; } for ($i=0; $i<$size; $i++){ echo "arr1[$i] = $$arr1[$i] arr2[$i] = $$arr2[$i] \n"; } ?>
它将产生以下输出:
arr1[0] = $10 arr2[0] = $50 arr1[1] = $20 arr2[1] = $40 arr1[2] = $30 arr2[2] = $30 arr1[3] = $40 arr2[3] = $20 arr1[4] = $50 arr2[4] = $10
使用“foreach”循环遍历索引数组
您还可以使用foreach 循环迭代索引数组。请看下面的示例:
<?php $arr1 = [10, 20, 30, 40, 50]; foreach ($arr1 as $val){ echo "$val \n"; } ?>
它将产生以下输出:
10 20 30 40 50
请注意,PHP内部将索引数组视为关联数组,其中索引被视为键。可以使用`var_dump()`输出数组来验证此事实。
示例
我们可以使用foreach 语法将索引数组的每个元素解包到键和值变量中:
<?php $arr1 = [10, 20, 30, 40, 50]; foreach ($arr1 as $key => $val){ echo "arr1[$key] = $val \n"; } ?>
它将产生以下输出:
arr1[0] = 10 arr1[1] = 20 arr1[2] = 30 arr1[3] = 40 arr1[4] = 50
在 PHP 中,数组可以混合包含值和键值对。PHP 只为没有键的值分配索引。
示例
在这个例子中,PHP 为数字分配递增索引,跳过其中出现的键值对。
<?php $arr1 = [10, 20, "vals" => ["ten", "twenty"], 30, 40, 50]; var_dump($arr1); ?>
它将产生以下输出:
array(6) { [0]=> int(10) [1]=> int(20) ["vals"]=> array(2) { [0]=> string(3) "ten" [1]=> string(6) "twenty" } [2]=> int(30) [3]=> int(40) [4]=> int(50) }
PHP 关联数组
如果 PHP 数组中的每个元素都是键值对,则此类数组称为关联数组。在这种类型的数组中,每个值都由其关联的键而不是索引标识。
关联数组用于实现字典、映射、树等数据结构。
在 PHP 中,使用“=>”符号建立键与其值之间的关联。
如何在 PHP 中声明关联数组?
可以使用声明数组的两种方法——array() 函数和方括号表示法。
$arr1 = array( "Maharashtra"=>"Mumbai", "Telangana"=>"Hyderabad", "UP"=>"Lucknow", "Tamilnadu"=>"Chennai" ); $arr2 = ["Maharashtra"=>"Mumbai", "Telangana"=>"Hyderabad", "UP"=>"Lucknow", "Tamilnadu"=>"Chennai"];
如果我们调用 var_dump() 函数,以上两个数组将显示类似的结构:
array(4) { ["Maharashtra"]=> string(6) "Mumbai" ["Telangana"]=> string(9) "Hyderabad ["UP"]=> string(7) "Lucknow" ["Tamilnadu"]=> string(7) "Chennai" }
关联数组中每个元素的键部分可以是任何数字(整数、浮点数或布尔值)或字符串。值部分可以是任何类型。但是,浮点键将转换为整数。因此,布尔 true/false 用作“1”或“0”作为键。
示例
请看以下示例:
<?php $arr1 = array( 10=>"hello", 5.75=>"world", -5=>"foo", false=>"bar" ); var_dump($arr1); ?>
它将产生以下输出:
array(4) { [10]=> string(5) "hello" [5]=> string(5) "world" [-5]=> string(3) "foo" [0]=> string(3) "bar" }
请注意,键 5.75 将四舍五入为 5,键“true”反映为“0”。如果同一个键在数组中出现多次,则最后出现的键值对将被保留,丢弃键与之前值的关联。
PHP 内部甚至将索引数组视为关联数组,其中索引实际上是值的键。这意味着第 0 个索引处的值的键等于“0”,依此类推。对索引数组进行 var_dump() 也会显示出 PHP 数组的这种特性。
迭代 PHP 关联数组
foreach 循环是最简单且最适合迭代关联数组的方法,尽管其他类型的循环也可以通过一些操作使用。
示例
让我们看看foreach 循环的实现,其中每个键值对都解包到两个变量中。
<?php $capitals = array( "Maharashtra"=>"Mumbai", "Telangana"=>"Hyderabad", "UP"=>"Lucknow", "Tamilnadu"=>"Chennai" ); foreach ($capitals as $k=>$v) { echo "Capital of $k is $v \n"; } ?>
它将产生以下输出:
Capital of Maharashtra is Mumbai Capital of Telangana is Hyderabad Capital of UP is Lucknow Capital of Tamilnadu is Chennai
还有另一种在 PHP 中使用foreach 循环的方法,其中每个元素都存储在一个变量中。然后,我们可以使用array_search() 分离键和值部分,并在循环体中使用它们。
<?php $capitals = array( "Maharashtra"=>"Mumbai", "Telangana"=>"Hyderabad", "UP"=>"Lucknow", "Tamilnadu"=>"Chennai" ); foreach ($capitals as $pair) { $cap = array_search($pair, $capitals); echo "Capital of $cap is $capitals[$cap] \n"; } ?>
它将产生以下输出:
Capital of Maharashtra is Mumbai Capital of Telangana is Hyderabad Capital of UP is Lucknow Capital of Tamilnadu is Chennai
要使用 for、while 或do-while 循环,我们必须首先获取所有键的数组(使用 array_keys()),找到大小并将其用作循环语法中的测试条件。
示例
以下是如何使用for 循环遍历关联数组:
<?php $capitals = array( "Maharashtra"=>"Mumbai", "Telangana"=>"Hyderabad", "UP"=>"Lucknow", "Tamilnadu"=>"Chennai" ); $keys=array_keys($capitals); for ($i=0; $i<count($keys); $i++){ $cap = $keys[$i]; echo "Capital of $cap is $capitals[$cap] \n"; } ?>
它将产生以下输出:
Capital of Maharashtra is Mumbai Capital of Telangana is Hyderabad Capital of UP is Lucknow Capital of Tamilnadu is Chennai
使用键访问值
在关联数组中,键是值的标识符而不是索引。因此,要获取与某个键关联的值,请使用 $arr[key] 语法。这也可以用来更新某个键的值。
示例
在下面的代码中,声明了一个关联数组$arr1。创建另一个数组$arr2,以便它存储来自$arr1 的每一对,每个键的值加倍。
<?php $arr1 = array("a"=>10, "b"=>20, "c"=>30, "d"=>40); foreach ($arr1 as $k=>$v){ $arr2[$k] = $v*2; } print_r($arr2); ?>
它将产生以下输出:
Array ( [a] => 20 [b] => 40 [c] => 60 [d] => 80 )
此处使用的print_r() 函数以易于理解的人类可读形式显示存储在数组中的数据。
PHP 多维数组
多维数组是数组的数组。在 PHP 数组中,每个元素都可以是另一个数组。如果数组包含值或键值对,其值是单个标量类型,则它是一维数组。如果数组中的每个元素都是一个或多个标量值的数组,则它是一个二维数组。
PHP 数组也可以是二维关联数组,其中外部数组的每个元素都是键值对,其值是另一个关联数组。
# one dimensional indexed array $arr = [10, 20, 30, 40]; # one dimensional associative array $arr = ["key1"=> "val1", "key2" => "val2", "key3" => "val3"]; # two dimensional indexed array $arr = [ [1,2,3,4], [10, 20, 30, 40], [100, 200, 300, 400] ]; # two dimensional associative array $arr = [ "row1" => ["key11" => "val11", "key12" => "val12", "key13" => "val13"], "row2" => ["key21" => "val21", "key22" => "val22", "key23" => "val23"], "row3" => ["key31" => "val31", "key32" => "val32", "key33" => "val33"] ];
迭代二维数组
需要两个嵌套循环才能遍历二维数组中的所有元素。foreach 循环更适合数组遍历。二维数组就像数据以行和列形式的表格表示。
示例
以下示例显示如何以表格形式重现二维数组:
<?php $tbl = [ [1,2,3,4], [10, 20, 30, 40], [100, 200, 300, 400] ]; echo ("\n"); foreach ($tbl as $row){ foreach ($row as $elem){ $val = sprintf("%5d", $elem); echo $val; } echo "\n"; } ?>
它将产生以下输出:
1 2 3 4 10 20 30 40 100 200 300 400
示例
我们还可以使用两个嵌套的foreach 循环来遍历二维关联数组。将外部数组的每一行解包到行键和行值变量中,并使用内部foreach 循环遍历每一行的元素。
<?php $tbl = [ "row1" => ["key11" => "val11", "key12" => "val12", "key13" => "val13"], "row2" => ["key21" => "val21", "key22" => "val22", "key23" => "val23"], "row3" => ["key31" => "val31", "key32" => "val32", "key33" => "val33"] ]; echo ("\n"); foreach ($tbl as $rk=>$rv){ echo "$rk\n"; foreach ($rv as $k=>$v){ echo "$k => $v "; } echo "\n"; } ?>
它将产生以下输出:
row1 key11 => val11 key12 => val12 key13 => val13 row2 key21 => val21 key22 => val22 key23 => val23 row3 key31 => val31 key32 => val32 key33 => val33
访问二维数组中的元素
访问和修改数组中元素的 $arr[$key] 语法也可以扩展到二维数组。对于二维索引数组,可以使用表达式“$arr[$i][$j]”获取和赋值第 i 行中的第 j 个元素。
示例
<?php $tbl = [[1,2,3,4], [10, 20, 30, 40], [100, 200, 300, 400]]; # prints number in index 2 of the row 2 print ("Value at [2], [2] :" . $tbl[2][2]); ?>
它将产生以下输出:
Value at [2], [2] :300
类似地,可以将第 i 行和第 j 列的值设置为另一个值。
$tbl[2][2] = 250;
示例
如果是二维关联数组,我们需要使用所需列的行键和键值变量来访问或修改其值。
<?php $tbl = [ "row1" => ["key11" => "val11", "key12" => "val12", "key13" => "val13"], "row2" => ["key21" => "val21", "key22" => "val22", "key23" => "val23"], "row3" => ["key31" => "val31", "key32" => "val32", "key33" => "val33"] ]; print "value at row2 - key22 is " . $tbl["row2"]["key22"]; ?>
它将产生以下输出:
value at row2 - key22 is val22
多维数组
在上面的例子中,我们有一个数组,其中每个键的关联值是另一个键值对的集合,我们称之为二维数组。这个概念可以扩展到任意数量的级别。例如,如果内部数组中的每个元素将其键与另一个数组关联,则它成为一个三维数组。
这是一个三维数组的示例:
$arr3D = [ [ [1, 0, 9], [0, 5, 6], [1, 0, 3] ], [ [0, 4, 6], [0, 0, 1], [1, 2, 7] ], ];
示例
要遍历这样的三维数组,我们需要三个嵌套的foreach 循环,如下所示:
<?php $arr3D = [ [[1, 0, 9],[0, 5, 6],[1, 0, 3]], [[0, 4, 6],[0, 0, 1],[1, 2, 7]], ]; foreach ($arr3D as $arr) { foreach ($arr as $row) { foreach ($row as $element) { echo "$element "; } echo "\n"; } echo "\n"; } ?>
它将产生以下输出:
1 0 9 0 5 6 1 0 3 0 4 6 0 0 1 1 2 7
但是,完全可以声明一个扩展到任意维度的数组。为此,我们需要一个通用的解决方案来遍历任意维度的数组。
多维数组的递归遍历
以下代码显示了一个递归函数,如果某个键的值是另一个数组,则该函数会调用自身。如果我们将任何数组作为参数传递给此函数,它将被遍历,显示其中的所有键值对。
function showarray($arr) { foreach ($arr as $k=>$v) { if (is_array($v)) { showarray($v); } else { echo "$k => $v "; } } echo "\n"; }
示例
让我们将上面的三维数组$arr3D 传递给它并查看结果:
<?php $arr3D = [ [[1, 0, 9],[0, 5, 6],[1, 0, 3]], [[0, 4, 6],[0, 0, 1],[1, 2, 7]], ]; function showarray($arr){ foreach ($arr as $k=>$v){ if (is_array($v)){ showarray($v); } else { echo "$k => $v "; } } echo "\n"; } showarray($arr3D); ?>
它将产生以下输出:
0 => 1 1 => 0 2 => 9 0 => 0 1 => 5 2 => 6 0 => 1 1 => 0 2 => 3 0 => 0 1 => 4 2 => 6 0 => 0 1 => 0 2 => 1 0 => 1 1 => 2 2 => 7
此递归函数可用于任何类型的数组,无论是索引数组还是关联数组,以及任何维度。
示例
让我们使用二维关联数组作为参数传递给 showarray() 函数:
<?php $tbl = [ "row1" => ["key11" => "val11", "key12" => "val12", "key13" => "val13"], "row2" => ["key21" => "val21", "key22" => "val22", "key23" => "val23"], "row3" => ["key31" => "val31", "key32" => "val32", "key33" => "val33"] ]; function showarray($arr){ foreach ($arr as $k=>$v){ if (is_array($v)){ showarray($v); } else { echo "$k => $v "; } } echo "\n"; } showarray($tbl); ?>
它将产生以下输出:
key11 => val11 key12 => val12 key13 => val13 key21 => val21 key22 => val22 key23 => val23 key31 => val31 key32 => val32 key33 => val33
PHP 数组函数
PHP 数组函数允许您以各种方式与数组交互和操作它们。PHP 数组对于存储、管理和操作变量集至关重要。
PHP 支持简单和多维数组,可以是用户创建的,也可以是由其他函数创建的。
安装
使用PHP数组函数无需安装;它们是PHP核心的一部分,随标准PHP安装一起提供。
运行时配置
此扩展程序在php.ini中没有定义任何配置指令。
PHP 数组函数
下表列出了所有与PHP数组相关的函数。其中,“版本”列指示支持该函数的最早PHP版本。
序号 | 函数及描述 | 版本 |
---|---|---|
1 | array()
创建数组 |
4.2.0 |
2 | array_change_key_case()
返回一个所有键都为小写或大写的数组 |
4.2.0 |
3 | array_chunk()
将数组分割成多个数组块 |
4.2.0 |
3 | array_column()
返回输入数组中单列的值 |
5.5.0 |
4 | array_combine()
使用一个数组作为键,另一个数组作为值来创建一个数组 |
5 |
5 | array_count_values()
返回一个数组,其中包含每个值的出现次数 |
4 |
6 | array_diff()
比较数组值,并返回差异 |
4 |
7 | array_diff_assoc()
比较数组键和值,并返回差异 |
4 |
8 | array_diff_key()
比较数组键,并返回差异 |
5 |
9 | array_diff_uassoc()
比较数组键和值,并使用额外的用户自定义函数进行检查,然后返回差异 |
5 |
10 | array_diff_ukey()
比较数组键,并使用额外的用户自定义函数进行检查,然后返回差异 |
5 |
11 | array_fill()
用值填充数组 |
4 |
12 | array_fill_keys()
用值填充数组,并指定键 |
5 |
13 | array_filter()
使用用户自定义函数过滤数组元素 |
4 |
14 | array_flip()
交换数组中所有键与其关联的值 |
4 |
15 | array_intersect()
比较数组值,并返回匹配项 |
4 |
16 | array_intersect_assoc()
比较数组键和值,并返回匹配项 |
4 |
17 | array_intersect_key()
比较数组键,并返回匹配项 |
5 |
18 | array_intersect_uassoc()
比较数组键和值,并使用额外的用户自定义函数进行检查,然后返回匹配项 |
5 |
19 | array_intersect_ukey()
比较数组键,并使用额外的用户自定义函数进行检查,然后返回匹配项 |
5 |
20 | array_key_exists()
检查数组中是否存在指定的键 |
4 |
21 | array_keys()
返回数组的所有键 |
4 |
22 | array_map()
将数组的每个值发送到用户自定义函数,该函数返回新值 |
4 |
23 | array_merge()
将一个或多个数组合并成一个数组 |
4 |
24 | array_merge_recursive()
将一个或多个数组合并成一个数组 |
4 |
25 | array_multisort()
对多个或多维数组进行排序 |
4 |
26 | array_pad()
向数组插入指定数量的项,并使用指定的值 |
4 |
27 | array_pop()
删除数组的最后一个元素 |
4 |
28 | array_product()
计算数组中值的乘积 |
5 |
29 | array_push()
向数组的末尾插入一个或多个元素 |
4 |
30 | array_rand()
从数组中返回一个或多个随机键 |
4 |
31 | array_reduce()
使用用户定义的函数将数组作为字符串返回 |
4 |
32 | array_reverse()
按相反顺序返回数组 |
4 |
33 | array_search()
在数组中搜索给定值并返回键 |
4 |
34 | array_shift()
删除数组的第一个元素,并返回已删除元素的值 |
4 |
35 | array_slice()
返回数组的选定部分 |
4 |
36 | array_splice()
删除和替换数组的指定元素 |
4 |
37 | array_sum()
返回数组中值的总和 |
4 |
38 | array_udiff()
在用户自定义函数中比较数组值并返回一个数组 |
5 |
39 | array_udiff_assoc()
比较数组键,在用户自定义函数中比较数组值,并返回一个数组 |
5 |
40 | array_udiff_uassoc()
在用户自定义函数中比较数组键和数组值,并返回一个数组 |
5 |
41 | array_uintersect()
在用户自定义函数中比较数组值并返回一个数组 |
5 |
42 | array_uintersect_assoc()
比较数组键,在用户自定义函数中比较数组值,并返回一个数组 |
5 |
43 | array_uintersect_uassoc()
在用户自定义函数中比较数组键和数组值,并返回一个数组 |
5 |
44 | array_unique()
删除数组中的重复值 |
4 |
45 | array_unshift()
向数组的开头添加一个或多个元素 |
4 |
46 | array_values()
返回数组的所有值 |
4 |
47 | array_walk()
将用户函数应用于数组的每个成员 |
3 |
48 | array_walk_recursive()
递归地将用户函数应用于数组的每个成员 |
5 |
49 | arsort()
按相反顺序对数组进行排序并保持索引关联 |
3 |
50 | asort()
对数组进行排序并保持索引关联 |
3 |
51 | compact()
创建包含变量及其值的数组 |
4 |
52 | count()
计算数组中的元素个数或对象中的属性个数 |
3 |
53 | current()
返回数组中的当前元素 |
3 |
54 | each()
返回数组中的当前键值对 |
3 |
55 | end()
将数组的内部指针设置为其最后一个元素 |
3 |
56 | extract()
从数组将变量导入到当前符号表中 |
3 |
57 | in_array()
检查数组中是否存在指定的值 |
4 |
58 | key()
从数组中获取键 |
3 |
59 | krsort()
按相反顺序对数组的键进行排序 |
3 |
60 | ksort()
按键对数组进行排序 |
3 |
61 | list()
像数组一样分配变量 |
3 |
62 | natcasesort()
使用不区分大小写的“自然顺序”算法对数组进行排序 |
4 |
63 | natsort()
使用“自然顺序”算法对数组进行排序 |
4 |
64 | next()
推进数组的内部数组指针 |
3 |
65 | pos()
current() 的别名 |
3 |
66 | prev()
倒回内部数组指针 |
3 |
67 | range()
创建一个包含一系列元素的数组 |
3 |
68 | reset()
将数组的内部指针设置为其第一个元素 |
3 |
69 | rsort()
按相反顺序对数组进行排序 |
3 |
70 | shuffle()
随机排列数组 |
3 |
71 | sizeof()
count() 的别名 |
3 |
72 | sort()
对数组进行排序 |
3 |
73 | uasort()
使用用户定义的函数对数组进行排序并保持索引关联 |
3 |
74 | uksort()
使用用户定义的函数按键对数组进行排序 |
3 |
75 | usort()
使用用户定义的函数按值对数组进行排序 |
3 |
PHP数组常量
序号 | 常量 & 说明 |
---|---|
1 | CASE_LOWER 与array_change_key_case()一起使用,将数组键转换为小写 |
2 |
CASE_UPPER 与array_change_key_case()一起使用,将数组键转换为大写 |
3 |
SORT_ASC 与array_multisort()一起使用,按升序排序 |
4 |
SORT_DESC 与array_multisort()一起使用,按降序排序 |
5 |
SORT_REGULAR 用于正常比较项目 |
6 |
SORT_NUMERIC 用于按数值比较项目 |
7 |
SORT_STRING 用于将项目作为字符串进行比较 |
8 |
SORT_LOCALE_STRING 用于根据当前区域设置将项目作为字符串进行比较 |
9 |
COUNT_NORMAL |
10 |
COUNT_RECURSIVE |
11 |
EXTR_OVERWRITE |
12 |
EXTR_SKIP |
13 |
EXTR_PREFIX_SAME |
14 |
EXTR_PREFIX_ALL |
15 |
EXTR_PREFIX_INVALID |
16 |
EXTR_PREFIX_IF_EXISTS |
17 | EXTR_IF_EXISTS |
18 | EXTR_REFS |
PHP 常量数组
在PHP 5.6版本之前,无法声明常量数组。从PHP 5.6版本开始,可以使用“const”关键字声明常量数组。从PHP 7版本开始,也可以使用define()函数创建常量数组。
常量数组是在创建后无法修改的数组。与普通数组不同,它的标识符不以“$”符号开头。
声明常量数组的旧语法为:
const ARR = array(val1, val2, val3);
示例
<?php const FRUITS = array( "Watermelon", "Strawberries", "Pomegranate", "Blackberry", ); var_dump(FRUITS); ?>
它将产生以下输出:
array(4) { [0]=> string(10) "Watermelon" [1]=> string(12) "Strawberries" [2]=> string(11) "Pomegranate" [3]=> string(10) "Blackberry" }
您也可以使用传统的方括号语法在PHP中声明常量数组:
const FRUITS = [ "Watermelon", "Strawberries", "Pomegranate", "Blackberry", ];
示例
无法修改常量数组中的任何元素。因此,以下代码会抛出致命错误:
<?php const FRUITS = [ "Watermelon", "Strawberries", "Pomegranate", "Blackberry", ]; FRUITS[1] = "Mango"; ?>
它将产生以下输出:
PHP Fatal error: Cannot use temporary expression in write context
PHP 7及更高版本中的常量数组
较新版本的PHP允许您使用define()函数声明常量数组。
<?php define ('FRUITS', [ "Watermelon", "Strawberries", "Pomegranate", "Blackberry", ]); print_r(FRUITS); ?>
它将产生以下输出:
Array ( [0] => Watermelon [1] => Strawberries [2] => Pomegranate [3] => Blackberry )
您也可以在这里使用array()函数声明常量数组。
define ('FRUITS', array( "Watermelon", "Strawberries", "Pomegranate", "Blackberry", ));
示例
也可以声明关联常量数组。以下是一个示例:
<?php define ('CAPITALS', array( "Maharashtra" => "Mumbai", "Telangana" => "Hyderabad", "Gujarat" => "Gandhinagar", "Bihar" => "Patna" )); print_r(CAPITALS); ?>
它将产生以下输出:
Array ( [Maharashtra] => Mumbai [Telangana] => Hyderabad [Gujarat] => Gandhinagar [Bihar] => Patna )
PHP 函数
与大多数编程语言一样,PHP中的函数是一块组织良好的可重用代码块,用于执行单个相关的操作。函数为您的应用程序提供更好的模块化和高度的代码重用性。
PHP通过定义独立的可重用函数块来安排处理逻辑,从而支持结构化编程方法。这种方法的主要优点是代码变得易于理解、开发和维护。
下图显示了工资计算过程如何被逐步分解成独立且可重用的函数。
函数类型
您已经看到了许多函数,例如fopen()和fread()等。它们是内置函数,但PHP也允许您创建自己的函数。PHP中有两种类型的函数:
内置函数 - PHP的标准库包含大量用于字符串处理、文件IO、数学计算等的内置函数。
用户定义函数 - 您也可以创建用户定义函数,以满足编程逻辑的要求。
可以通过传递所需数据(称为参数或自变量)从任何其他函数调用函数。被调用的函数将其结果返回给调用环境。
您应该清楚以下两部分:
创建PHP函数
调用PHP函数
事实上,您几乎不需要创建自己的PHP函数,因为已经有超过1000个针对不同领域的内置库函数,您只需要根据您的需求调用它们。
请参考PHP函数参考以获取完整的实用函数集。
PHP中的用户定义函数
创建自己的PHP函数非常容易。让我们从一个简单的示例开始,然后我们将详细说明它是如何工作的。假设您想创建一个PHP函数,当您调用它时,它会在您的浏览器上显示一条简单的消息。
示例
在这个例子中,我们创建一个名为writeMessage()的函数,然后调用它来打印一条简单的消息:
<?php /* Defining a PHP Function */ function writeMessage() { echo "You are really a nice person, Have a nice time!"; } /* Calling a PHP Function */ writeMessage(); ?>
它将产生以下输出:
You are really a nice person, Have a nice time!
在PHP中创建函数
现在让我们详细了解这个过程。第一步是编写一个函数,然后您可以根据需要多次调用它。要创建一个新的函数,请使用function关键字,后跟您可能想要使用的函数名称。在名称前面,加上一个括号,它可以包含也可以不包含参数。后面是一个由花括号分隔的语句块。此函数块包含每次调用函数时要执行的语句。
定义函数的一般语法如下:
function foo($arg_1, $arg_2, $arg_n) { statements; return $retval; }
如果函数旨在将某些结果返回给调用环境,则函数块中应该有一个return语句作为最后一条语句。return语句不是必需的,即使没有它,程序流程也会返回到调用者,尽管没有携带任何值。
任何有效的PHP代码都可能出现在函数内部,甚至包括其他函数和类定义。函数的名称必须遵循与形成变量名称相同的规则。它应该以字母或下划线开头,后跟任意数量的字母、数字或下划线。
这是一个简单的PHP函数。每当调用时,它都会显示消息“Hello World”。
function sayhello() { echo "Hello World"; }
在PHP中调用函数
定义函数后,可以从PHP代码中的任何位置多次调用它。请注意,函数不会自动调用。要调用函数,请在语句中使用其名称;函数名称后跟一个分号。
<?php # define a function function sayhello(){ echo "Hello World"; } # calling the function sayhello(); ?>
它将产生以下输出:
Hello World
假设上述脚本“hello.php”位于PHP服务器的文档根目录下,打开浏览器并输入URL为https://127.0.0.1/hello.php。你应该会在浏览器窗口中看到“Hello World”消息。
在这个例子中,函数的定义没有参数也没有返回值。在接下来的章节中,我们将学习如何定义和传递参数,以及如何使函数返回一些值。此外,还将详细解释PHP函数的一些高级特性,例如递归函数、按值调用函数与按引用调用函数等。
PHP 函数参数
PHP中的函数可以定义为接受一个或多个参数。函数参数是在定义函数时,函数名前括号内用逗号分隔的表达式列表。参数可以是任何标量类型(数字、字符串或布尔值)、数组、对象,甚至是另一个函数。
function foo($arg_1, $arg_2, $arg_n) { statements; return $retval; }
参数充当在函数体内部处理的变量。因此,它们遵循与任何普通变量相同的命名约定,即它们应该以“$”开头,并且可以包含字母、数字和下划线。
注意 - 对可以定义的参数数量没有限制。
当需要调用一个带参数的函数时,你必须确保传递给它的值的数量与函数定义中参数的数量相同。
foo(val1, val2, val_n);
一个定义了参数的函数可以产生一个动态变化的结果,这取决于传递的值。
示例
下面的代码包含了带有两个参数的addition()函数的定义,并显示了这两个数的和。运行时输出取决于传递给函数的两个值。
<?php function addition($first, $second) { $result = $first+$second; echo "First number: $first \n"; echo "Second number: $second \n"; echo "Addition: $result"; } addition(10, 20); $x=100; $y=200; addition($x, $y); ?>
它将产生以下输出:
First number: 10 Second number: 20 Addition: 30 First number: 100 Second number: 200 Addition: 300
形式参数和实际参数
有时术语参数(argument) 用于指代形参(parameter)。实际上,这两个术语有一定的区别。
形参是指在函数定义中使用的变量,而实参是指调用函数时传递给函数的值。
实参可以是字面量、变量或表达式。
函数定义中的形参也经常被称为形式参数,而传递的值被称为实际参数。
形式参数和实际参数的名称不必相同。实际参数的值按照从左到右的顺序赋值给对应的形式参数。
函数中定义的形式参数的数量和传递的实际参数的数量应该相同。
示例
当实际参数的数量少于形式参数的数量时,PHP会引发ArgumentCountError错误。但是,如果实际参数的数量多于形式参数的数量,则多余的实际参数将被忽略。
<?php function addition($first, $second) { $result = $first+$second; echo "First number: $first \n"; echo "Second number: $second \n"; echo "Addition: $result \n"; } # Actual arguments more than formal arguments addition(10, 20, 30); # Actual arguments fewer than formal arguments $x=10; $y=20; addition($x); ?>
它将产生以下输出:
First number: 10 Second number: 20 Addition: 30 PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function addition(), 1 passed in /home/cg/root/20048/main.php on line 16 and exactly 2 expected in /home/cg/root/20048/main.php:2
参数类型不匹配
PHP是一种动态类型的语言,因此在将实际参数的值复制给形式参数时,它不强制执行类型检查。但是,如果函数体内的任何语句试图执行特定数据类型不支持的特定操作,PHP会引发异常。
在上面的addition()函数中,假设传递的是数值参数。如果传递字符串参数,PHP不会有任何异议,但是执行加法的语句会遇到异常,因为"+"操作没有为字符串类型定义。
示例
请看以下示例:
<?php function addition($first, $second) { $result = $first+$second; echo "First number: $first \n"; echo "Second number: $second \n"; echo "Addition: $result"; } # Actual arguments are strings $x="Hello"; $y="World"; addition($x, $y); ?>
它将产生以下输出:
PHP Fatal error: Uncaught TypeError: Unsupported operand types: string + string in hello.php:5
但是,PHP是一种弱类型语言。它尽可能地尝试将变量转换为兼容的类型。因此,如果传递的值之一是数字的字符串表示,而第二个是数值变量,则PHP会将字符串变量转换为数值以执行加法运算。
示例
请看以下示例:
<?php function addition($first, $second) { $result = $first+$second; echo "First number: $first \n"; echo "Second number: $second \n"; echo "Addition: $result"; } # Actual arguments are strings $x="10"; $y=20; addition($x, $y); ?>
它将产生以下输出:
First number: 10 Second number: 20 Addition: 30
PHP - 按值调用
默认情况下,PHP使用“按值调用”机制将参数传递给函数。调用函数时,实际参数的值将被复制到函数定义的形式参数中。
在执行函数体期间,如果任何形式参数的值发生任何变化,则不会反映在实际参数中。
实际参数 - 在函数调用中传递的参数。
形式参数 - 在函数定义中声明的参数。
示例
让我们考虑一下下面代码中使用的函数 -
<?php function change_name($nm) { echo "Initially the name is $nm \n"; $nm = $nm."_new"; echo "This function changes the name to $nm \n"; } $name = "John"; echo "My name is $name \n"; change_name($name); echo "My name is still $name"; ?>
它将产生以下输出:
My name is John Initially the name is John This function changes the name to John_new My name is still John
在这个例子中,change_name()函数将_new附加到传递给它的字符串参数。但是,传递给它的变量的值在函数执行后保持不变。
实际上,形式参数充当函数的局部变量。这样的变量只能在其初始化的作用域内访问。对于一个函数,其由花括号“{ }”标记的主体是其作用域。此作用域内的任何变量都无法被外部代码访问。因此,对任何局部变量的操作都不会影响外部世界。
“按值调用”方法适用于使用传递给它的值的函数。它执行某些计算并返回结果,而无需更改传递给它的参数的值。
注意 - 任何执行公式类型计算的函数都是按值调用的示例。
示例
请看以下示例:
<?php function addFunction($num1, $num2) { $sum = $num1 + $num2; return $sum; } $x = 10; $y = 20; $num = addFunction($x, $y); echo "Sum of the two numbers is : $num"; ?>
它将产生以下输出:
Sum of the two numbers is : 30
示例
这是另一个按值传递参数调用函数的示例。该函数将接收到的数字加1,但这不会影响传递给它的变量。
<?php function increment($num) { echo "The initial value: $num \n"; $num++; echo "This function increments the number by 1 to $num \n"; } $x = 10; increment($x); echo "Number has not changed: $x"; ?>
它将产生以下输出:
The initial value: 10 This function increments the number by 1 to 11 Number has not changed: 10
PHP还支持在调用函数时传递变量的引用。我们将在下一章讨论它。
PHP 按引用传递
PHP默认使用“按值调用”机制将参数传递给函数。如果函数内的参数发生更改,则更改不会反映在函数外部。为了允许函数修改其参数,“按引用调用”机制必须被使用。
在PHP中,引用变量充当原始变量或宿主变量的“别名”,以便两者都可以读写单个值。换句话说,两个不同名称的变量可以访问相同的值,它们的行为就像它们是同一个变量一样。
下面的PHP脚本将有助于理解什么是引用。这里,$var是一个普通的字符串变量。我们将$var1声明为$var的引用,在后者后面附加“&”符号。
$var = "Hello"; $var1 = &$var;
当我们说$var1是$var的别名或引用时,这意味着它的值发生任何变化也会改变$var的值,反之亦然。
示例
下面的例子演示了“按引用调用”如何在PHP中工作 -
<?php $var = "Hello"; $var1 = &$var; $var1 = "Hello World"; echo "var=$var var1=$var1" . PHP_EOL; $var = "How are you?"; echo "var=$var var1=$var1" . PHP_EOL; ?>
它将产生以下输出:
var=Hello World var1=Hello World var=How are you? var1=How are you?
按引用调用PHP函数
要按引用调用函数,需要将形式参数名以“&”符号作为前缀声明。
function callref(&$arg1, &$arg2) { Statements; }
函数的调用与“按值调用”方法一样。
callref($x, $y);
当函数被调用时,$arg1成为$x的引用,$arg2成为$y的引用。
如果在函数体内部,$arg1或$arg2(或两者)的值发生变化,它也会导致$x和$y的值发生变化。
示例
让我们看下面的例子 -
<?php function change_name(&$nm) { echo "Initially the name is $nm" . PHP_EOL; $nm = $nm."_new"; echo "This function changes the name to $nm" . PHP_EOL; } $name = "John"; echo "My name is $name" . PHP_EOL; change_name($name); echo "My name now is $name" . PHP_EOL; ?>
变量$name传递给函数change_name()。引用变量&$nm成为其引用变量。$nm的任何变化都会反映在函数外部的$name中。
它将产生以下输出:
My name is John Initially the name is John This function changes the name to John_new My name now is John_new
交换两个变量
在下面的PHP代码中,我们通过按值传递参数来调用函数。该函数试图交换它们的值。
在函数内部,它们的值发生了变化,但是这个交换在函数执行后并没有反映在实际参数中。
当通过按引用传递参数调用相同的函数时,交换效果也会反映在实际参数中。
<?php function swap_value($a, $b) { echo "Initial values a = $a b = $b \n"; $c = $a; $a = $b; $b = $c; echo "Swapped values a = $a b = $b \n"; } $x = 10; $y =20; echo "Actual arguments x = $x y = $y \n\n"; swap_value($x, $y); echo "Actual arguments do not change after the function: \n"; echo "x = $x y = $y \n\n"; function swap_ref(&$a, &$b) { echo "Initial values a = $a b = $b \n"; $c = $a; $a = $b; $b = $c; echo "Swapped values a = $a b = $b \n"; } swap_ref($x, $y); echo "Actual arguments get changed after the function: \n"; echo "x = $x y = $y"; ?>
它将产生以下输出:
Actual arguments x = 10 y = 20 Initial values a = 10 b = 20 Swapped values a = 20 b = 10 Actual arguments do not change after the function: x = 10 y = 20 Initial values a = 10 b = 20 Swapped values a = 20 b = 10 Actual arguments get changed after the function: x = 20 y = 10
按引用返回
就像PHP中的函数可以按引用接受参数一样,它也可以返回引用。要定义一个返回引用的函数,请在函数名前添加“&”符号。
示例
下面的代码显示了一个返回引用的函数的示例。它返回$x,它是myfunction()内部的局部静态变量。由于“&”符号加在其前面,$a(存储返回值的变量)成为&x的引用。因此,$a的任何更改也会更改$x的值。
<?php function &myfunction(){ static $x=10; echo "x Inside function: $x \n"; return $x; } $a=&myfunction(); echo "Returned by Reference: $a \n"; $a=$a+10; $a=&myfunction(); ?>
它将产生以下输出:
x Inside function: 10 Returned by Reference: 10 x Inside function: 20
PHP 默认参数
与大多数支持命令式编程的语言一样,PHP中的函数可能有一个或多个具有默认值的参数。因此,这样的函数可以在不向其传递任何值的情况下被调用。如果没有要传递的值,则该函数将使用其默认值进行处理。如果函数调用提供了一个值,则默认值将被覆盖。
function fun($arg1 = val1, $arg2 = val2) { Statements; }
这样的函数可以以不同的方式调用 -
fun(); # Function will use defaults for both arguments fun($x); # Function passes $x to arg1 and uses default for arg2 fun($x, $y); # Both arguments use the values passed
示例 1
在这里,我们定义了一个名为greeting()的函数,它有两个参数,两者都具有string作为其默认值。我们通过传递一个字符串、两个字符串以及没有任何参数来调用它。
<?php function greeting($arg1="Hello", $arg2="world") { echo $arg1 . " ". $arg2 . PHP_EOL; } greeting(); greeting("Thank you"); greeting("Welcome", "back"); greeting("PHP"); ?>
它将产生以下输出:
Hello world Thank you world Welcome back PHP world
示例 2
你可以定义一个函数,其中只有一部分参数具有默认值,而其他参数必须传递值。
<?php function greeting($arg1, $arg2="World") { echo $arg1 . " ". $arg2 . PHP_EOL; } # greeting(); ## This will raise ArgumentCountError greeting("Thank you"); greeting("Welcome", "back"); ?>
它将产生以下输出:
Thank you World Welcome back
第一次调用(无参数)会引发ArgumentCountError,因为你必须为第一个参数传递值。如果只传递一个值,它将被列表中的第一个参数使用。
但是,如果你在没有默认值的参数之前声明具有default的参数,则只有在为两者都传递值的情况下才能调用该函数。你不能出现第一个参数使用默认值,而第二个使用传递的值的情况。
greeting()函数现在有带默认值的$arg1和没有任何默认值的$arg2。
function greeting($arg1="Hello", $arg2) { echo $arg1 . " ". $arg2 . PHP_EOL; }
如果你传递一个字符串“PHP” -
greeting("PHP");
并希望将结果打印为“Hello PHP”,则会显示以下错误消息。
PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function greeting(), 1 passed in hello.php on line 10 and exactly 2 expected
示例 3
让我们定义一个名为percent()的函数,该函数计算三门科目成绩的百分比。
假设每门科目的分数都是满分100分,则函数定义中的$total参数的默认值为300。
<?php function percent($p, $c, $m, $ttl=300) { $per = ($p+$c+$m)*100/$ttl; echo "Marks obtained: \n"; echo "Physics = $p Chemistry = $c Maths = $m \n"; echo "Percentage = $per \n"; } percent(50, 60, 70); ?>
它将产生以下输出:
Marks obtained: Physics = 50 Chemistry = 60 Maths = 70 Percentage = 60
但是,如果每门科目的最高分是50分,那么你必须向函数传递第四个值,否则百分比将根据300而不是150计算。
<?php function percent($p, $c, $m, $ttl=300) { $per = ($p+$c+$m)*100/$ttl; echo "Marks obtained: \n"; echo "Physics = $p Chemistry = $c Maths = $m \n"; echo "Percentage = $per \n"; } percent(30, 35, 40, 150); ?>
它将产生以下输出:
Marks obtained: Physics = 30 Chemistry = 35 Maths = 40 Percentage = 70
PHP 具名参数
命名参数的功能是在PHP 8.0版本中引入的。它是现有机制的扩展,该机制在调用时将位置参数传递给函数。
默认情况下,传递的参数的值将复制到相同位置的相应形式参数。PHP的命名参数功能使得可以根据参数名称而不是位置传递值。
如果我们定义如下函数 -
function myfunction($x, $y) { statement1; statement2; . . . }
并调用它为 -
myfunction(10, 20);
在这种情况下,值按照声明的顺序传递给变量“x”和“y”。这意味着,第一个值传递给第一个参数,第二个值传递给第二个参数,依此类推。“x”和“y”是位置参数。
要按命名参数传递值,请指定要将值传递到的参数名称。参数的名称是形式参数的名称,没有“$”符号。要传递的值放在“:”符号的前面。
myfunction(x:10, y:20);
示例
以下代码演示了如何在PHP中使用命名参数 -
<?php function myfunction($x, $y) { echo "x = $x y = $y"; } myfunction(x:10, y:20); ?>
它将产生以下输出:
x = 10 y = 20
使用命名参数可以按任何顺序传递值,而不必按照函数定义中声明参数的顺序传递。我们可以像下面这样调用myfunction(),它将产生相同的结果。
myfunction(y:20, x:10);
有了这个特性,参数就变得与顺序无关并且具有自文档性。它还可以任意跳过具有默认值的参数。
将命名参数与位置参数组合
命名参数可以与位置参数组合,条件是命名参数必须放在位置参数之后。
示例
<?php function myfunction($x, $y, $z) { echo "x = $x y = $y z = $z"; } myfunction(10, z:20, y:30); ?>
它将产生以下输出:
x = 10 y = 30 z = 20
但是,如果你尝试将$z视为位置参数,
myfunction(x:10, y:20, 30);
在这种情况下,PHP会遇到以下错误 -
PHP Fatal error: Cannot use positional argument after named argument in hello.php on line 7
从数组中传递命名参数
PHP 8.1.0 还引入了另一个特性,允许在解包参数后使用命名参数。无需为每个参数单独提供值,可以使用“...”(三个点)在数组前将数组中的值解包到相应的参数中。
示例
<?php function myfunction($x, $y, $z=30) { echo "x = $x y = $y z = $z"; } myfunction(...[10, 20], z:30); ?>
它将产生以下输出:
x = 10 y = 20 z = 30
请注意,多次传递相同的参数会导致如下异常:
myfunction(x:10, z:20, x:20);
错误:
PHP Fatal error: Uncaught Error: Named parameter $x overwrites previous argument in hello.php:7
PHP 可变参数
在 PHP 中,可以编写一个函数,该函数能够接受元素数量可变的参数列表。要声明可变参数列表,参数名前要加上“...”(三个点)符号。传递的值将收集到一个数组中,数组名与参数名相同。
function myfunction(...$arg) { Statement1; Statement2; }
要调用此类函数,请在括号中放入任意数量用逗号分隔的值。
myfunction(v1, v2, v3, . . . , vn);
函数中声明的形式参数是所有传递值的一个数组。我们可以使用任何合适的内置数组函数来执行此过程。
示例
在下面的示例中,用户定义的函数myfunction()能够接收可变数量的值并计算它们的平均值。
<?php function myfunction(...$numbers) { $avg = array_sum($numbers)/count($numbers); return $avg; } $avg = myfunction(5, 12, 9, 23, 8); echo "average = $avg"; ?>
它将产生以下输出:
average = 11.4
尝试更改传递数组的大小并再次运行程序。
您可以使用foreach循环遍历函数内的数组。函数在可变长度参数之前可以有任何位置参数。从接收到的值中,将首先填充位置参数,其余参数将复制到数组中。
示例
<?php function myfunction($x, ...$numbers) { echo "First number: $x" . PHP_EOL; echo "Remaining numbers: "; foreach ($numbers as $n) { echo "$n "; } } myfunction(5, 12, 9, 23, 8, 41); ?>
它将产生以下输出:
First number: 5 Remaining numbers: 12 9 23 8 41
可变参数函数
即使没有“...”语法,也可以处理传递给函数的可变数量的参数。PHP 具有内置函数,如 func_num_args()、func_get_arg() 和 func_get_args(),这些函数可以获得类似的结果。
func_num_args():返回传递给函数的参数个数。
func_get_arg():返回参数列表中的一个项目。
func_get_args():返回包含函数参数列表的数组。
示例
上面的可变参数示例可以使用这些函数改写如下:
<?php function myfunction() { $sum = 0; foreach (func_get_args() as $n) { $sum += $n; } return $sum; } echo myfunction(5, 12, 9, 23, 8, 41); ?>
它将产生以下输出:
98
示例
此程序打印传递给函数的所有数字:
<?php function myfunction() { $len = func_num_args(); echo "Numbers : "; $i=0; for ($i=0; $i<$len; $i++) echo func_get_arg($i) . " "; } myfunction(5, 12, 9, 23, 8, 41); ?>
它将产生以下输出:
Numbers : 5 12 9 23 8 41
PHP 返回值
PHP 函数可以在其函数体的最后一个语句中使用可选的 return 语句。大多数 PHP 内置函数都会返回某个值。例如,strlen() 函数返回字符串的长度。类似地,用户定义的函数也可以返回某个值。
函数是一个独立的、完整的和可重用的语句块。调用时,它执行某个任务并将程序控制权返回到调用它的位置,即使没有使用 return 语句也是如此。return 语句允许它将值和控制权一起返回到调用环境。
function foo($arg_1, $arg_2) { statements; return $retval; }
函数可以返回任何类型的数据,包括标量变量、数组和对象。没有表达式在前的 return 关键字返回 null,这等效于函数根本没有返回值。
函数返回的值可以存储在变量中,可以放在表达式中,或者如果出现在 print 或 echo 中,则显示在输出中。
$res = foo($x, $y);
它允许在程序中进一步使用函数的返回值。
示例
让我们修改上一章中的 addition() 函数,使其包含一个return语句以返回加法的结果。
<?php function addition($first, $second) { $result = $first+$second; return $result; } $x=10; $y=20; $z = addition($x, $y); echo "First number: $x Second number: $y Addition: $z". PHP_EOL; ?>
它将产生以下输出:
First number: 10 Second number: 20 Addition: 30
PHP 中的函数可以有任意数量的参数,但只能返回一个值。函数一旦遇到第一个return语句,就会立即返回到调用环境,放弃函数体中其余的语句。
示例
如果尝试在return语句中包含多个值,则会遇到 PHP 解析错误,如下所示:
<?php function raiseto($x) { $sqr = $x**2; $cub = $x**3; return $sqr, $cub; } $a = 5; $val = raiseto($a); ?>
它将产生以下输出:
PHP Parse error: syntax error, unexpected token ",", expecting ";"
条件返回
您可以根据不同的条件语句执行多个return语句。
示例
在下面的程序中,raiseto()函数返回数字的平方或立方,取决于索引参数是 2 还是 3。
<?php function raiseto($x, $i) { if ($i == 2) { return $x**2; } elseif ($i==3) { return $x**3; } } $a = 5; $b = 2; $val = raiseto($a, $b); echo "$a raised to $b = $val" . PHP_EOL; $x = 7; $y = 3; echo "$x raised to $y = " . raiseto($x, $y) . PHP_EOL; ?>
它将产生以下输出:
5 raised to 2 = 25 7 raised to 3 = 343
将多个值作为数组返回
PHP 中的函数只能返回单个值。但是,此单个值可以是包含多个值的数组。我们可以利用此特性同时返回数字的平方和立方。
示例
请看以下示例:
<?php function raiseto($x){ $sqr = $x**2; $cub = $x**3; $ret = ["sqr" => $sqr, "cub" => $cub]; return $ret; } $a = 5; $val = raiseto($a); echo "Square of $a: " . $val["sqr"] . PHP_EOL; echo "Cube of $a: " . $val["cub"] . PHP_EOL; ?>
它将产生以下输出:
Square of 5: 25 Cube of 5: 125
PHP 传递函数
除了标量类型、数组和对象之外,还可以将函数作为参数传递给 PHP 中的函数。如果定义的函数接受另一个函数作为参数,则将在函数内部调用传递的函数。PHP 的标准库具有一些此类型的内置函数,其中一个要传递的参数是函数,该函数可以是另一个内置函数,甚至是用户定义的函数。
array_map
array_map() 是内置函数之一。此函数的第一个参数是回调函数。可能还有其他参数作为其他数组。回调函数将应用于所有数组元素。
array_map(?callable $callback, array $array, array ...$arrays): array
array_map() 函数返回一个数组。它包含将回调函数应用于作为其他参数传递的数组的对应元素的结果。
示例
在下面的示例中,我们有一个 square() 函数,它计算传递给它的数字的平方。此函数又用作 array_map() 函数的参数,以及另一个数字数组。每个数字依次传递给 squares() 函数。结果数组是平方列表。
<?php function square($number) { return $number * $number; } $arr = [1, 2, 3, 4, 5]; $squares = array_map('square', $arr); var_dump($squares); ?>
它将产生以下输出:
array(5) { [0]=> int(1) [1]=> int(4) [2]=> int(9) [3]=> int(16) [4]=> int(25) }
call_user_func
将函数传递给另一个函数的另一个示例是 call_user_func()。顾名思义,它调用另一个用户定义的回调函数,并将其他参数传递给回调函数。
call_user_func(callable $callback, mixed ...$args): mixed
示例
在下面的示例中,square() 函数被重复调用,将数组中的每个数字传递给它。
<?php function square($number) { return $number * $number; } $arr = [1, 2, 3, 4, 5]; foreach($arr as $a) { echo "square of $a:" . call_user_func("square", $a). PHP_EOL; } ?>
它将产生以下输出:
square of 1:1 square of 2:4 square of 3:9 square of 4:16 square of 5:25
usort
作为传递函数的另一个示例,我们来看一下 usort() 函数。
usort(array &$array, callable $callback): true
第一个参数是数组。数组根据回调函数排序,回调函数是第二个参数。
回调参数是一个比较函数,如果第一个参数分别小于、等于或大于第二个参数,则必须返回小于、等于或大于零的整数。
示例
这是一个示例。首先,我们有一个mysort()函数。它比较两个数字,如果第一个数字小于、等于或大于第二个数字,则返回“-1”、“0”或“1”。
usort()的第一个参数是 mysort() 函数,第二个参数是数组。首先,将前两个数字传递给 mysort()。如果它返回 1,则交换它们。接下来,传递第二个和第三个数字,如果比较返回 1,则交换它们。该过程重复进行,以便数组元素按升序排列。
<?php function mysort($a, $b) { if ($a == $b) { return 0; } return ($a < $b) ? -1 : 1; } $a = array(3, 2, 5, 6, 1); usort($a, "mysort"); foreach ($a as $key => $value) { echo "$key: $value\n"; } ?>
它将产生以下输出:
0: 1 1: 2 2: 3 3: 5 4: 6
将回调传递给用户定义的函数
除了上述内置函数之外,您还可以定义自己的函数,该函数接受一个参数作为另一个函数。
在下面的示例中,我们有两个函数 square() 和 cube(),它们分别返回给定数字的平方和立方。
接下来,是myfunction(),它的第一个参数用作变量函数,第二个参数传递给它。
因此,myfunction() 在内部调用 square() 或 cube() 以返回给定数字的平方或立方。
示例
<?php function myfunction($function, $number) { $result = $function($number); return $result; } function cube($number) { return $number ** 2; } function square($number) { return $number ** 3; } $x = 5; $cube = myfunction('cube', $x); $square = myfunction('square', $x); echo "Square of $x = $square" . PHP_EOL; echo "Cube of $x = $cube" . PHP_EOL; ?>
它将产生以下输出:
Square of 5 = 125 Cube of 5 = 25
PHP 递归函数
递归函数是这样一种函数,它会调用自身,直到满足某个条件。在 PHP 中,可以定义递归函数。
当某个问题用自身来定义时,就会使用递归。
有时,使用迭代方法解决问题可能会很繁琐。递归方法为看似复杂的问题提供了一种非常简洁的解决方案。
PHP 中的递归与 C 和 C++ 中的递归非常相似。
递归函数尤其用于遍历嵌套数据结构以及搜索或排序算法。
二叉树遍历、堆排序和查找最短路径是一些使用递归的情况。
使用递归计算阶乘
递归最流行的示例是阶乘的计算。从数学上讲,阶乘定义为:
n! = n × (n-1)!
可以看出,我们使用阶乘本身来定义阶乘。因此,这是一个编写递归函数的合适案例。
让我们展开上述定义,计算 5 的阶乘值。
5! = 5 × 4! 5 × 4 × 3! 5 × 4 × 3 × 2! 5 × 4 × 3 × 2 × 1! 5 × 4 × 3 × 2 × 1 = 120
虽然我们可以使用循环执行此计算,但其递归函数会通过递减数字直到达到 1 来连续调用它。
示例
以下是计算阶乘的递归函数。
<?php function factorial ($n) { if ($n == 1) { echo $n . PHP_EOL; return 1; } else { echo "$n * "; return $n*factorial($n-1); } } echo "Factorial of 5 = " . factorial(5); ?>
它将产生以下输出:
5 * 4 * 3 * 2 * 1 Factorial of 5 = 120
使用递归进行二分查找
让我们再看一个示例,了解递归是如何工作的。手头的问题是检查给定数字是否存在于列表中。
虽然我们可以使用for循环并比较每个数字来对列表中的某个数字进行顺序搜索,但顺序搜索效率不高,尤其是在列表过大的情况下。在这里,我们可以使用二分查找算法,该算法检查索引“high”是否大于索引“low”。根据“mid”变量中存在的值,再次调用函数来搜索元素。
我们有一个按升序排列的数字列表。然后,我们找到列表的中点,并根据所需数字是否小于或大于中点处的数字,将检查限制在中点的左侧或右侧。
下图显示了二分查找的工作原理:
示例
以下代码实现了递归二分搜索技术:
<?php function bsearch($my_list, $low, $high, $elem) { if ($high >= $low) { $mid = intval(($high + $low)/2); if ($my_list[$mid] == $elem) return $mid; elseif ($my_list[$mid] > $elem) return bsearch($my_list, $low, $mid - 1, $elem); else return bsearch($my_list, $mid + 1, $high, $elem); } else return -1; } $list = [5,12,23, 45, 49, 67, 71, 77, 82]; $num = 67; $result = bsearch($list,0,count($list)-1, $num); if ($result != -1) echo " Number $num found at index " . $result; else echo "Element not found!"; ?>
它将产生以下输出:
Number 67 found at index 5
您可以检查给定列表中存在的不同数字以及列表中不存在的数字的输出。
PHP 类型提示
PHP 支持在声明函数定义中的变量以及类中的属性或实例变量时使用“类型提示”。PHP 被广泛认为是一种弱类型语言。在 PHP 中,无需在为变量赋值之前声明变量的类型。
PHP 解析器会尽最大努力将变量强制转换为兼容类型。因此,如果传递的值之一是数字的字符串表示形式,而第二个是数字变量,则 PHP 会将字符串变量强制转换为数字以执行加法运算。
示例
请看以下示例:
<?php function addition($x, $y) { echo "First number: $x Second number: $y Addition: " . $x+$y; } $x="10"; $y=20; addition($x, $y); ?>
它将产生以下输出:
First number: 10 Second number: 20 Addition: 30
但是,如果上面的示例中的$x是一个不包含有效数字表示的字符串,则会遇到错误。
<?php function addition($x, $y) { echo "First number: $x Second number: $y Addition: " . $x+$y; } $x="Hello"; $y=20; addition($x, $y); ?>
它将产生以下输出:
PHP Fatal error: Uncaught TypeError: Unsupported operand types: string + int in hello.php:5
从 PHP 5.6 版本开始支持类型提示。这意味着您可以明确声明代码中声明的变量的预期类型。PHP 允许您对函数参数、返回值和类属性进行类型提示。有了它,就可以编写更健壮的代码了。
让我们在上面的程序中的 addition 函数中加入类型提示:
function addition($x, $y) { echo "First number: $x Second number: $y Addition: " . $x+$y; }
类型提示功能主要由 IDE(集成开发环境)使用,以提示用户函数声明中使用的参数的预期类型。
下图显示了 VS Code 编辑器在您键入时弹出的函数原型:
如果鼠标悬停在函数名称上,则会显示参数和返回值的类型声明:
请注意,仅仅在变量声明中使用数据类型并不能防止引发不匹配类型异常,因为 PHP 是一种动态类型语言。换句话说,$x="10" 和 $y=20 仍然会将结果加起来为 30,而 $x="Hello" 会使解析器引发错误。
strict_types
可以使 PHP 对类型转换施加更严格的规则,以便不会将“10”隐式转换为 10。这可以通过在 declare() 语句中将 strict_types 指令设置为 1 来强制执行。declare() 语句必须是 PHP 代码中的第一个语句,紧跟在“<?php”标签之后。
示例
<?php declare (strict_types=1); function addition(int $x, int $y) { echo "First number: $x Second number: $y Addition: " . $x+$y; } $x=10; $y=20; addition($x, $y); ?>
它将产生以下输出:
First number: 10 Second number: 20 Addition: 30
现在,如果将$x设置为“10”,则不会进行隐式转换,从而导致以下错误:
PHP Fatal error: Uncaught TypeError: addition(): Argument #1 ($x) must be of type int, string given
VS Code IDE 也指示了相同效果的错误:
从 PHP 7 开始,类型提示支持已扩展到函数返回,以防止出现意外的返回值。您可以通过在参数列表后添加预期类型(在冒号 (:) 符号前缀)来对返回值进行类型提示。
示例
让我们为上面加法函数的返回值添加类型提示。
<?php declare (strict_types=1); function addition(int $x, int $y) : int { return $x+$y; } $x=10; $y=20; $result = addition($x, $y); echo "First number: $x Second number: $y Addition: " . $result; ?>
同样,如果发现函数返回的值不是整数,IDE 甚至在运行之前就会指出原因。
联合类型
PHP 从 8.0 版本开始引入联合类型。现在可以为单个声明指定多个类型。数据类型用“|”符号分隔。
示例
在下面 addition() 函数的定义中,$x 和 $y 参数可以是 int 或 float 类型。
<?php declare (strict_types=1); function addition(int|float $x, int|float $y) : float { return $x+$y; } $x=10.55; $y=20; $result = addition($x, $y); echo "First number: $x Second number: $y Addition: " . $result; ?>
类中的类型提示
在 PHP 中,从 7.4 版本开始,可以在类属性和方法的声明中使用类型提示。
示例
在下面的示例中,类构造函数使用了类型提示。
<?php declare (strict_types=1); class Student { public $name; public $age; public function __construct(string $name, int $age) { $this->name = $name; $this->age = $age; } public function dispStudent() { echo "Name: $this->name Age: $this->age"; } } $s1 = new Student("Amar", 21); $s1->dispStudent(); ?>
也可以在类属性的声明中使用类型提示。
class Student { public string $name; public int $age; public function __construct($name, $age) { $this->name = $name; $this->age = $age; } public function dispStudent() { echo "Name: $this->name Age: $this->age"; } }
程序开发中最常见的错误是类型错误。类型提示功能有助于减少此类错误。
PHP 变量作用域
在 PHP 中,变量的作用域是指其定义的上下文以及可访问的范围。通常,一个简单的顺序 PHP 脚本(没有任何循环或函数等)只有一个作用域。在 "<?php" 和 "?>" 标签内声明的任何变量,从定义点开始都可以在整个程序中使用。
根据作用域,PHP 变量可以是以下三种类型之一:
主脚本中的变量也可以提供给使用 include 或 require 语句包含的任何其他脚本。
示例
在下面的示例中,"test.php" 脚本包含在主脚本中。
main.php
<?php $var=100; include "test.php"; ?>
test.php
<?php echo "value of \$var in test.php : " . $var; ?>
执行主脚本时,将显示以下输出:
value of $var in test.php : 100
但是,当脚本具有用户定义的函数时,内部的任何变量都具有局部作用域。因此,在函数内部定义的变量无法在外部访问。在函数外部(上方)定义的变量具有全局作用域。
示例
请看以下示例:
<?php $var=100; // global variable function myfunction() { $var1="Hello"; // local variable echo "var=$var var1=$var1" . PHP_EOL; } myfunction(); echo "var=$var var1=$var1" . PHP_EOL; ?>
它将产生以下输出:
var= var1=Hello var=100 var1= PHP Warning: Undefined variable $var in /home/cg/root/64504/main.php on line 5 PHP Warning: Undefined variable $var1 in /home/cg/root/64504/main.php on line 8
注意,全局变量不会自动在函数的局部作用域中可用。同样,函数内部的变量在外部也无法访问。
"global" 关键字
要在函数的局部作用域内访问全局变量,应使用"global"关键字显式执行此操作。
示例
PHP 脚本如下:
<?php $a=10; $b=20; echo "Global variables before function call: a = $a b = $b" . PHP_EOL; function myfunction() { global $a, $b; $c=($a+$b)/2; echo "inside function a = $a b = $b c = $c" . PHP_EOL; $a=$a+10; } myfunction(); echo "Variables after function call: a = $a b = $b c = $c"; ?>
它将产生以下输出:
Global variables before function call: a = 10 b = 20 inside function a = 10 b = 20 c = 15 Variables after function call: a = 20 b = 20 c = PHP Warning: Undefined variable $c in /home/cg/root/48499/main.php on line 12
现在可以在函数内处理全局变量。此外,在函数内对全局变量所做的任何更改都将反映在全局命名空间中。
$GLOBALS 数组
PHP 将所有全局变量存储在一个名为 $GLOBALS 的关联数组中。变量的名称和值构成键值对。
示例
在下面的 PHP 脚本中,使用 $GLOBALS 数组访问全局变量:
<?php $a=10; $b=20; echo "Global variables before function call: a = $a b = $b" . PHP_EOL; function myfunction() { $c=($GLOBALS['a']+$GLOBALS['b'])/2; echo "c = $c" . PHP_EOL; $GLOBALS['a']+=10; } myfunction(); echo "Variables after function call: a = $a b = $b c = $c"; ?>
它将产生以下输出:
Global variables before function call: a = 10 b = 20 c = 15 PHP Warning: Undefined variable $c in C:\xampp\htdocs\hello.php on line 12 Variables after function call: a = 20 b = 20 c =
静态变量
使用 static 关键字定义的变量不会在每次调用函数时都进行初始化。此外,它保留上次调用的值。
示例
请看以下示例:
<?php function myfunction() { static $x=0; echo "x = $x" . PHP_EOL; $x++; } for ($i=1; $i<=3; $i++) { echo "call to function :$i : "; myfunction(); } ?>
它将产生以下输出:
call to function :1 : x = 0 call to function :2 : x = 1 call to function :3 : x = 2
PHP 严格类型
PHP 被广泛认为是一种弱类型语言。在 PHP 中,不需要在为变量赋值之前声明其类型。PHP 解析器会尽最大可能将变量强制转换为兼容的类型。
例如,如果传递的值之一是数字的字符串表示形式,而第二个是数值变量,则 PHP 会将字符串变量强制转换为数字以执行加法运算。
示例
请看以下示例:
<?php function addition($x, $y) { echo "First number: $x Second number: $y Addition: " . $x+$y; } $x="10"; $y=20; addition($x, $y); ?>
它将产生以下输出:
First number: 10 Second number: 20 Addition: 30
但是,如果上面示例中的 $x 是一个不包含有效数字表示的字符串,则会遇到错误。
<?php function addition($x, $y) { echo "First number: $x Second number: $y Addition: " . $x+$y; } $x="Hello"; $y=20; addition($x, $y); ?>
它将产生以下输出:
PHP Fatal error: Uncaught TypeError: Unsupported operand types: string + int in hello.php:5
类型提示
从 PHP 5.6 版本开始支持类型提示。这意味着您可以明确声明代码中声明的变量的预期类型。PHP 允许您对函数参数、返回值和类属性进行类型提示。有了它,就可以编写更健壮的代码了。
让我们在上面的程序中的 addition 函数中加入类型提示:
function addition(int $x, int $y) { echo "First number: $x Second number: $y Addition: " . $x+$y; }
请注意,仅仅在变量声明中使用数据类型并不能防止引发不匹配类型异常,因为 PHP 是一种动态类型语言。换句话说,$x="10" 和 $y=20 仍然会将结果相加为 30,而 $x="Hello" 会导致解析器引发错误。
示例
<?php function addition($x, $y) { echo "First number: $x \n"; echo "Second number: $y \n"; echo "Addition: " . $x+$y . "\n\n"; } $x=10; $y=20; addition($x, $y); $x="10"; $y=20; addition($x, $y); $x="Hello"; $y=20; addition($x, $y); ?>
它将产生以下输出:
First number: 10 Second number: 20 Addition: 30 First number: 10 Second number: 20 Addition: 30 First number: Hello Second number: 20 PHP Fatal error: Uncaught TypeError: Unsupported operand types: string + int in hello.php:5
strict_types
可以通过将 strict_types 指令在 declare() 语句中设置为 1 来强制 PHP 对类型转换实施更严格的规则,以便不会将 "10" 隐式转换为 10。
declare() 语句必须是 PHP 代码中的第一条语句,紧跟在 "<?php" 标签之后。
示例
请看以下示例:
<?php declare (strict_types=1); function addition(int $x, int $y) { echo "First number: $x Second number: $y Addition: " . $x+$y; } $x=10; $y=20; addition($x, $y); ?>
它将产生以下输出:
First number: 10 Second number: 20 Addition: 30
现在,如果将 $x 设置为 "10",则不会进行隐式转换,从而导致以下错误:
PHP Fatal error: Uncaught TypeError: addition(): Argument #1 ($x) must be of type int, string given
从 PHP 7 开始,类型提示支持已扩展到函数返回,以防止出现意外的返回值。可以通过在参数列表后添加预期类型(以冒号 (:) 符号为前缀)来提示返回类型。
示例
让我们为下面的 division() 函数的返回值添加类型提示。
<?php declare (strict_types=1); function division(int $x, int $y) : int { return $x/$y; } $x=10; $y=20; $result = division($x, $y); echo "First number: $x Second number: $y Addition: " . $result; ?>
因为函数返回 0.5,它不是 int 类型(即函数返回值使用的类型提示),所以会显示以下错误:
Fatal error: Uncaught TypeError: division(): Return value must be of type int, float returned in hello.php:5
PHP 匿名函数
什么是匿名函数?
PHP 允许定义匿名函数。通常,当我们在 PHP 中定义函数时,我们通常会为其提供一个名称,该名称用于在需要时调用函数。相反,匿名函数是在定义时没有指定任何名称的函数。此类函数也称为闭包或lambda 函数。
有时,您可能只需要一个一次性使用的函数。匿名函数最常见的用途是创建内联回调函数。
匿名函数使用 Closure 类实现。Closure 是一个匿名函数,它封闭在其定义的环境中。
定义匿名函数的语法如下:
$var=function ($arg1, $arg2) { return $val; };
请注意,在 function 关键字和左括号之间没有函数名,并且函数定义之后有一个分号。这意味着匿名函数定义是表达式。当分配给变量时,可以使用变量的名称稍后调用匿名函数。
示例
请看以下示例:
<?php $add = function ($a, $b) { return "a:$a b:$b addition: " . $a+$b; }; echo $add(5,10); ?>
它将产生以下输出:
a:5 b:10 addition: 15
匿名函数作为回调
匿名函数通常用作回调。回调函数用作另一个函数的参数之一。匿名函数会动态执行,其返回值成为父函数的参数,父函数可以是内置函数或用户定义函数。
示例
在此示例中,我们在 usort() 函数内使用匿名函数,这是一个内置函数,它使用用户定义的比较函数按值对数组进行排序。
<?php $arr = [10,3,70,21,54]; usort ($arr, function ($x , $y) { return $x > $y; }); foreach ($arr as $x){ echo $x . "\n"; } ?>
它将产生以下输出:
3 10 21 54 70
示例
以下示例使用匿名函数计算数组中连续数字后的累积和。在这里,我们使用 array_walk() 函数。此函数将用户定义的函数应用于数组中的每个元素。
<?php $arr=array(1,2,3,4,5); array_walk($arr, function($n){ $s=0; for($i=1;$i<=$n;$i++){ $s+=$i; } echo "Number: $n Sum: $s". PHP_EOL; }); ?>
它将产生以下输出:
Number: 1 Sum: 1 Number: 2 Sum: 3 Number: 3 Sum: 6 Number: 4 Sum: 10 Number: 5 Sum: 15
匿名函数作为闭包
闭包也是一个匿名函数,它可以在"use"关键字的帮助下访问其作用域之外的变量。
示例
请看下面的例子:
<?php $maxmarks=300; $percent=function ($marks) use ($maxmarks) { return $marks*100/$maxmarks; }; $m = 250; echo "Marks = $m Percentage = ". $percent($m); ?>
它将产生以下输出:
Marks = 250 Percentage = 83.333333333333
PHP 箭头函数
箭头函数是在 PHP 7.4 版本中引入的。箭头函数提供了一种更简单、更简洁的语法来编写匿名函数。使用 PHP 7.4,引入了关键字"fn"来定义箭头函数,而不是传统上使用"function"关键字。
fn (argument_list) => expr
"=>" 符号之后只有一个表达式,其值为箭头函数的返回值。
箭头函数没有显式的 return 语句。
与匿名函数一样,箭头函数被分配给一个变量以便调用它。
示例
以下示例演示如何在 PHP 中使用箭头函数:
<?php $add = fn ($a, $b) => $a + $b; $x = 10; $y = 20; echo " x: $x y: $y Addition: " . $add($x, $y); ?>
它将产生以下输出:
x: 10 y: 20 Addition: 30
使用箭头函数作为回调函数
我们也可以使用箭头函数作为回调函数。回调函数用作另一个函数的参数之一。箭头函数会动态执行,"=>" 之后表达式的值成为父函数的参数,父函数可以是内置函数或用户定义函数。
示例
在此示例中,我们在 usort() 函数内使用箭头函数,这是一个内置函数,它使用用户定义的比较函数按值对数组进行排序。
<?php $arr = [10,3,70,21,54]; usort ($arr, fn ($x , $y) => $x > $y); foreach ($arr as $x){ echo $x . "\n"; } ?>
它将产生以下输出:
3 10 21 54 70
访问父作用域中的变量
箭头函数可以自动访问父作用域中的变量。与匿名函数不同,不需要 "use" 关键字即可充当闭包。当表达式中使用的变量在父作用域中定义时,它将被隐式按值捕获。
<?php $maxmarks=300; $percent=fn ($marks) => $marks*100/$maxmarks; $m = 250; echo "Marks = $m Percentage = ". $percent($m); ?>
它将产生以下输出:
Marks = 250 Percentage = 83.333333333333
示例
箭头函数会自动按值捕获变量,即使嵌套也是如此。
在下面的示例中,箭头函数在另一个箭头函数的表达式部分中定义。
<?php $z = 1; $fn = fn($x) => fn($y) => $x * $y + $z; $x = 5; $y = 10; echo "x:$x y:$y \n"; echo "Result of nested arrow functions: " . ($fn($x)($y)); ?>
它将产生以下输出:
x:5 y:10 Result of nested arrow functions: 51
与匿名函数一样,箭头函数语法允许任意函数签名,包括参数和返回类型、默认值、可变参数,以及按引用传递和返回。
PHP 变量处理函数
PHP 变量处理函数是内置的 PHP 库函数,使我们能够以各种方式操作和测试 php 变量。
安装
使用 PHP 变量处理函数不需要安装;它们是 PHP 核心的一部分,并随标准 PHP 安装一起提供。
运行时配置
此扩展程序在php.ini中没有定义任何配置指令。
PHP 变量处理函数
下表列出了所有与 PHP 变量处理相关的函数。此处“版本”列指示支持该函数的 PHP 最早版本。
序号 | 函数及描述 | 版本 |
---|---|---|
1 | boolval()
函数返回已定义变量的布尔值,即返回 TRUE 或 FALSE。 |
5.5.0 |
2 | debug_zval_dump()
函数用于将内部 zend 值的字符串表示形式转储到输出。 |
4.2.0 |
3 | doubleval()
函数用于返回已定义变量的浮点值。 |
4, 5, 7, 8 |
4 | empty()
函数用于检查已定义变量的值是否为空。 |
4, 5, 7, 8 |
5 | floatval()
函数用于返回已定义变量的浮点值。 |
4.2.0, 5, 7, 8 |
6 | get_defined_vars()
函数用于将所有已定义变量作为数组返回。 |
4.0.4, 5, 7, 8 |
7 | get_resource_id()
函数用于返回给定资源的整数标识符。 |
8 |
8 | get_resource_type()
函数返回已定义变量资源的类型。 |
4.0.2, 5, 7, 8 |
9 | gettype()
函数返回已定义变量的类型。 |
4, 5, 7, 8 |
10 | intval()
函数返回已定义变量的整数值。 |
4, 5, 7, 8 |
11 | is_array()
函数用于检查已定义变量是否为数组。 |
4, 5, 7, 8 |
12 | is_bool()
函数用于检查已定义变量是否为布尔值,即返回 true 或 false 值。 |
4, 5, 7, 8 |
13 | is_callable()
函数用于检查变量中的数据是否可以作为函数调用。 |
4.0.6, 5, 7, 8 |
14 | is_countable()
函数用于检查变量中的数据是否可计数。 |
7.3.0, 8 |
15 | is_double()
函数用于检查已定义变量的类型是否为浮点型。 |
4, 5, 7, 8 |
16 | is_float()
该函数用于检查定义的变量是否为浮点数。 |
4, 5, 7, 8 |
17 | is_int()
该函数用于检查定义的变量是否为整数类型。 |
4, 5, 7, 8 |
18 | is_integer()
该函数用于检查定义的变量是否为整数。 |
4, 5, 7, 8 |
19 | is_iterable()
该函数用于检查变量中的数据是否为可迭代值。 |
7.1.0, 8 |
20 | is_long()
该函数用于检查变量是否为整数类型。 |
4, 5, 7, 8 |
21 | is_null()
该函数检查变量是否具有NULL值。 |
4.0.4, 5, 7, 8 |
22 | is_numeric()
该函数用于检查定义的变量是否为数字或数字字符串。 |
4, 5, 7, 8 |
23 | is_object()
该函数用于检查变量是否为对象。 |
4, 5, 7, 8 |
24 | is_real()
该函数用于检查定义的变量是否为浮点数。 |
4, 5, 7, 8 |
25 | is_resource()
该函数用于检查定义的变量是否为资源。 |
4, 5, 7, 8 |
26 | is_scalar()
该函数用于检查定义的变量是否为标量。 |
4.0.5, 5, 7, 8 |
27 | is_string()
该函数用于检查定义的变量是否为字符串类型。 |
4, 5, 7, 8 |
28 | isset()
该函数用于检查变量是否已声明并已设置值。 |
4, 5, 7, 8 |
29 | print_r()
该函数用于以可读的格式显示或打印变量的数据。 |
4, 5, 7, 8 |
30 | serialize()
该函数用于将变量的数据转换为可存储的表示形式,以便数据可以存储在文件或内存缓冲区中。 |
4, 5, 7, 8 |
31 | settype()
该函数用于将变量设置为特定类型。 |
4, 5, 7, 8 |
32 | strval()
该函数用于返回变量的字符串值。 |
4, 5, 7, 8 |
33 | unserialize()
该函数用于反序列化变量的数据,即该函数返回序列化变量的实际数据。 |
4, 5, 7, 8 |
34 | unset()
该函数用于取消设置变量。 |
4, 5, 7, 8 |
35 | var_dump()
该函数用于转储一个或多个变量的信息。信息包含变量的类型和值。 |
4, 5, 7, 8 |
36 | var_export()
该函数返回关于变量的结构化信息。 |
4.2.0, 5, 7, 8 |
PHP 局部变量
作用域可以定义为变量在其声明的程序中具有的可用范围。PHP 变量可以是四种作用域类型之一:
- 局部变量
- 全局变量
- 静态变量
- 函数参数
局部变量
在函数中声明的变量被认为是局部变量;也就是说,它只能在该函数中引用。在该函数之外的任何赋值都将被视为与函数中包含的变量完全不同的变量。
<?php $x = 4; function assignx () { $x = 0; print "\$x inside function is $x. \n"; } assignx(); print "\$x outside of function is $x."; ?>
这将产生以下结果:
$x inside function is 0. $x outside of function is 4.
PHP 全局变量
在PHP中,任何可以在PHP脚本中的任何地方访问的变量都被称为**全局变量**。如果变量在脚本中的所有函数或类之外声明,则它成为全局变量。
虽然全局变量可以直接在函数外部访问,但它们不会自动在函数内部可用。
示例
在下面的脚本中,**$name**对于函数**sayhello()**是全局的。
<?php $name = "Amar"; function sayhello() { echo "Hello " . $name; } sayhello(); ?>
但是,该变量在函数内部不可访问。因此,您将收到**错误消息**“未定义变量 $name”。
Hello PHP Warning: Undefined variable $name in /home/cg/root/93427/main.php on line 5
示例
要在函数内访问它,需要在变量前使用“global”关键字。
<?php $name = "Amar"; function sayhello() { GLOBAL $name; echo "Hello " . $name; } sayhello(); ?>
它将产生以下输出:
Hello Amar
如果函数访问全局变量并修改它,则在函数调用完成后,修改后的值在任何地方都可用。
让我们在**sayhello()**函数内部更改**$name**的值,并在函数调用后检查其值。
示例
看一下下面的例子 -
<?php $name = "Amar"; function sayhello() { GLOBAL $name; echo "Global variable name: $name" .PHP_EOL; $name = "Amarjyot"; echo "Global variable name changed to: $name" .PHP_EOL; } sayhello(); echo "Global variable name after function call: $name" .PHP_EOL; ?>
它将产生以下输出:
Global variable name: Amar Global variable name changed to: Amarjyot Global variable name after function call: Amarjyot
$GLOBALS 数组
PHP维护一个名为**$GLOBALS**的关联数组,其中包含在全局范围内声明的所有变量及其值。$GLOBALS数组还存储许多称为超级全局变量的预定义变量以及用户定义的全局变量。
任何全局变量也可以在任何函数内部使用访问数组元素的常规语法访问。例如,全局变量**$name**的值由**$GLOBALS["name"]**给出。
示例
在下面的示例中,两个全局变量 $x 和 $y 在 addition() 函数内部被访问。
<?php $x = 10; $y = 20; function addition() { $z = $GLOBALS['x']+$GLOBALS['y']; echo "Addition: $z" .PHP_EOL; } addition(); ?>
它将产生以下输出:
Addition: 30
示例
您还可以通过将任何局部变量添加到 $GLOBALS 数组中来将其添加到全局作用域中。让我们将**$z**添加到全局作用域。
<?php $x = 10; $y = 20; function addition() { $z = $GLOBALS['x']+$GLOBALS['y']; $GLOBALS['z'] = $z; } addition(); echo "Now z is the global variable. Addition: $z" .PHP_EOL; ?>
它将产生以下输出:
Now z is the global variable. Addition: 30
在一个PHP脚本中包含另一个PHP脚本
你可以在一个PHP脚本中包含另一个PHP脚本。在包含的脚本中声明的变量将添加到包含它的PHP脚本的全局作用域中。
这是“a.php”文件:
<?php include 'b.php'; function addition() { $z = $GLOBALS['x']+$GLOBALS['y']; echo "Addition: $z" .PHP_EOL; } addition(); ?>
它包含具有**$x**和**$y**变量的“b.php”,因此它们成为“a.php”脚本中**addition()**函数的全局变量。
<?php $x = 10; $y = 20; ?>
全局变量通常在实现单例模式、访问嵌入式系统中的寄存器以及许多函数使用一个变量时使用。
PHP 超全局变量
PHP解析器在其全局命名空间中填充当前脚本的许多预定义变量。预定义变量被称为“**PHP超级全局变量**”。
任何在任何函数、方法或类之外声明的用户定义变量也是全局变量。但是,要访问它,需要使用**global**关键字。
相反,**超级全局变量**始终可以在PHP脚本中的任何地方使用,无需使用**global**关键字。
PHP中的大多数超级全局变量都是关联数组,由Web服务器填充。因此,如果脚本在命令行环境中运行,一些超级全局变量可能为空。
PHP中超级全局变量的列表包括以下内容:
$GLOBALS
$_SERVER
$_GET
$_POST
$_FILES
$_COOKIE
$_SESSION
$_REQUEST
$_ENV
本章将简要介绍PHP中的这些超级全局变量。在后续章节中,我们将详细讨论这些超级全局变量。
$GLOBALS
这是一个对所有全局定义变量的引用的关联数组。变量名构成键,其内容是关联数组的值。
$_SERVER
所有服务器和执行环境相关信息都包含在这个关联数组中。
5.4.0之前的PHP版本包含$HTTP_SERVER_VARS包含相同的信息,但现在已被删除。
$_GET
这是一个关联数组,通过附加到HTTP请求URL的查询字符串传递给当前脚本的变量。请注意,除了GET请求外,所有带有查询字符串的请求都会填充该数组。
查询字符串是所有变量及其值的列表,其形式为var=val,并由“&”符号连接。
查询字符串本身附加在“?”符号后的PHP脚本名称之后。例如,**https://127.0.0.1/hello.php?first_name=Amar&last_name=Sharma**。
$_POST
这是一个键值对的关联数组,通过使用**URLEncoded**或**multipart/form-data**内容类型的HTTP POST方法传递到URL。
$HTTP_POST_VARS也包含与$_POST相同的信息,但它不是超级全局变量,现在已被弃用。向服务器发送POST请求数据的最简单方法是将HTML表单的method属性指定为POST。
$_FILES
$_FILES变量是一个关联数组,包含通过HTTP POST方法上传的项目。当HTML表单包含一个文件类型的输入元素,其enctype属性设置为multipart/form-data,并且method属性设置为HTTP POST方法时,将上传文件。
$_COOKIE
Cookie是服务器存储在客户端计算机上的文本文件,它们用于跟踪目的。
超级全局变量$_COOKIE存储与HTTP请求一起传递给当前PHP脚本的变量,形式为cookie。
$_SESSION
HTTP会话是用户与服务器建立连接的时间和连接终止的时间之间的时间段。在此期间,一些数据以会话变量的形式跨页面持久可用。
$_SESSION超级全局变量是当前脚本可用的会话变量的关联数组。
$_REQUEST
$_REQUEST是一个关联数组,它是$_GET、$_POST和$_COOKIE变量内容的集合。
这些变量的顺序由“php.ini”文件中**requests_order**和**variables_order**设置的值决定。
$_ENV
$_ENV是一个关联数组,存储当前脚本可用的所有环境变量。如果PHP作为服务器模块或CGI处理器运行,此数组还包括CGI变量。
PHP $GLOBALS
$GLOBALS是PHP中的“**超级全局变量**”或“**自动全局变量**”之一。它在整个脚本的所有范围内都可用。无需执行“**global $variable;**”即可在函数或方法中访问它。
$GLOBALS是对所有全局定义变量的引用的关联数组。变量名构成键,其内容是关联数组的值。
示例
此示例显示$GLOBALS数组包含全局变量的名称和内容:
<?php $var1="Hello"; $var2=100; $var3=array(1,2,3); echo $GLOBALS["var1"] . "\n"; echo $GLOBALS["var2"] . "\n"; echo implode($GLOBALS["var3"]) . "\n"; ?>
它将产生以下输出:
Hello 100 123
示例
在下面的示例中,**$var1**在全局命名空间以及函数内的局部变量中定义。全局变量是从$GLOBALS数组中提取的。
<?php function myfunction() { $var1="Hello PHP"; echo "var1 in global namespace: " . $GLOBALS['var1']. "\n"; echo "var1 as local variable: ". $var1; } $var1="Hello World"; myfunction(); ?>
它将产生以下输出:
var1 in global namespace: Hello World var1 as local variable: Hello PHP
示例
在PHP 8.1.0之前,全局变量可以通过$GLOBALS数组的副本进行修改。
<?php $a = 1; $globals = $GLOBALS; $globals['a'] = 2; var_dump($a); ?>
它将产生以下输出:
int(1)
这里,**$globals**是$GLOBALS超级全局变量的副本。将副本中的元素(其键为“a”)更改为2,实际上会更改**$a**的值。
它将产生以下输出:
int(2)
示例
从PHP 8.1.0开始,$GLOBALS是全局符号表的只读副本。也就是说,不能通过其副本修改全局变量。与上述相同的操作不会将**$a**更改为2。
<?php $a = 1; $globals = $GLOBALS; $globals['a'] = 2; var_dump($a); ?>
它将产生以下输出:
int(1)
PHP $_SERVER
$_SERVER是PHP中的超级全局变量。它包含有关HTTP标头、路径和脚本位置等信息。
$_SERVER是一个关联数组,它包含所有服务器和执行环境相关信息。
此关联数组中的大多数条目都由Web服务器填充。条目可能因Web服务器而异,因为服务器可能会省略一些条目,或提供其他条目。
对于在命令行上运行的PHP脚本,大多数这些条目将不可用或没有任何意义。
PHP还将使用请求标头中的值创建其他元素。这些条目的名称将为“HTTP_”,后跟标头名称,大写,并使用下划线而不是连字符。
例如,“Accept-Language”标头将作为$_SERVER['HTTP_ACCEPT_LANGUAGE']提供。
5.4.0之前的PHP版本包含`$HTTP_SERVER_VARS`,其中包含相同的信息,但现在已被移除。
下表列出了一些重要的$_SERVER数组服务器变量及其值的描述。
序号 | 服务器变量及描述 |
---|---|
1 | PHP_SELF 存储当前正在执行脚本的文件名。 |
2 | SERVER_ADDR 此数组属性返回当前脚本正在执行的服务器的IP地址。 |
3 | SERVER_NAME 当前脚本正在执行的服务器主机名。如果服务器在本地运行,则返回localhost。 |
4 | QUERY_STRING 查询字符串是由“&”符号分隔的键值对字符串,附加在“?”符号后的URL之后。 例如,https://127.0.0.1/testscript?name=xyz&age=20 URL返回尾随查询字符串 |
5 | REQUEST_METHOD 用于访问URL的HTTP请求方法,例如POST、GET、PUT或DELETE。 在上例查询字符串中,附加到带有“?”符号的查询字符串的URL使用GET方法请求页面。 |
6 | DOCUMENT_ROOT 返回服务器上配置为文档根目录的目录名。 在XAMPP Apache服务器上,它返回**htdocs**作为文档根目录c:/xampp/htdocs的名称。 |
7 | REMOTE_ADDR 用户查看当前页面的机器的IP地址。 |
8 | SERVER_PORT Web服务器侦听传入请求的端口号。默认为80。 |
示例
从XAMPP服务器的文档根目录调用的以下脚本列出了所有服务器变量:
<?php foreach ($_SERVER as $k=>$v) echo $k . "=>" . $v . "\n"; ?>
它将产生以下输出:
MIBDIRS=>C:/xampp/php/extras/mibs MYSQL_HOME=>\xampp\mysql\bin OPENSSL_CONF=>C:/xampp/apache/bin/openssl.cnf PHP_PEAR_SYSCONF_DIR=>\xampp\php PHPRC=>\xampp\php TMP=>\xampp\tmp HTTP_HOST=>localhost HTTP_CONNECTION=>keep-alive HTTP_SEC_CH_UA=>"Chromium";v="116", "Not) A;Brand";v="24", "Google Chrome";v="116" HTTP_SEC_CH_UA_MOBILE=>?0 HTTP_SEC_CH_UA_PLATFORM=>"Windows" HTTP_DNT=>1 HTTP_UPGRADE_INSECURE_REQUESTS=>1 HTTP_USER_AGENT=>Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 HTTP_ACCEPT=>text/html,application/xhtml+xml,application/xml; q=0.9,image/avif,image/webp,image/apng,*/*; q=0.8,application/signed-exchange;v=b3;q=0.7 HTTP_SEC_FETCH_SITE=>none HTTP_SEC_FETCH_MODE=>navigate HTTP_SEC_FETCH_USER=>?1 HTTP_SEC_FETCH_DEST=>document HTTP_ACCEPT_ENCODING=>gzip, deflate, br HTTP_ACCEPT_LANGUAGE=>en-US,en;q=0.9,mr;q=0.8 PATH=>C:\Python311\Scripts\; C:\Python311\;C:\WINDOWS\system32; C:\WINDOWS;C:\WINDOWS\System32\Wbem; C:\WINDOWS\System32\WindowsPowerShell\v1.0\; C:\WINDOWS\System32\OpenSSH\;C:\xampp\php; C:\Users\user\AppData\Local\Microsoft\WindowsApps; C:\VSCode\Microsoft VS Code\bin SystemRoot=>C:\WINDOWS COMSPEC=>C:\WINDOWS\system32\cmd.exe PATHEXT=>.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW WINDIR=>C:\WINDOWS SERVER_SIGNATURE=> Apache/2.4.56 (Win64) OpenSSL/1.1.1t PHP/8.0.28 Server at localhost Port 80 SERVER_SOFTWARE=>Apache/2.4.56 (Win64) OpenSSL/1.1.1t PHP/8.0.28 SERVER_NAME=>localhost SERVER_ADDR=>::1 SERVER_PORT=>80 REMOTE_ADDR=>::1 DOCUMENT_ROOT=>C:/xampp/htdocs REQUEST_SCHEME=>http CONTEXT_PREFIX=> CONTEXT_DOCUMENT_ROOT=>C:/xampp/htdocs SERVER_ADMIN=>postmaster@localhost SCRIPT_FILENAME=>C:/xampp/htdocs/hello.php REMOTE_PORT=>54148 GATEWAY_INTERFACE=>CGI/1.1 SERVER_PROTOCOL=>HTTP/1.1 REQUEST_METHOD=>GET QUERY_STRING=> REQUEST_URI=>/hello.php SCRIPT_NAME=>/hello.php PHP_SELF=>/hello.php REQUEST_TIME_FLOAT=>1694802456.9816 REQUEST_TIME=>1694802456
PHP $_REQUEST
在PHP中,`$_REQUEST`是一个超级全局变量。它是一个关联数组,包含`$_GET`、`$_POST`和`$_COOKIE`变量的内容。
“php.ini”文件中的设置决定了此变量的组成。
“php.ini”中的一个指令是**request_order**,它决定PHP注册GET、POST和COOKIE变量的顺序。
此数组中列出的变量的存在和顺序根据PHP的**variables_order**定义。
如果从命令行运行PHP脚本,则`$_REQUST`数组中不包含**argc**和**argv**变量,因为它们的值取自`$_SERVER`数组,而`$_SERVER`数组又由Web服务器填充。
使用GET方法的$_REQUEST
将以下脚本保存到Apache服务器的文档文件夹中。如果您在Windows上使用XAMPP服务器,请将脚本作为“hello.php”放在“c:/xampp/htdocs”文件夹中。
<html> <body> <?php echo "<h3>First Name: " . $_REQUEST['first_name'] . "<br />" . "Last Name: " . $_REQUEST['last_name'] . "</h3>"; ?> </body> </html>
启动XAMPP服务器,并在浏览器窗口中输入**https://127.0.0.1/hello.php?first_name=Amar&last_name=Sharma**作为URL。
您应该获得以下**输出**:
使用POST方法的$_REQUEST
在文档根目录下,将以下脚本保存为“hello.html”。
<html> <body> <form action="hello.php" method="post"> First Name: <input type="text" name="first_name" /> <br /> Last Name: <input type="text" name="last_name" /> <input type="submit" value="Submit" /> </form> </body> </html>
在浏览器中,输入URL“https://127.0.0.1/hello.html”。您应该在浏览器窗口中获得类似的**输出**。
您也可以将PHP代码嵌入HTML脚本中,并使用PHP_SELF变量将表单POST到自身:
<html> <body> <form action="<?php echo $_SERVER['PHP_SELF'];?>" method="post"> <p>First Name: <input type="text" name="first_name" /></p> <p>Last Name: <input type="text" name="last_name" /></p> <input type="submit" value="Submit" /> </form> <?php if ($_SERVER["REQUEST_METHOD"] == "POST") echo "<h3>First Name: " . $_REQUEST['first_name'] . "<br />" . "Last Name: " . $_REQUEST['last_name'] . "</h3>"; ?> </body> </html>
它将产生以下输出:
PHP $_POST
`$_POST`是PHP中预定义的或超级全局变量之一。它是一个键值对的关联数组,通过使用URLEncoded或multipart/form-data内容类型的HTTP POST方法传递到URL。
`$HTTP_POST_VARS`也包含与`$_POST`相同的信息,但它不是超级全局变量,现在已被弃用。
使用POST请求向服务器发送数据的最简单方法是将HTML表单的**method属性**指定为**POST**。
假设浏览器中的URL是“https://127.0.0.1/hello.php”,则在下面的HTML表单“hello.html”中设置method=POST:
<html> <body> <form action="hello.php" method="post"> <p>First Name: <input type="text" name="first_name"/> </p> <p>Last Name: <input type="text" name="last_name" /> </p> <input type="submit" value="Submit" /> </form> </body> </html>
此练习的“hello.php”脚本(位于文档根目录文件夹中)如下所示:
<?php echo "<h3>First name: " . $_POST['first_name'] . "<br /> " . "Last Name: " . $_POST['last_name'] . "</h3>"; ?>
现在,在浏览器中打开**https://127.0.0.1/hello.html**。您应该在屏幕上看到以下输出:
当您按下**提交**按钮时,数据将使用POST方法提交到“hello.php”。
您也可以在hello.php中混合HTML表单和PHP代码,并使用“PHP_SELF”变量将表单数据发布到自身:
<html> <body> <form action="<?php echo $_SERVER['PHP_SELF'];?>" method="post"> <p>First Name: <input type="text" name="first_name"/> </p> <br /> <p>Last Name: <input type="text" name="last_name" /></p> <input type="submit" value="Submit" /> </form> <?php echo "<h3>First Name: " . $_POST['first_name'] . "<br /> " . "Last Name: " . $_POST['last_name'] . "</h3>"; ?> </body> </html>
它将产生以下输出:
PHP $_GET
`$_GET`是PHP中的超级全局变量之一。它是通过附加到HTTP请求URL的查询字符串传递给当前脚本的变量的关联数组。请注意,除了GET请求外,所有带有查询字符串的请求都会填充此数组。
`$HTTP_GET_VARS`包含相同的信息,但现在已被弃用。
默认情况下,客户端浏览器使用HTTP GET方法向服务器发送URL请求。附加到URL的查询字符串可能包含由“&”符号连接的键值对。`$_GET`关联数组存储这些键值对。
将以下脚本保存到Apache服务器的文档文件夹中。如果您在Windows上使用XAMPP服务器,请将脚本作为“hello.php”放在“c:/xampp/htdocs”文件夹中。
<?php echo "<h3>First Name: " . $_REQUEST['first_name'] . "<br />" . "Last Name: " . $_REQUEST['last_name'] . "</h3>"; ?>
启动XAMPP服务器,并在浏览器窗口中输入“https://127.0.0.1/hello.php?first_name=Mukesh&last_name=Sinha”作为URL。您应该获得以下**输出**:
`$_GET`数组在HTML表单数据使用GET方法提交到URL时也会被填充。
在文档根目录下,将以下脚本保存为“**hello.html**”:
<html> <body> <form action="hello.php" method="get"> <p>First Name: <input type="text" name="first_name"/></p> <p>Last Name: <input type="text" name="last_name" /></p> <input type="submit" value="Submit" /> </form> </body> </html>
在浏览器中,输入URL“**https://127.0.0.1/hello.html**”:
您应该在浏览器窗口中获得类似的**输出**:
在下面的例子中,`htmlspecialchars()`用于将字符转换为HTML实体:
字符 |
替换 |
---|---|
& (与号) |
& |
" (双引号) |
" |
' (单引号) |
' 或 ' |
< (小于号) |
< |
> (大于号) |
> |
假设浏览器中的URL是“https://127.0.0.1/hello.php?name=Suraj&age=20”:
<?php echo "Name: " . htmlspecialchars($_GET["name"]) . ""; echo "Age: " . htmlspecialchars($_GET["age"]) . "<br/>"; ?>
它将产生以下输出:
Name: Suraj Age: 20
PHP $_FILES
`$_FILES`是PHP中的“超级全局”或自动全局变量之一。它在整个脚本的所有范围内都可用。`$_FILES`变量是一个关联数组,包含通过HTTP POST方法上传的项目。
当HTML表单包含一个文件类型的输入元素、其enctype属性设置为multipart/form-data以及method属性设置为HTTP POST方法时,将上传文件。
`$HTTP_POST_FILES`也包含相同的信息,但它不是超级全局变量,现在已被弃用。
下面的HTML脚本包含一个表单,其中包含**文件**类型的**输入**元素:
<input type="file" name="file">
此“input type”呈现一个标题为文件的按钮。单击时,会弹出一个文件对话框。您可以选择要上传的文件。
服务器上的PHP脚本可以在`$_FILES`变量中访问文件数据。
`$_FILES`数组包含以下属性:
**`$_FILES['file']['name']`** - 用户选择上传的文件的原始名称。
**`$_FILES['file']['type']`** - 文件的MIME类型。例如“image/gif”。但是,此MIME类型不会在PHP端进行检查。
**`$_FILES['file']['size']`** - 上传文件的以字节为单位的大小。
**`$_FILES['file']['tmp_name']`** - 上传文件在服务器上存储的临时文件名。
**`$_FILES['file']['full_path']`** - 浏览器提交的完整路径。从PHP 8.1.0开始可用。
**`$_FILES['file']['error']`** - 与此文件上传相关的错误代码。
**错误代码**如下所示:
错误代码 | 描述 |
---|---|
UPLOAD_ERR_OK (值=0) |
没有错误,文件上传成功。 |
UPLOAD_ERR_INI_SIZE (值=1) |
上传的文件超过了php.ini中的upload_max_filesize指令。 |
UPLOAD_ERR_FORM_SIZE (值=2) |
上传的文件超过了MAX_FILE_SIZE。 |
UPLOAD_ERR_PARTIAL (值=3) |
上传的文件仅部分上传。 |
UPLOAD_ERR_NO_FILE (值=4) |
没有上传文件。 |
UPLOAD_ERR_NO_TMP_DIR (值=6) |
缺少临时文件夹。 |
UPLOAD_ERR_CANT_WRITE (值=7) |
无法将文件写入磁盘。 |
UPLOAD_ERR_EXTENSION (值=8) |
PHP扩展阻止了文件上传。 |
示例
下面的“test.html”包含一个HTML表单,其enctype设置为multiform/form-data。它还包含一个input file元素,该元素在表单上呈现一个按钮,供用户选择要上传的文件。将此文件保存到Apache服务器的文档根目录文件夹中。
<html> <body> <form action="hello.php" method="POST" enctype="multipart/form-data"> <p><input type="file" name="file"></p> <p><input type ="submit" value="submit"></p> </form> </body> </html>
上面的HTML在浏览器窗口中呈现一个名为“选择文件”的按钮。要打开文件对话框,请单击“选择文件”按钮。当所选文件的名称出现后,单击**提交**按钮。
示例
文档根目录文件夹中的服务器端PHP脚本(**upload.php**)读取`$_FILES`数组变量如下:
<?php echo "Filename: " . $_FILES['file']['name']."<br>"; echo "Type : " . $_FILES['file']['type'] ."<br>"; echo "Size : " . $_FILES['file']['size'] ."<br>"; echo "Temp name: " . $_FILES['file']['tmp_name'] ."<br>"; echo "Error : " . $_FILES['file']['error'] . "<br>"; ?>
它将产生以下输出:
Filename: abc.txt Type : text/plain Size : 556762 Temp name: C:\xampp\tmp\phpD833.tmp Error : 0
示例
在PHP中,您可以使用HTML数组功能上传多个文件:
<html> <body> <form action="hello.php" method="POST" enctype="multipart/form-data"> <input type="file" name="files[]"/> <input type="file" name="files[]"/> <input type ="submit" value="submit"/> </form> </body> </html>
现在,将PHP脚本(**hello.php**)更改为:
<?php foreach ($_FILES["files"]["name"] as $key => $val) { echo "File uploaded: $val <br>"; } ?>
浏览器将显示多个“选择文件”按钮。上传所选文件后,单击“提交”按钮,浏览器将显示响应URL **https://127.0.0.1/hello.html**的文件名称,如下所示:
PHP $_ENV
**`$_ENV`**是PHP中的超级全局变量。它是一个关联数组,存储当前脚本中可用的所有环境变量。**`$HTTP_ENV_VARS`**也包含相同的信息,但它不是超级全局变量,现在已被弃用。
环境变量被导入到全局命名空间。大多数这些变量由运行PHP解析器的shell提供。因此,环境变量列表在不同的平台上可能不同。
如果PHP作为服务器模块或CGI处理器运行,则此数组(`$_ENV`)还包含CGI变量。
我们可以使用**foreach**循环来显示所有可用的环境变量:
<?php foreach ($_ENV as $k=>$v) echo $k . " => " . $v . "<br>"; ?>
在Windows操作系统和XAMPP服务器上,您可能会获得如下所示的环境变量列表:
变量 |
值 |
---|---|
ALLUSERSPROFILE |
C:\ProgramData |
APPDATA |
C:\Users\user\AppData\Roaming |
CommonProgramFiles |
C:\Program Files\Common Files |
CommonProgramFiles(x86) |
C:\Program Files (x86)\Common Files |
CommonProgramW6432 |
C:\Program Files\Common Files |
COMPUTERNAME |
GNVBGL3 |
ComSpec |
C:\WINDOWS\system32\cmd.exe |
DriverData |
C:\Windows\System32\Drivers\DriverData |
HOMEDRIVE |
C: |
HOMEPATH |
\Users\user |
LOCALAPPDATA |
C:\Users\user\AppData\Local |
LOGONSERVER |
\\GNVBGL3 |
MOZ_PLUGIN_PATH |
C:\Program Files (x86)\ Foxit Software\ Foxit PDF Reader\plugins\ |
NUMBER_OF_PROCESSORS |
8 |
OneDrive |
C:\Users\user\OneDrive |
OneDriveConsumer |
C:\Users\user\OneDrive |
OS |
Windows_NT |
Path |
C:\Python311\Scripts\; C:\Python311\; C:\WINDOWS\system32; C:\WINDOWS; C:\WINDOWS\System32\Wbem; C:\WINDOWS\System32\WindowsPowerShell\ v1.0\; C:\WINDOWS\System32\OpenSSH\; C:\xampp\php; C:\Users\user\AppData\Local\Microsoft\ WindowsApps; C:\VSCode\Microsoft VS Code\bin |
PATHEXT |
.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE; .WSF;.WSH;.MSC;.PY;.PYW |
PROCESSOR_ARCHITECTURE |
AMD64 |
PROCESSOR_IDENTIFIER |
Intel64 Family 6 Model 140 Stepping 1, GenuineIntel |
PROCESSOR_LEVEL |
6 |
PROCESSOR_REVISION |
8c01 |
ProgramData |
C:\ProgramData |
ProgramFiles |
C:\Program Files |
ProgramFiles(x86) |
C:\Program Files (x86) |
ProgramW6432 |
C:\Program Files |
PSModulePath |
C:\Program Files\WindowsPowerShell\Modules; C:\WINDOWS\system32\WindowsPowerShell\v1.0\ Modules |
PUBLIC |
C:\Users\Public |
SystemDrive |
C: |
SystemRoot |
C:\WINDOWS |
TEMP |
C:\Users\user\AppData\Local\Temp |
TMP |
C:\Users\user\AppData\Local\Temp |
USERDOMAIN |
GNVBGL3 |
USERDOMAIN_ROAMINGPROFILE |
GNVBGL3 |
USERNAME |
user |
USERPROFILE |
C:\Users\user |
windir |
C:\WINDOWS |
ZES_ENABLE_SYSMAN |
1 |
__COMPAT_LAYER |
RunAsAdmin Installer |
AP_PARENT_PID |
10608 |
您也可以访问单个环境变量的值。此代码获取PATH环境变量:
<?php echo "Path: " . $_ENV['Path']; ?>
它将产生以下输出:
Path: C:\Python311\Scripts\;C:\Python311\;C:\WINDOWS\system32; C:\WINDOWS;C:\WINDOWS\System32\Wbem; C:\WINDOWS\System32\WindowsPowerShell\v1.0\; C:\WINDOWS\System32\OpenSSH\;C:\xampp\php; C:\Users\mlath\AppData\Local\Microsoft\WindowsApps; C:\VSCode\Microsoft VS Code\bin
**注意** - `$_ENV`数组可能产生空结果,这取决于“php.ini”设置“variables_order”。您可能需要编辑“php.ini”文件并将**variables_order="EGPCS"**设置为**variables_order="GPCS"**值。
getenv()函数
PHP库提供`getenv()`函数来检索所有环境变量的列表或特定环境变量的值。
下面的脚本显示所有可用的环境变量的值。
<?php $arr=getenv(); foreach ($arr as $key=>$val) echo "$key=>$val"; ?>
要获取特定变量的值,请使用其名称作为 getenv() 函数的参数。
<?php echo "Path: " . getenv("PATH"); ?>
putenv() 函数
PHP 还提供 putenv() 函数来创建新的环境变量。环境变量仅在当前请求期间存在。
应避免更改某些环境变量的值。默认情况下,用户只能设置以“PHP_”开头的环境变量(例如 PHP_FOO=BAR)。
"php.ini" 中的 "safe_mode_protected_env_vars" 指令包含一个逗号分隔的环境变量列表,最终用户将无法使用 putenv() 更改这些变量。
<?php putenv("PHP_TEMPUSER=GUEST"); echo "Temp user: " . getenv("PHP_TEMPUSER"); ?>
浏览器将显示以下输出:
Temp user: GUEST
PHP $_COOKIE
PHP 超全局变量 $_COOKIE 存储传递给当前 PHP 脚本以及 HTTP 请求的 cookie 形式的变量。$HTTP_COOKIE_VARS 也包含相同的信息,但它不是超全局变量,现在已被弃用。
什么是 Cookie?
Cookie 是服务器存储在客户端计算机上的文本文件,用于跟踪目的。PHP 透明地支持 HTTP Cookie。Cookie 通常在 HTTP 标头中设置。JavaScript 也可以直接在浏览器上设置 Cookie。
服务器脚本向浏览器发送一组 Cookie。它将此信息存储在本地机器上以备将来使用。下次浏览器向 Web 服务器发送任何请求时,它会将这些 Cookie 信息发送到服务器,服务器使用这些信息来识别用户。
setcookie() 函数
PHP 提供setcookie 函数来创建一个 Cookie 对象,以便与 HTTP 响应一起发送到客户端。
setcookie(name, value, expire, path, domain, security);
参数
名称 - 存储的 Cookie 名称。
值 - 这设置命名变量的值。
过期时间 - 这指定自 1970 年 1 月 1 日 00:00:00 GMT 以来的秒数。
路径 - Cookie 有效的目录。
域名 - 在非常大的域名中指定域名。
安全性 - HTTPS 为 1。常规 HTTP 默认值为 0。
如何设置 Cookie
请查看以下示例。如果尚未设置名为username 的 Cookie,则此脚本会设置它。
示例
<?php if (isset($_COOKIE['username'])) { echo "<h2>Cookie username already set: " . $_COOKIE['username'] . "</h2>"; } else { setcookie("username", "Mohan Kumar"); echo "<h2>Cookie username is now set.</h2>"; } ?>
从 Apache 服务器的文档根目录运行此脚本。您应该会看到此消息作为输出:
Cookie username is now set
如果重新执行此脚本,则 Cookie 现在已设置。
Cookie username already set: Mohan Kumar
示例
要在客户端后续访问时检索 Cookie:
<?php $arr=$_COOKIE; foreach ($arr as $key=>$val); echo "<h2>$key => $val </h2>"; ?>
浏览器将显示以下输出:
Username => Mohan Kumar
如何删除 Cookie
要删除 Cookie,请使用已过期的日期设置 Cookie,以便浏览器触发 Cookie 删除机制。
<?php setcookie("username", "", time() - 3600); echo "<h2>Cookie username is now removed</h2>"; ?>
浏览器现在将显示以下输出:
Cookie username is now removed
使用数组表示法设置 Cookie
您也可以使用 Cookie 名称中的数组表示法来设置数组 Cookie。
setcookie("user[three]", "Guest"); setcookie("user[two]", "user"); setcookie("user[one]", "admin");
如果 Cookie 名称包含点 (.),则 PHP 会将其替换为下划线 (_)。
PHP $_SESSION
PHP 中的一个超全局变量$_SESSION 是当前脚本中可用的会话变量的关联数组。$HTTP_SESSION_VARS 也包含相同的信息,但它不是超全局变量,现在已被弃用。
什么是会话?
会话是在整个网站页面之间访问数据的另一种方法。它是用户与服务器建立连接的时间与连接终止之间的时间持续时间。在此期间,用户可以导航到不同的页面。很多时候,需要一些数据在页面之间持久可用。这是由会话变量促成的。
会话在服务器上的临时目录中创建一个文件,其中存储已注册的会话变量及其值。在此访问期间,网站上的所有页面都可以使用这些数据。
服务器为每个会话分配一个唯一的 SESSIONID。由于 HTTP 是无状态协议,会话变量中的数据会在会话终止时自动删除。
session_start() 函数
为了启用对会话数据的访问,必须调用 session_start() 函数。session_start() 基于通过 GET 或 POST 请求传递的会话标识符,或通过 Cookie 传递的会话标识符来创建会话或恢复当前会话。
session_start(array $options = []): bool
如果成功启动会话,此函数返回true,否则返回false。
处理会话变量
要创建新的会话变量,请在 $_SESSION 数组中添加键值对:
$_SESSION[ "var"]=value;
要读取会话变量的值,可以使用echo/print 语句,或var_dump() 或print_r() 函数。
echo $_SESSION[ "var"];
要获取当前会话中所有会话变量的列表,可以使用foreach 循环遍历$_SESSION:
foreach ($_SESSION as $key=>$val) echo $key . "=>" . $val;
要手动清除所有会话数据,可以使用session_destroy() 函数。也可以通过调用unset() 函数释放特定的会话变量。
unset($_SESSION[ "var"]);
会话函数列表
在 PHP 中,有很多用于管理会话数据的内置函数。
会话函数 | 描述 |
---|---|
session_abort | 丢弃会话数组更改并结束会话 |
session_cache_expire | 返回当前缓存过期时间 |
session_cache_limiter | 获取和/或设置当前缓存限制器 |
session_commit | session_write_close 的别名 |
session_create_id | 创建新的会话 ID |
session_decode | 从会话编码字符串解码会话数据 |
session_destroy | 销毁注册到会话的所有数据 |
session_encode | 将当前会话数据编码为会话编码字符串 |
session_gc | 执行会话数据垃圾收集 |
session_get_cookie_params | 获取会话 Cookie 参数 |
session_id | 获取和/或设置当前会话 ID |
session_is_registered | 找出全局变量是否在会话中注册 |
session_module_name | 获取和/或设置当前会话模块 |
session_name | 获取和/或设置当前会话名称 |
session_regenerate_id | 使用新生成的 ID 更新当前会话 ID |
session_register_shutdown | 会话关闭函数 |
session_register | 将一个或多个全局变量与当前会话注册 |
session_reset | 使用原始值重新初始化会话数组 |
session_save_path | 获取和/或设置当前会话保存路径 |
session_set_cookie_params | 设置会话 Cookie 参数 |
session_set_save_handler |
设置用户级会话存储函数 |
session_start | 启动新会话或恢复现有会话 |
session_status | 返回当前会话状态 |
session_unregister | 从当前会话注销全局变量 |
session_unset | 释放所有会话变量 |
session_write_close | 写入会话数据并结束会话 |
示例
以下 PHP 脚本呈现 HTML 表单。表单数据用于创建三个会话变量。超链接将浏览器带到另一个页面,该页面读取会话变量。
将此代码另存为文档根目录中的“test.php”,并在客户端浏览器中打开它。输入数据并按提交按钮。
<html> <body> <form action="<?php echo $_SERVER['PHP_SELF'];?>" method="post"> <h3>User's ID: <input type="text" name="ID"/></h3> <h3>Your Name: <input type="text" name="name"/></h3> <h3>Enter Age: <input type="text" name="age"/></h3> <input type="submit" value="Submit"/> </form> <?php session_start(); if ($_SERVER["REQUEST_METHOD"] == "POST") { $_SESSION['UserID'] = $_POST['ID']; $_SESSION['Name'] = $_POST['name']; $_SESSION['age'] = $_POST['age']; } echo "Following Session Variables Created: \n"; foreach ($_SESSION as $key=>$val) echo "<h3>" . $key . "=>" . $val . "</h3>"; echo "<br/>" . '<a href="hello.php">Click Here</a>'; ?> </body> </html>
单击“提交”按钮时,它将显示创建的所有会话变量的列表:
接下来,在“hello.php”文件中保存以下脚本。
<?php session_start(); echo "<h2>Following Session variables Read:</h2>"; foreach ($_SESSION as $key=>$val) echo "<h3>" . $key . "=>" . $val . "</h3>"; ?>
现在,请按照“test.php”页面上的链接导航到“hello.php”。它将显示读取的会话变量:
PHP 文件处理
在 PHP 中,文件是一个资源对象,可以以线性方式从中读取或写入数据。“文件处理”是指 PHP 中的一组函数,这些函数可以使用 PHP 代码对磁盘文件执行读/写操作。
文件对象被分类为流。任何在其上执行线性读/写操作的资源都是流。其他类似流的对象是 TCP 套接字、标准输入流(即由“php://stdin”表示的系统键盘)、由“php://stdout”表示的标准输出流和错误流“php://stderr”。
注意 - 常量 STDIN、STDOUT 和 STDERR 分别代表相应的标准流。
尽管 PHP 被认为是用于开发 Web 应用程序的服务器端脚本语言,但 PHP 也具有命令行界面来执行控制台 IO 操作。
示例
PHP 中的 readline() 函数接受来自标准键盘的用户输入,而 echo/print 语句在控制台上呈现输出。
<?php $str = readline("Type something:"); echo $str; ?>
它将产生以下输出:
C:\xampp\php>php hello.php Type something: Are you enjoying this PHP tutorial? Are you enjoying this PHP tutorial?
示例
我们可以通过从“php://stdin”读取输入并将其输出到“php://stdout”来获得相同的效果。
<?php $f = fopen("php://stdin", "r"); echo "Type something: "; $str = fgets($f); $f1 = fopen("php://stdout", "w"); fputs($f1, $str); ?>
在这里,fopen() 函数用于打开stdin 流以进行读取和stdout 流以进行写入。
示例
PHP 支持各种流协议,用于流相关函数,例如 fopen()、file_exists() 等。使用 php_get_wrappers() 函数获取所有已注册包装器的列表。
<?php print_r(stream_get_wrappers()); ?>
它将产生以下输出:
Array ( [0] => php [1] => file [2] => glob [3] => data [4] => http [5] => ftp [6] => zip [7] => compress.zlib [8] => compress.bzip2 [9] => https [10] => ftps [11] => phar )
流引用为“scheme://target”。例如,文件流是“file://xyz.txt”。
来自控制台的输入数据存储在计算机的主内存 (RAM) 中,直到应用程序运行为止。此后,RAM 中的内存内容将被擦除。
我们希望以一种可以在需要时从持久介质(如磁盘文件)中检索到的方式存储它。因此,我们将使用磁盘文件来读取数据,并使用目标来存储数据,而不是标准流(键盘用于输入,显示设备用于输出)。
除了在上述示例中使用的读和写模式(与标准流的 IO 操作)之外,文件流还可以以各种其他模式打开,例如“r+”和“w+”用于同时读/写,“b”用于二进制模式等。
要打开磁盘文件以进行读取并获取其引用指针,请使用 fopen() 函数。
$handle = fopen('file://' . __DIR__ . '/data.txt', 'r');
“file://” 方案是默认方案。因此,尤其是在处理本地文件时,可以轻松省略。
注意 − 建议始终关闭已打开的流。为此,请使用 fclose() 函数。
fclose($handle);
PHP 提供多个内置函数用于对文件流执行读/写操作。在后续章节中,我们将探讨文件系统函数。
PHP 打开文件
PHP 的内置函数库提供 fopen() 函数来打开文件或任何其他流,并返回其“引用指针”,也称为“句柄”。
PHP 中的 fopen() 函数类似于 C 中的 fopen() 函数,不同之处在于 C 中的 fopen() 函数无法打开 URL。
fopen() 的语法
fopen() 函数具有以下签名:
fopen( string $filename, string $mode, bool $use_include_path = false, ?resource $context = null ): resource|false
$filename 和 $mode 参数是必需的。以下是参数的说明:
$filename − 此参数是一个字符串,表示要打开的资源。它可以是本地文件系统中的文件,也可以是远程服务器上的文件,带有 scheme:// 前缀。
$mode − 一个字符串,表示授予文件/资源的访问类型。
$use_include_path − 一个可选的布尔参数,如果要也在 include_path 中搜索文件,则可以将其设置为“1”或 true。
$context − 一个上下文流资源。
打开文件的模式
PHP 允许以以下模式打开文件:
模式 | 描述 |
---|---|
r | 只读打开文件。 |
w | 只写打开文件;即使文件存在,也会创建一个新文件。 |
a | 以追加模式打开文件 |
x | 创建一个只写的新文件。 |
r+ | 读/写打开文件。 |
w+ | 读/写打开文件;即使文件存在,也会创建一个新文件。 |
a+ | 以追加模式读/写打开文件。 |
x+ | 创建一个读/写的新文件。 |
c | 如果文件不存在,则打开文件进行写入。但是,如果文件存在,则不会截断(与 w 模式不同)。 |
c+ | 如果文件不存在,则打开文件进行读/写。但是,如果文件存在,则不会截断(与 w 模式不同)。 |
e | 在打开的文件描述符上设置 close-on-exec 标志。仅在符合 POSIX.1-2008 系统上编译的 PHP 中可用。 |
如果 fopen() 函数成功执行,则它将返回绑定到文件流的“文件指针”或“句柄”资源。但是,如果失败,则返回 false 并发出 E_WARNING。
$handle = fopen('a.txt, 'r'); var_dump($handle);
如果文件存在于当前目录中,则输出将显示成功:
resource(5) of type (stream)
如果没有,则会收到以下错误消息:
Warning: fopen(a.txt): Failed to open stream: No such file or directory in a.php on line 2 bool(false)
示例
以下示例显示了 fopen() 函数的不同用法:
<?php $handle = fopen("hello.txt", "w"); $handle = fopen("c:/xampp/htdocs/welcome.png", "rb"); $handle = fopen("https://127.0.0.1/hello.txt", "r"); ?>
请注意,当文件名是目录时,此函数也可能成功。在这种情况下,您可能需要使用is_dir()函数在执行任何读/写操作之前检查它是否是文件。
打开文件后,您可以使用fwrite()或fputs()等函数向其中写入数据,并使用fread()和fgets()函数从中读取数据。
关闭文件
建议始终关闭句柄引用的打开流:
fclose($handle);
PHP 读取文件
PHP 中有多种选项可用于读取使用 fopen() 函数打开的文件中的数据。PHP 库中的以下内置函数可以帮助我们执行读取操作:
fgets() − 从文件指针获取一行。
fgetc() − 返回文件指针中单个字符的字符串。
fread() − 从文件指针读取指定数量的字节。
fscanf() − 从文件读取数据并根据指定的格式进行解析。
fgets() 函数
fgets() 函数可以从打开的文件中返回一行。此函数在指定长度的新行或 EOF 处停止返回,以先到达者为准,并在失败时返回false。
fgets(resource $stream, ?int $length = null): string|false
这里,$stream参数是指向使用 fopen() 函数以读或读/写模式打开的文件的文件指针或句柄,$length是指定要读取的字节数的可选参数。
当读取“length-1”个字节或遇到换行符时,读取操作结束,以先到达者为准。
示例
以下代码从“hello.txt”文件读取第一行:
<?php $file = fopen("hello.txt", "r"); $str = fgets($file); echo $str; fclose($file); ?>
它将产生以下输出:
Hello World
示例
您可以将 fgets() 函数放在循环中,以读取文件直到文件结束。
<?php $file = fopen("hello.txt", "r"); while(! feof($file)) { echo fgets($file). "<br>"; } fclose($file); ?>
它将产生以下输出:
Hello World TutorialsPoint PHP Tutorials
这里,我们使用了feof()函数,如果文件指针位于 EOF 处,则返回 true;否则返回 false。
fgetc() 函数
fgetc() 函数返回从文件句柄的当前位置读取的单个字符。遇到 EOF 时返回false。
fgetc(resource $stream): string|false
这里,$stream参数是指向使用 fopen() 函数以读或读/写模式打开的文件的文件指针或句柄。
示例
以下代码显示从“hello.txt”文件读取的第一个字符:
<?php $file = fopen("hello.txt", "r"); $str = fgets($file); echo $str; fclose($file); ?>
它将产生以下输出:
H
示例
您还可以将fgetc()函数放在循环中,以逐个字符读取文件,直到到达 EOF。
<?php $file = fopen("hello.txt", "r"); while(! feof($file)) { $char = fgetc($file); if ($char == "\n") echo "<br>"; echo $char; } fclose($file); ?>
它将产生以下输出:
Hello World TutorialsPoint PHP Tutorials
fread() 函数
PHP 中的 fread() 函数是用于从文件读取数据的二进制安全函数。fgets() 函数仅从文本文件读取,而 fread() 函数可以以二进制模式读取文件。
fread(resource $stream, int $length): string|false
这里,$stream参数是指向使用 fopen() 函数以二进制读或读/写模式(rb或rb+)打开的文件的文件指针或句柄。$length参数指定要读取的字节数。
如果没有给出$length参数,PHP 将尝试读取整个文件,直到到达 EOF,这取决于指定的块大小。
示例
以下代码读取文本文件:
<?php $name = "hello.txt"; $file = fopen($name, "r"); $data = fread($file, filesize($name)); echo $data; fclose($file); ?>
它将产生以下输出:
Hello World TutorialsPoint PHP Tutorials
示例
您还可以读取以rb模式打开的非 ASCII 文件(例如图像文件)。
<?php $name = "welcome.png"; $file = fopen($name, "rb"); $data = fread($file, filesize($name)); var_dump($data); fclose($file); ?>
浏览器将“var_dump”信息显示为:
fscanf() 函数
PHP 中的 fscanf() 函数从文件流读取输入并根据指定的格式进行解析,从而将其转换为相应类型的变量。每次调用该函数都会从文件中读取一行。
fscanf(resource $stream, string $format, mixed &...$vars): array|int|false|null
这里,$stream参数是指向使用 fopen() 函数以读模式打开的文件的句柄。并且,$format是一个包含一个或多个以下格式说明符的字符串:
%% − 返回百分号
%b − 二进制数
%c − 根据 ASCII 值的字符
%f − 浮点数
%F − 浮点数
%o − 八进制数
%s − 字符串
%d − 带符号十进制数
%e − 科学计数法
%u − 无符号十进制数
%x − 小写字母的十六进制数
%X − 大写字母的十六进制数
$vars是一个可选参数,它通过引用指定变量,这些变量将包含已解析的值。
假设“employees.txt”文件位于包含以下 PHP 脚本的同一目录中。文本文件中的每一行都包含每个员工的姓名、电子邮件、职位和薪水,并用制表符分隔。
示例
以下 PHP 脚本使用 fscanf() 函数中的格式说明符读取文件:
<?php $fp = fopen("employees.txt", "r"); while ($employee_info = fscanf($fp, "%s\t%s\t%s\t%d\n")) { list ($name, $email, $post, $salary) = $employee_info; echo "<b>Name</b>: $name <b>Email</b>: $email <b>Salary</b>: Rs. $salary <br>"; } fclose($fp); ?>
它将产生以下输出:
Name: Ravishankar Email: [email protected] Salary: Rs. 40000 Name: Kavita Email: [email protected] Salary: Rs. 25000 Name: Nandkumar Email: [email protected] Salary: Rs. 30000
PHP 写入文件
PHP 的内置函数库提供两个函数来对文件流执行写操作。这两个函数是fwrite()和fputs()。
为了能够向文件中写入数据,必须以写入模式 (w)、追加模式 (a)、读/写模式 (r+ 或 w+) 或二进制写入/追加模式 (rb+、wb+ 或 wa) 打开文件。
fputs() 函数
fputs() 函数将字符串写入以可写模式打开的文件。
fputs(resource $stream, string $string, int $length)
这里,$stream参数是指向以可写模式打开的文件的句柄。$string参数是要写入的数据,$length是指定要写入的最大字节数的可选参数。
fputs() 函数返回写入的字节数,如果函数不成功,则返回false。
示例
以下代码打开一个新文件,向其中写入一个字符串,并返回写入的字节数。
<?php $fp = fopen("hello.txt", "w"); $bytes = fputs($fp, "Hello World\n"); echo "bytes written: $bytes"; fclose($fp); ?>
它将产生以下输出:
bytes written: 12
示例
如果需要在现有文件中添加文本,则必须以追加模式 (a) 打开它。让我们在前面示例的同一文件中再添加一个字符串。
<?php $fp = fopen("hello.txt", "a"); $bytes = fputs($fp, "Hello PHP"); echo "bytes written: $bytes"; fclose($fp); ?>
如果在文本编辑器中打开“hello.txt”文件,则应该看到其中的两行。
示例
在以下 PHP 脚本中,一个现有的文件 (hello.txt) 在循环中逐行读取,每一行都写入另一个文件 (new.txt)
假设“hello.txt”包含以下文本:
Hello World TutorialsPoint PHP Tutorials
以下是创建现有文件副本的 PHP 代码:
<?php $file = fopen("hello.txt", "r"); $newfile = fopen("new.txt", "w"); while(! feof($file)) { $str = fgets($file); fputs($newfile, $str); } fclose($file); fclose($newfile); ?>
新创建的“new.txt”文件应该具有完全相同的内容。
fwrite() 函数
frwrite() 函数是 fread() 函数的对应函数。它执行二进制安全写操作。
fwrite(resource $stream, string $data, ?int $length = null): int|false
这里,$stream参数是指向以可写模式打开的文件的资源。要写入文件的数据在$data参数中提供。可以提供可选的$length参数来指定要写入的字节数。它应该是int类型,写入将在写入 length 个字节或到达数据末尾后停止,以先到达者为准。
fwrite() 函数返回写入的字节数,如果失败,则返回false以及 E_WARNING。
示例
以下程序打开一个新文件,执行写操作并显示写入的字节数。
<?php $file = fopen("/PhpProject/sample.txt", "w"); echo fwrite($file, "Hello Tutorialspoint!!!!!"); fclose($file); ?>
示例
在以下示例代码中,以二进制读取模式打开现有的“welcome.png”文件。fread() 函数用于将它的字节读取到“$data”变量中,然后写入另一个文件“new.png”:
<?php $name = "welcome.png"; $file = fopen($name, "rb"); $newfile = fopen("new.png", "wb"); $size = filesize($name); $data = fread($file, $size); fwrite($newfile, $data, $size); fclose($file); fclose($newfile); ?>
运行上述代码。当前目录现在应该有一个现有“welcome.png”文件的副本。
PHP 文件是否存在
在对文件执行任何处理之前,检查您尝试打开的文件是否真的存在通常非常有用。否则,程序可能会引发运行时异常。
PHP 的内置库在这方面提供了一些实用程序函数。本章将讨论的一些函数包括:
file_exists() − 测试文件是否存在
is_file() − 如果 fopen() 返回的句柄是指文件还是目录。
is_readable() − 测试您打开的文件是否允许读取数据
is_writable() − 测试是否允许向文件中写入数据
file_exists() 函数
此函数适用于文件和目录。它检查给定的文件或目录是否存在。
file_exists(string $filename): bool
此函数的唯一参数是一个字符串,表示具有完整路径的文件/目录。该函数根据文件是否存在返回 true 或 false。
示例
以下程序检查文件“hello.txt”是否存在。
<?php $filename = 'hello.txt'; if (file_exists($filename)) { $message = "The file $filename exists"; } else { $message = "The file $filename does not exist"; } echo $message; ?>
如果文件存在于当前目录中,则消息为:
The file hello.txt exists
如果不存在,则消息为:
The file hello.txt does not exist
示例
指向文件的字符串可以具有相对路径或绝对路径。假设“hello.txt”文件位于当前目录内的“hello”子目录中。
<?php $filename = 'hello/hello.txt'; if (file_exists($filename)) { $message = "The file $filename exists"; } else { $message = "The file $filename does not exist"; } echo $message; ?>
它将产生以下输出:
The file hello/hello.txt exists
示例
尝试给出如下所示的绝对路径:
<?php $filename = 'c:/xampp/htdocs/hello.txt'; if (file_exists($filename)) { $message = "The file $filename exists"; } else { $message = "The file $filename does not exist"; } echo $message; ?>
它将产生以下输出:
The file c:/xampp/htdocs/hello.txt exists
is_file() 函数
file_exists()函数对现有文件和目录都返回true。is_file()函数可以帮助您确定它是否是文件。
is_file ( string $filename ) : bool
以下示例显示了is_file()函数的工作方式:
<?php $filename = 'hello.txt'; if (is_file($filename)) { $message = "$filename is a file"; } else { $message = "$filename is a not a file"; } echo $message; ?>
输出表明它是一个文件:
hello.txt is a file
现在,将“$filename”更改为目录,然后查看结果:
<?php $filename = hello; if (is_file($filename)) { $message = "$filename is a file"; } else { $message = "$filename is a not a file"; } echo $message; ?>
现在,您将被告知“hello”不是文件。
请注意,is_file()函数接受一个$filename,并且只有当$filename是一个文件并且存在时才返回true。
is_readable() 函数
有时,您可能想提前检查是否可以从中读取文件。is_readable()函数可以确定这一事实。
is_readable ( string $filename ) : bool
示例
下面是is_readable()函数工作方式的示例:
<?php $filename = 'hello.txt'; if (is_readable($filename)) { $message = "$filename is readable"; } else { $message = "$filename is not readable"; } echo $message; ?>
它将产生以下输出:
hello.txt is readable
is_writable() 函数
可以使用 `is_writable()` 函数检查文件是否存在以及是否可以对指定文件执行写入操作。
is_writable ( string $filename ) : bool
示例
以下示例演示了 `**is_writable()**` 函数的工作原理:
<?php $filename = 'hello.txt'; if (is_writable($filename)) { $message = "$filename is writable"; } else { $message = "$filename is not writable"; } echo $message; ?>
对于普通的存档文件,程序会显示其可写。但是,将其属性更改为“只读”并运行程序。现在您将看到:
hello.txt is writable
PHP 下载文件
大多数现代浏览器允许自动下载某些类型的文件,无需任何服务器端代码(例如 PHP 脚本)。例如,zip 文件或 EXE 文件。
如果 HTML 超链接指向 ZIP 或 EXE 文件,浏览器会将其下载并弹出保存对话框。但是,文本文件、图像文件等不会下载,而是在浏览器中打开,您可以将其保存到本地文件系统。
`readfile()` 函数
要下载此类文件(而不是浏览器自动打开它们),我们可以使用 PHP 内置函数库中的 `**readfile()**` 函数。
readfile(string $filename, bool $use_include_path = false, ?resource $context = null) : int|false
此函数读取文件并将其写入输出缓冲区。
第二个参数 `**$use_include_path**` 默认值为 false,因此将下载当前目录中的文件。如果设置为 `**true**`,则将搜索添加到 `**php.ini**` 配置的 `**include_path**` 设置中的目录,以找到要下载的文件。
`readfile()` 函数返回读取的字节数,即使成功完成或未成功完成也是如此,返回false。
示例
以下 PHP 脚本显示了 `readfile()` 函数的用法。
要下载文件,应将 `**Content-Type**` 响应标头设置为 `**application/octet-stream**`。此 MIME 类型是二进制文件的默认类型。浏览器通常不会执行它,甚至不会询问是否应该执行它。
此外,将 `Content-Disposition` 标头设置为 `attachment` 会提示弹出“另存为”对话框。
<?php $filePath = 'welcome.png'; // Set the Content-Type header to application/octet-stream header('Content-Type: application/octet-stream'); // Set the Content-Disposition header to the filename of the downloaded file header('Content-Disposition: attachment; filename="'. basename($filePath).'"'); // Read the contents of the file and output it to the browser. readfile($filePath); ?>
将上述脚本保存为文档根文件夹中的“download.php”。确保要下载的文件位于同一文件夹中。
启动服务器并在浏览器中访问 `**https://127.0.0.1/download.php**`。您将看到如下所示的“另存为”对话框:
您可以选择名称并下载文件。
对于大型文件,您可以从文件流中以特定预定义大小的块读取它。如果 `Content-Disposition` 头设置为“attachment”(如前面的示例),浏览器会提供将其保存到本地文件系统。
<?php $filename = 'welcome.png'; header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . basename($filename) . '"'); $handle = fopen($filename, 'rb'); $buffer = ''; $chunkSize = 1024 * 1024; ob_start(); while (!feof($handle)) { $buffer = fread($handle, $chunkSize); echo $buffer; ob_flush(); flush(); } fclose($handle); ?>
PHP 复制文件
您可以通过三种不同的方式将现有文件复制到新文件:
循环读取一行并写入另一行
将整个内容读取到字符串中并将字符串写入另一个文件
使用 PHP 内置函数库,包括 `copy()` 函数。
方法 1
在第一种方法中,您可以从现有文件中读取每一行并写入新文件,直到现有文件到达文件结尾。
在以下 PHP 脚本中,一个现有的文件 (hello.txt) 在循环中逐行读取,每一行都写入另一个文件 (new.txt)
假设“hello.txt”包含以下文本:
Hello World TutorialsPoint PHP Tutorials
示例
以下是创建现有文件副本的 PHP 代码:
<?php $file = fopen("hello.txt", "r"); $newfile = fopen("new.txt", "w"); while(! feof($file)) { $str = fgets($file); fputs($newfile, $str); } fclose($file); fclose($newfile); ?>
新创建的“new.txt”文件应该具有完全相同的内容。
方法 2
这里我们使用 PHP 库中的两个内置函数:
file_get_contents( string $filename, bool $use_include_path = false, ?resource $context = null, int $offset = 0, ?int $length = null ): string|false
此函数将整个文件读取到字符串中。`$filename` 参数是一个包含要读取的文件名的字符串。
另一个函数是:
file_put_contents( string $filename, mixed $data, int $flags = 0, ?resource $context = null ): int|false
该函数将 `$data` 的内容放入 `$filename` 中。它返回写入的字节数。
示例
在下面的示例中,我们将“hello.txt”的内容读取到字符串 `$data` 中,并将其用作参数写入“test.txt”文件。
<?php $source = "hello.txt"; $target = "test.txt"; $data = file_get_contents($source); file_put_contents($target, $data); ?>
方法 3
PHP 提供了 `copy()` 函数,专门用于执行复制操作。
copy(string $from, string $to, ?resource $context = null): bool
`$from` 参数是一个包含现有文件的字符串。`$to` 参数也是一个包含要创建的新文件名的字符串。如果目标文件已存在,它将被覆盖。
复制操作将根据文件是否成功复制返回 `true` 或 `false`。
示例
让我们使用 `copy()` 函数将“text.txt”作为“hello.txt”文件的副本。
<?php $source = "a.php"; $target = "a1.php"; if (!copy($source, $target)) { echo "failed to copy $source...\n"; } ?>
PHP 追加文件
在 PHP 中,`fopen()` 函数返回在不同打开模式下使用的文件的指针,例如“w”表示写入模式,“r”表示读取模式,“r+”或“w+”模式表示同时读/写操作,“a”模式表示追加模式。
当文件以“w”模式参数打开时,它总是打开一个新文件。这意味着如果文件已存在,其内容将丢失。随后的 `fwrite()` 函数将数据放在文件的起始位置。
假设存在一个名为“new.txt”的文件,其内容如下:
Hello World TutorialsPoint PHP Tutorial
以下语句:
$fp = fopen("new.txt", "w");
在写入新内容之前擦除所有现有数据。
读/写模式
显然,如果文件以“r”模式打开,则无法添加新数据。“r+”或“w+”模式以“r/w”模式打开文件,但仍然在打开文件后立即执行 `fwrite()` 语句将覆盖内容。
示例
请看下面的代码:
<?php $fp = fopen("new.txt", "r+"); fwrite($fp, "PHP-MySQL Tutorial\n"); fclose($fp); ?>
使用此代码,“new.txt”文件的内容现在将变为:
PHP-MySQL Tutorial lsPoint PHP Tutorial
要确保新内容添加到现有文件的末尾,我们需要在写入操作之前手动将文件指针移到末尾。(初始文件指针位置在第 0 个字节)
`fseek()` 函数
PHP 的 `fseek()` 函数可以将文件指针放在您想要的任何位置:
fseek(resource $stream, int $offset, int $whence = SEEK_SET): int
`$whence` 参数是从哪里计算偏移量的。其值为:
`**SEEK_SET**` - 将位置设置为等于偏移量字节。
`**SEEK_CUR**` - 将位置设置为当前位置加上偏移量。
`**SEEK_END**` - 将位置设置为文件末尾加上偏移量。
示例
因此,我们需要使用 `fseek()` 函数将指针移动到末尾,如下面的代码所示,该代码将新内容添加到末尾。
<?php $fp = fopen("new.txt", "r+"); fseek($fp, 0, SEEK_END); fwrite($fp, "\nPHP-MySQL Tutorial\n"); fclose($fp); ?>
现在检查“new.txt”的内容。它将包含以下文本:
Hello World TutorialsPoint PHP Tutorial PHP-MySQL Tutorial
追加模式
无需手动将指针移动到末尾,`fopen()` 函数中的“a”参数以追加模式打开文件。每个 `fwrite()` 语句都会将内容添加到现有内容的末尾,方法是自动将指针移动到 `SEEK_END` 位置。
<?php $fp = fopen("new.txt", "a"); fwrite($fp, "\nPHP-MySQL Tutorial\n"); fclose($fp); ?>
`fopen()` 函数允许的模式之一是“r+”模式,该模式下文件执行读/追加操作。要从任何位置读取数据,您可以使用 `fseek()` 将指针置于所需的字节。但是,每个 `fwrite()` 操作都只在末尾写入新内容。
示例
在下面的程序中,文件以“a+”模式打开。要读取第一行,我们从开头将文件位置移到第 0 个位置。但是,`fwrite()` 语句仍然将新内容添加到末尾,并且不会像“r+”模式那样覆盖下一行。
<?php $fp = fopen("new.txt", "a+"); fseek($fp, 0, SEEK_SET); $data = fread($fp, 12); echo $data; fwrite($fp, "PHP-File Handling"); fclose ($fp); ?>
因此,如果文件以“r+/w+”模式或“a/a+”模式打开,我们可以将数据追加到现有文件中。
PHP 删除文件
PHP 没有 `delete` 关键字或 `delete()` 函数。相反,它提供了 `unlink()` 函数,该函数在调用时会从文件系统中删除文件。它类似于 Unix/C 的 `unlink` 函数。
如果无法完成删除操作,PHP 将返回 false 并显示 E_WARNING 消息。
unlink(string $filename, ?resource $context = null): bool
`unlink()` 函数的必需字符串参数是一个指向要删除文件的字符串。
示例
以下代码演示了 `unlink()` 函数的简单用法:
<?php $file = "my_file.txt"; if (unlink($file)) { echo "The file was deleted successfully."; } else { echo "The file could not be deleted."; } ?>
删除指向文件的符号链接
`unlink()` 函数还可以删除指向文件的符号链接。但是,删除符号链接不会删除原始文件。符号链接是现有文件的快捷方式。
在 Windows 中,以管理员权限打开命令提示符,并使用 `/h` 开关和 `mlink` 命令创建指向文件的符号链接。(`/j` 开关用于指向文件夹的符号链接)
mklink /h hellolink.lnk hello.txt Hardlink created for hellolink.lnk <<===>> hello.txt
在 Ubuntu Linux 中,要创建指向文件的符号链接,可以使用以下命令:
ln -s /path/to/original_file /path/to/symlink
要创建指向目录的符号链接,可以使用以下命令:
ln -s /path/to/original_directory /path/to/symlink
在 PHP 中,还有一个 `symlink()` 函数用于此目的。
symlink(string $target, string $link): bool
示例
使用以下代码创建一个符号链接:
<?php $target = 'hello.txt'; $link = 'hellolink.lnk'; symlink($target, $link); echo readlink($link); ?>
现在删除上面创建的符号链接:
unlink("hellolink.lnk");
如果检查当前工作目录,符号链接将被删除,而原始文件保持不变。
如何在 PHP 中重命名文件
您可以使用操作系统控制台中的相应命令来更改现有文件的名称。例如,Linux 终端中的“`mv` 命令”或 Windows 命令提示符中的“`rename` 命令”可以帮助您更改文件的名称。
但是,要以编程方式重命名文件,PHP 的内置库包含一个 `rename()` 函数。
以下是 `rename()` 函数的语法:
rename(string $from, string $to, ?resource $context = null): bool
`$from` 和 `$to` 字符串分别是现有文件和新文件的名称。`rename()` 函数尝试将 `$from` 重命名为 `$to`,必要时在目录之间移动它。
如果您正在重命名一个文件并且 `$to` 已存在,则它将被覆盖。如果您正在重命名一个目录并且 `$to` 存在,则此函数将发出警告。
要将“hello.txt”的名称更改为“test.txt”:
<?php rename("hello.txt", "test.txt"); ?>
您还可以采用一种稍微间接的方法来重命名文件。复制现有文件并删除原始文件。这也将“hello.txt”重命名为“test.txt”:
copy("hello.txt", "test.txt"); unlink("hello.txt");
PHP – 处理 CSV 文件
流行的电子表格程序使用 CSV 文件格式(代表逗号分隔值)以纯文本格式导出工作表数据。文件中的每一行代表工作表的一行,每列中的值用逗号分隔。
PHP 的文件系统函数库提供了两个函数——`fgetcsv()` 和 `fputcsv()`——分别用于将 CSV 文件中的数据读取到数组中并将数组元素放入 CSV 文件中。
`fgetcsv()` 函数
`fgetcsv()` 函数从文件指针读取行,并将其解析为 CSV 字段。
fgetcsv( resource $stream, ?int $length = null, string $separator = ",", string $enclosure = "\"", string $escape = "\\" ): array|false
`$stream` 参数是文件资源的句柄,以读取模式打开。解析字段的默认分隔符是逗号,如果需要,您可以指定任何其他符号。
`fgetcsv()` 函数返回一个包含字段的索引数组。如果函数遇到任何错误,它将返回 `false`。
为了演示 `fgetcsv()` 函数的用法,请将以下文本存储为当前工作目录中的“hello.txt”。
Name, Email, Post, Salary Ravishankar, [email protected], Manager, 40000 Kavita, [email protected], Assistant, 25000 Nandkumar, [email protected], Programmer, 30000
示例
以下 PHP 代码从该文件读取 CSV 数据,并返回一个数组。然后在 HTML 表格中呈现数组中的字段:
<?php $filename = 'hello.csv'; $data = []; // open the file $f = fopen($filename, 'r'); if ($f === false) { die('Cannot open the file ' . $filename); } // read each line in CSV file at a time while (($row = fgetcsv($f)) !== false) { $data[] = $row; } // close the file fclose($f); echo "<table border=1>"; foreach ($data as $row) { echo "<tr>"; foreach($row as $val) { echo "<td>$val</td>"; } echo "</tr>"; } echo "</table>"; ?>
它将产生以下输出:
名称 | 邮箱 | 职位 | 薪水 |
---|---|---|---|
Ravishankar | [email protected] | 经理 | 40000 |
Kavita | [email protected] | 助理 | 25000 |
Nandkumar | [email protected] | 程序员 | 30000 |
`fputcsv()` 函数
`fputcsv()` 函数将一个索引数组及其元素用逗号分隔,放在 CSV 文件的当前文件指针位置。
fputcsv( resource $stream, array $fields, string $separator = ",", string $enclosure = "\"", string $escape = "\\", string $eol = "\n" ): int|false
目标文件必须以写入模式打开。第二个必填参数是一个由逗号分隔的字段组成的数组。与fgetcsv()函数一样,默认分隔符为逗号。
示例
在下面的代码中,一个二维的逗号分隔值数组被写入到一个CSV文件中。
<?php $data = [ ["Name", "Email", "Post", "Salary"], ["Ravishankar", "[email protected]", "Manager", "40000"], ["Kavita", "[email protected]", "Assistant", "25000"], ["Nandkumar", "[email protected]", "Programmer", "30000"], ]; $filename = 'employee.csv'; // open csv file for writing $f = fopen($filename, 'w'); if ($f === false) { die('Error opening the file ' . $filename); } // write each row at a time to a file foreach ($data as $row) { fputcsv($f, $row); } // close the file fclose($f); ?>
执行上述程序后,应该在当前工作目录中创建“employee.csv”文件。
PHP – 文件权限
权限的概念是Unix/Linux文件系统的核心。权限决定了谁能访问文件以及如何访问文件。Linux中的文件权限由**chmod命令**操作,该命令可以在Linux终端内运行。PHP提供了**chmod()函数**,您可以用它以编程方式处理文件权限。
只有在Linux操作系统上工作时,PHP的chmod()函数才有效。它在Windows上不起作用,因为Windows操作系统有不同的文件权限控制机制。
要查看文件中启用的权限,请使用“**ls -l**”命令(长列表)获取文件列表。
mvl@GNVBGL3:~$ ls -l -rwxr-xr-x 1 mvl mvl 16376 May 5 21:52 a.out -rw-r--r-- 1 mvl mvl 83 May 5 21:52 hello.cpp -rwxr-xr-x 1 mvl mvl 43 Oct 11 14:50 hello.php -rwxr-xr-x 1 mvl mvl 43 May 8 10:01 hello.py drwxr-xr-x 5 mvl mvl 4096 Apr 20 21:52 myenv
第一列包含每个文件的权限标志。第三列和第四列分别指示每个文件的拥有者和组,后面跟着大小、日期和时间以及文件名。
权限字符串有十个字符,其含义如下:
位置 | 含义 |
---|---|
1 | 如果是目录则为“d”,如果是普通文件则为“-” |
2, 3, 4 | 文件拥有者(用户)的读、写、执行权限 |
5, 6, 7 | 组的读、写、执行权限 |
8, 9, 10 | 其他用户的读、写、执行权限 |
权限字符串中的字符具有以下含义:
值 | 含义 |
---|---|
- | 标志未设置。 |
r | 文件可读。 |
w | 文件可写。对于目录,可以创建或删除文件。 |
x | 文件可执行。对于目录,可以列出文件。 |
如果您考虑上述列表中的第一个条目:
-rwxr-xr-x 1 mvl mvl 16376 May 5 21:52 a.out
“a.out”文件由用户“mvl”和组“mvl”拥有。它是一个普通文件,拥有者具有“读/写/执行”权限,组和其他用户具有“读/执行”权限。
权限标志的二进制和八进制表示可以通过下表理解:
八进制数字 | 二进制表示 (rwx) | 权限 |
---|---|---|
0 | 000 | 无 |
1 | 001 | 仅执行 |
2 | 010 | 仅写入 |
3 | 011 | 写入和执行 |
4 | 100 | 仅读取 |
5 | 101 | 读取和执行 |
6 | 110 | 读取和写入 |
7 | 111 | 读取、写入和执行(完全权限) |
chmod() 函数
chmod()函数可以更改指定文件的权限。成功时返回**true**,失败时返回**false**。
chmod(string $filename, int $permissions): bool
chmod()函数尝试将指定文件(**$filename**)的模式更改为权限中给定的模式。
第二个参数**$permissions**是一个具有四个八进制数字的八进制数。第一位始终为零,第二位指定拥有者的权限,第三位指定拥有者的用户组的权限,第四位指定其他所有人的权限。每一位都是每种权限值的总和。
1 | 执行权限 |
2 | 写入权限 |
4 | 读取权限 |
**$permissions**参数的默认值为**0777**,这意味着目录的创建启用了执行、写入和读取权限。
示例
请看以下示例:
<?php // Read and write for owner, nothing for everybody else chmod("/PhpProject/sample.txt", 0600); // Read and write for owner, read for everybody else chmod("/PhpProject/sample.txt", 0644); // Everything for owner, read and execute for everybody else chmod("/PhpProject/sample.txt", 0755); // Everything for owner, read for owner's group chmod("/PhpProject/sample.txt", 0740); ?>
chown() 函数
chown()函数尝试将文件filename的所有者更改为新用户。请注意,只有超级用户才能更改文件的所有者。
chown(string $filename, string|int $user): bool
示例
请看以下示例:
<?php // File name and username to use $file_name= "index.php"; $path = "/PhpProject/backup: " . $file_name ; $user_name = "root"; // Set the user chown($path, $user_name); // Check the result $stat = stat($path); print_r(posix_getpwuid(fileowner($path))); ?>
chgrp() 函数
chgrp()函数尝试将文件filename的组更改为group。
chgrp(string $filename, string|int $group): bool
只有**超级用户**可以随意更改文件的组;其他用户可以将文件的组更改为该用户所属的任何组。
示例
请看以下示例:
<?php $filename = "/PhpProject/sample.txt"; $format = "%s's Group ID @ %s: %d\n"; printf($format, $filename, date('r'), filegroup($filename)); chgrp($filename, "admin"); clearstatcache(); // do not cache filegroup() results printf($format, $filename, date('r'), filegroup($filename)); ?>
它将产生以下输出:
/PhpProject/sample.txt's Group ID @ Fri, 13 Oct 2023 07:42:21 +0200: 0 /PhpProject/sample.txt's Group ID @ Fri, 13 Oct 2023 07:42:21 +0200: 0
PHP – 创建目录
计算机文件存储在本地存储设备(称为**驱动器**)中,采用分层顺序,其中一个目录包含一个或多个文件以及子目录。操作系统Windows、Linux等中定义的相应DOS命令用于创建和管理目录。
PHP提供目录管理函数来创建目录、更改当前目录和删除某个目录。
本章讨论在PHP中使用以下目录函数:
mkdir() 函数
mkdir()函数创建一个新目录,其路径作为函数的参数之一给出。
mkdir( string $directory, int $permissions = 0777, bool $recursive = false, ?resource $context = null ): bool
参数
**$directory** – 第一个参数$directory是必需的。它是一个字符串,包含要创建的新目录的绝对路径或相对路径。
**$permissions** – 第二个参数$permissions是一个具有四个八进制数字的八进制数。第一位始终为零,第二位指定拥有者的权限,第三位指定拥有者的用户组的权限,第四位指定其他所有人的权限。
每一位都是每种权限值的总和:
1 = 执行权限
2 = 写入权限
4 = 读取权限
$permissions参数的默认值为**0777**,这意味着目录的创建启用了执行、写入和读取权限。
请注意,在Windows操作系统上工作时会忽略$permissions参数。
**$recursive** – 如果为true,则还会创建指定目录的任何父目录,并使用相同的权限。
**$context** – 此可选参数是流资源。
mkdir()函数返回true或false,指示函数是否已成功执行。
示例
以下是一些mkdir()函数的示例。
以下对mkdir()的调用会在当前工作目录内创建一个子目录。点表示路径是相对的。
$dir = "./mydir/"; mkdir($dir);
我们可以提供包含要创建的目录的绝对路径的字符串参数。
$dir = "c:/newdir/"; mkdir($dir);
以下对mkdir()的调用包含当前目录内的嵌套目录结构,因为$recursive参数设置为true。
$dirs = "./dir1/dir2/dir3/"; mkdir($dirs, 0777, true);
Windows资源管理器将显示嵌套目录结构如下:
chdir() 函数
PHP中的chdir()函数对应于Linux/Windows中的**chdir**或**cd**命令。它会根据需要更改当前目录。
chdir(string $directory): bool
此函数的字符串参数是需要将当前目录更改到的目录的绝对路径或相对路径。它返回true或false。
getcwd() 函数
getcwd()函数的工作方式类似于Ubuntu Linux中的pwd命令,并返回当前工作目录的路径。
示例
使用以下代码片段,PHP在更改当前工作目录之前和之后显示当前工作目录。在新当前目录中创建了几个文件。使用scandir()函数列出这些文件。
<?php echo "current directory: ". getcwd() . PHP_EOL; $dir = "./mydir"; chdir($dir); echo "current directory changed to: ". getcwd() .PHP_EOL; $fp = fopen("a.txt", "w"); fwrite($fp, "Hello World"); fclose($fp); copy("a.txt", "b.txt"); $dir = getcwd(); foreach(scandir($dir) as $file) echo $file . PHP_EOL; ?>
它将产生以下输出:
current directory: C:\xampp\php current directory changed to: C:\xampp\php\mydir . .. a.txt b.txt
rmdir() 函数
rmdir()函数删除路径作为参数给出的某个目录。要删除的目录必须为空。
$dir = "c:/newdir/"; rmdir($dir) or die("The directory is not present or not empty");
PHP – 列出文件
Windows命令DIR和Linux命令ls都显示当前目录中的文件列表。这些命令可以与不同的开关一起操作,以便对显示的文件列表应用条件。PHP提供了一些选项,可以通过编程方式列出给定目录中的文件。
readdir() 函数
PHP中的opendir()函数类似于fopen()函数。它返回目录的句柄,以便可以以序列化方式读取目录的内容。
opendir(string $directory, ?resource $context = null): resource|false
此函数打开一个目录句柄,供后续的closedir()、readdir()和rewinddir()调用使用。
**readdir()**函数从**opendir()**函数返回的流句柄读取下一个可用条目。
readdir(?resource $dir_handle = null): string|false
这里,**dir_handle**是之前用opendir()打开的目录句柄。如果没有指定,则假定为opendir()打开的最后一个链接。
**closedir()**函数类似于**fclose()**函数。它关闭目录句柄。
closedir(?resource $dir_handle = null): void
该函数关闭dir_handle指示的目录流。该流必须先前已由opendir()打开。
示例
以下PHP代码一次读取当前登录目录中的一个文件。
<?php $dir = getcwd(); // Open a known directory, and proceed to read its contents if (is_dir($dir)) { if ($dh = opendir($dir)) { while (($file = readdir($dh)) !== false) { echo "filename:" . $file . "\n"; } closedir($dh); } } ?>
scandir() 函数
scandir()函数检索给定目录内的文件和子目录。
scandir(string $directory, int $sorting_order = SCANDIR_SORT_ASCENDING, ?resource $context = null): array|false
默认情况下,“排序顺序”为按字母顺序升序排列。如果此可选参数设置为SCANDIR_SORT_DESCENDING,则排序顺序变为按字母顺序降序排列。如果将其设置为SCANDIR_SORT_NONE,则结果将未排序。
示例
使用以下PHP代码,scandir()函数返回给定目录中文件的数组。
<?php $dir = "c:/xampp/php/mydir/"; $files = scandir($dir); var_dump($files); ?>
它将产生以下输出:
array(4) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(5) "a.txt" [3]=> string(5) "b.txt" }
您可以使用**foreach**循环遍历scandir()函数返回的数组。
<?php $dir = "c:/xampp/php/mydir/"; $files = scandir($dir); foreach ($files as $file) echo $file . PHP_EOL; ?>
它将产生以下输出:
. .. a.txt b.txt
PHP中的面向对象编程
我们可以想象我们的宇宙是由不同的物体组成的,例如太阳、地球、月亮等。同样,我们可以想象我们的汽车是由不同的物体组成的,例如车轮、方向盘、齿轮等。同样,面向对象编程的概念假设一切都是一个对象,并使用不同的对象实现软件。
面向对象的概念
在详细介绍之前,让我们定义与面向对象编程相关的术语。
**类** – 这是程序员定义的数据类型,它包括局部函数和局部数据。您可以将类视为制作许多相同类型(或类)对象的模板。
**对象** – 类定义的数据结构的单个实例。您只定义一次类,然后创建属于该类的许多对象。对象也称为实例。
**成员变量** – 这些是在类中定义的变量。此数据对类外部不可见,可以通过成员函数访问。创建对象后,这些变量称为对象的属性。
**成员函数** – 这些是在类中定义的函数,用于访问对象数据。
**继承** – 当一个类通过继承父类的现有函数来定义时,这称为继承。子类将继承父类所有或部分成员函数和变量。
**父类** – 被另一个类继承的类。这也被称为基类或超类。
**子类** – 从另一个类继承的类。这也被称为子类或派生类。
**多态性** – 这是一个面向对象的概念,其中相同的函数可以用于不同的目的。例如,函数名将保持不变,但它采用不同数量的参数,并且可以执行不同的任务。
**重载** – 一种多态性,其中某些或所有运算符根据其参数的类型具有不同的实现。类似地,函数也可以用不同的实现来重载。
**数据抽象** – 任何隐藏(抽象)实现细节的数据表示。
**封装** – 指的是将所有数据和成员函数封装在一起形成一个对象的概念。
**构造函数** – 指的是一种特殊的函数,每当从类中形成对象时,都会自动调用该函数。
**析构函数** – 指的是一种特殊的函数,每当对象被删除或超出范围时,都会自动调用该函数。
定义PHP类
在PHP中定义新类的通用形式如下:
<?php class phpClass { var $var1; var $var2 = "constant string"; function myfunc ($arg1, $arg2) { [..] } [..] } ?>
以下是每一行的描述:
特殊的形式**class**,后跟要定义的类的名称。
一组大括号,包含任意数量的变量声明和函数定义。
变量声明以特殊的形式**var**开头,后跟常规的$变量名;它们也可能具有对常值的初始赋值。
函数定义看起来很像独立的PHP函数,但它们是局部于类的,将用于设置和访问对象数据。
示例
这是一个定义Books类型类的示例:
<?php class Books { /* Member variables */ var $price; var $title; /* Member functions */ function setPrice($par){ $this->price = $par; } function getPrice(){ echo $this->price ."<br/>"; } function setTitle($par){ $this->title = $par; } function getTitle(){ echo $this->title ." <br/>"; } } ?>
变量**$this**是一个特殊变量,它指的是同一个对象,即自身。
在PHP中创建对象
定义好类之后,就可以创建任意数量的该类类型的对象。下面是一个使用new运算符创建对象的示例。
$physics = new Books; $maths = new Books; $chemistry = new Books;
这里我们创建了三个对象,这些对象彼此独立,各自存在。接下来我们将看到如何访问成员函数和处理成员变量。
调用成员函数
创建对象后,就可以调用与该对象相关的成员函数。一个成员函数只能处理相关对象的成员变量。
下面的示例演示了如何通过调用成员函数来设置三本书的标题和价格。
$physics->setTitle( "Physics for High School" ); $chemistry->setTitle( "Advanced Chemistry" ); $maths->setTitle( "Algebra" ); $physics->setPrice( 10 ); $chemistry->setPrice( 15 ); $maths->setPrice( 7 );
现在,您可以调用另一个成员函数来获取上面示例中设置的值。
$physics->getTitle(); $chemistry->getTitle(); $maths->getTitle(); $physics->getPrice(); $chemistry->getPrice(); $maths->getPrice();
这将产生以下结果:
Physics for High School Advanced Chemistry Algebra 10 15 7
构造函数
构造函数是一种特殊的函数,每当创建对象时都会自动调用。因此,我们可以充分利用这种特性,通过构造函数初始化许多内容。
PHP 提供了一个名为__construct()的特殊函数来定义构造函数。您可以向构造函数传递任意数量的参数。
下面的示例将为 Books 类创建一个构造函数,并在对象创建时初始化书籍的价格和标题。
function __construct( $par1, $par2 ) { $this->title = $par1; $this->price = $par2; }
现在,我们不需要单独调用 set 函数来设置价格和标题。我们只需要在对象创建时初始化这两个成员变量。请查看下面的示例:
$physics = new Books( "Physics for High School", 10 ); $maths = new Books ( "Advanced Chemistry", 15 ); $chemistry = new Books ("Algebra", 7 ); /* Get those set values */ $physics->getTitle(); $chemistry->getTitle(); $maths->getTitle(); $physics->getPrice(); $chemistry->getPrice(); $maths->getPrice();
这将产生以下结果:
Physics for High School Advanced Chemistry Algebra 10 15 7
析构函数
像构造函数一样,您可以使用函数__destruct()定义析构函数。您可以在析构函数中释放所有资源。
继承
PHP 类定义可以使用 extends 子句从父类定义继承。语法如下:
class Child extends Parent { <definition body> }
继承的效果是子类(或子类或派生类)具有以下特性:
自动拥有父类所有成员变量声明。
自动拥有与父类相同的成员函数,这些函数(默认情况下)的工作方式与父类中的函数相同。
下面的示例继承 Books 类,并根据需求添加更多功能。
class Novel extends Books { var $publisher; function setPublisher($par){ $this->publisher = $par; } function getPublisher(){ echo $this->publisher. "<br />"; } }
现在,除了继承的函数外,Novel 类还保留了两个额外的成员函数。
函数重写
子类中的函数定义会覆盖父类中同名函数的定义。在子类中,我们可以修改从父类继承的函数的定义。
在下面的示例中,getPrice 和 getTitle 函数被重写以返回一些值。
function getPrice() { echo $this->price . "<br/>"; return $this->price; } function getTitle(){ echo $this->title . "<br/>"; return $this->title; }
公共成员
除非另行指定,否则类的属性和方法都是公共的。也就是说,它们可以在三种情况下访问:
从声明它的类之外
从声明它的类内部
从实现声明它的类的另一个类内部
到目前为止,我们看到的所有成员都是公共成员。如果要限制类的成员的可访问性,则可以将类成员定义为private或protected。
私有成员
通过将成员指定为私有,您可以将其可访问性限制在声明它的类中。私有成员不能从继承声明它的类的类中引用,也不能从类外部访问。
可以使用成员前面的private关键字将类成员设为私有。
class MyClass { private $car = "skoda"; $driver = "SRK"; function __construct($par) { // Statements here run every time // an instance of the class // is created. } function myPublicFunction() { return("I'm visible!"); } private function myPrivateFunction() { return("I'm not visible outside!"); } }
当另一个类使用 extends 继承MyClass类时,myPublicFunction() 将可见,$driver 也将可见。扩展类将无法感知或访问 myPrivateFunction 和 $car,因为它们被声明为私有的。
受保护成员
受保护的属性或方法可在声明它的类中访问,也可在扩展该类的类中访问。受保护的成员在这两种类之外不可用。可以使用成员前面的protected关键字将类成员设为受保护。
这是 MyClass 的不同版本:
class MyClass { protected $car = "skoda"; $driver = "SRK"; function __construct($par) { // Statements here run every time // an instance of the class // is created. } function myPublicFunction() { return("I'm visible!"); } protected function myPrivateFunction() { return("I'm visible in child class!"); } }
接口
接口的定义是为了为实现者提供通用的函数名称。不同的实现者可以根据自己的需求实现这些接口。可以说,接口是由开发人员实现的骨架。
从 PHP5 开始,可以像这样定义接口:
interface Mail { public function sendMail(); }
然后,如果另一个类实现了该接口,则如下所示:
class Report implements Mail { // sendMail() Definition goes here }
常量
常量有点像变量,因为它保存一个值,但实际上更像一个函数,因为常量是不可变的。一旦声明了常量,它就不会改变。
声明一个常量很容易,就像在这个版本的 MyClass 中一样:
class MyClass { const requiredMargin = 1.7; function __construct($incomingValue) { // Statements here run every time // an instance of the class // is created. } }
在这个类中,requiredMargin 是一个常量。它使用关键字 const 声明,在任何情况下都不能将其更改为 1.7 以外的任何值。请注意,常量的名称前面没有 $ 符号,变量名则有。
抽象类
抽象类是不能实例化,只能继承的类。您可以使用关键字abstract声明抽象类,如下所示:
从抽象类继承时,必须通过子类定义父类声明中标记为抽象的所有方法;此外,这些方法必须使用相同可见性定义。
abstract class MyAbstractClass { abstract function myAbstractFunction() { } }
请注意,抽象类中的函数定义也必须以关键字 abstract 开头。在非抽象类中拥有抽象函数定义是非法的。
static 关键字
将类成员或方法声明为静态,可以无需实例化类即可访问它们。声明为静态的成员不能使用实例化类对象访问(尽管可以使用静态方法)。
试试下面的例子:
<?php class Foo { public static $my_static = 'foo'; public function staticValue() { return self::$my_static; } } print Foo::$my_static . "\n"; $foo = new Foo(); print $foo->staticValue() . "\n"; ?>
final 关键字
PHP 5 引入了 final 关键字,它通过在定义前添加 final 来阻止子类覆盖方法。如果类本身被定义为 final,则它不能被扩展。
下面的示例将导致致命错误:无法覆盖最终方法 BaseClass::moreTesting()
<?php class BaseClass { public function test() { echo "BaseClass::test() called<br>"; } final public function moreTesting() { echo "BaseClass::moreTesting() called<br>"; } } class ChildClass extends BaseClass { public function moreTesting() { echo "ChildClass::moreTesting() called<br>"; } } ?>
调用父构造函数
与其为子类编写一个全新的构造函数,不如通过显式调用父构造函数,然后执行子类实例化所需的任何操作来编写它。这是一个简单的例子:
class Name { var $_firstName; var $_lastName; function Name($first_name, $last_name) { $this->_firstName = $first_name; $this->_lastName = $last_name; } function toString() { return($this->_lastName .", " .$this->_firstName); } } class NameSub1 extends Name { var $_middleInitial; function NameSub1($first_name, $middle_initial, $last_name) { Name::Name($first_name, $last_name); $this->_middleInitial = $middle_initial; } function toString() { return(Name::toString() . " " . $this->_middleInitial); } }
在这个例子中,我们有一个父类(Name),它有一个带两个参数的构造函数,还有一个子类(NameSub1),它有一个带三个参数的构造函数。NameSub1 的构造函数通过使用 :: 语法显式调用其父构造函数(传递其中两个参数),然后设置一个附加字段来工作。类似地,NameSub1 根据它覆盖的父函数定义其非构造函数 toString() 函数。
注意 - 构造函数可以与类名相同。在上面的示例中已定义。
PHP – 类和对象
类和对象的概念是 PHP 面向对象编程方法的核心。类是其对象的模板描述。它包括处理属性的属性和函数。对象是其类的实例。它以类中定义的属性和函数为特征。
在 PHP 中定义类
要定义类,PHP 有一个关键字“class”。同样,PHP 提供关键字“new”来声明任何给定类的对象。
在PHP中定义新类的通用形式如下:
<?php class phpClass { var $var1; var $var2 = "constant string"; function myfunc ($arg1, $arg2) { [..] } [..] } ?>
关键字class后面是您要定义的类的名称。类名遵循与 PHP 变量相同的命名约定。后面是一对大括号,包含任意数量的变量声明(属性)和函数定义。
变量声明以另一个保留关键字var开头,后面跟着传统的$variable名称;它们也可能具有对常量的初始赋值。
函数定义看起来很像独立的 PHP 函数,但它们是局部的类,将用于设置和访问对象数据。类中的函数也称为方法。
示例
这是一个定义 Book 类型的类的示例:
class Book { /* Member variables */ var $price; var $title; /* Member functions */ function setPrice($par){ $this->price = $par; } function getPrice(){ echo $this->price ."<br/>"; } function setTitle($par){ $this->title = $par; } function getTitle(){ echo $this->title ." <br/>"; } }
伪变量$this在从对象上下文中调用方法时可用。$this引用调用对象。
Book 类有两个成员变量(或属性) - $title和$price。成员变量(有时也称为实例变量)通常每个对象的取值不同;例如,每本书的标题和价格都与其他书籍不同。
Book 类具有函数(在类中定义的函数称为方法)setTitle() 和 setPrice()。这些函数是通过引用对象和参数调用的,用于分别设置标题和价格成员变量的值。
Book 类还具有getTitle()和getPrice()方法。调用时,它们返回传递引用的对象的标题和价格。
定义类后,可以使用 new 运算符声明一个或多个对象。
$b1 = new Book; $b2 = new Book;
new运算符分配每个对象成员变量和方法所需的内存。这里我们创建了两个对象,这些对象彼此独立,各自存在。
每个对象都可以使用“->”运算符访问其成员变量和方法。例如,b1对象的$title属性是“$b1->title”,要调用setTitle()方法,请使用“$b1->setTitle()”语句。
要设置b1对象的标题和价格,
$b1->setTitle("PHP Programming"); $b1->setPrice(450);
类似地,以下语句获取b1书的标题和价格:
echo $b1->getPrice(); echo $b1->getTitle();
示例
下面是定义 Book 类、声明两个对象并调用成员函数的完整 PHP 脚本。
<?php class Book { /* Member variables */ var $price; var $title; /* Member functions */ function setPrice($par){ $this->price = $par; } function getPrice(){ echo $this->price ."\n"; } function setTitle($par){ $this->title = $par; } function getTitle(){ echo $this->title ."\n"; } } $b1 = new Book; $b2 =new Book; $b1->setTitle("PHP Programming"); $b1->setPrice(450); $b2->setTitle("PHP Fundamentals"); $b2->setPrice(275); $b1->getTitle(); $b1->getPrice(); $b2->getTitle(); $b2->getPrice(); ?>
它将产生以下输出:
PHP Programming 450 PHP Fundamentals 275
PHP – 构造函数和析构函数
与大多数面向对象的语言一样,您也可以在 PHP 中的类中定义构造函数。当您使用 new 运算符声明对象时,其成员变量不会被赋值。构造函数用于在声明时初始化每个新对象。PHP 还支持使用析构函数,该函数会在对象不再有任何引用时将其从内存中销毁。
__construct() 函数
PHP 提供了一个 __construct() 函数来初始化对象。
__construct(mixed ...$values = ""): void
类中的构造方法会在每个新创建的对象上自动调用。请注意,定义构造函数不是强制性的。但是,如果存在,它适合对象在使用前可能需要的任何初始化。
您可以向构造函数传递任意数量的参数。__construct() 函数没有任何返回值。
让我们在上一章中使用的 Book 类中定义一个构造函数
<?php class Book { /* Member variables */ var $price; var $title; /*Constructor*/ function __construct(){ $this->title = "PHP Fundamentals"; $this->price = 275; } /* Member functions */ function getPrice() { echo "Price: $this->price \n"; } function getTitle(){ echo "Title: $this->title \n"; } } $b1 = new Book; $b1->getTitle(); $b1->getPrice(); ?>
它将产生以下输出:
Title: PHP Fundamentals Price: 275
参数化构造函数
由于构造函数在对象声明后立即被调用,因此 $b1 的成员变量已初始化,而无需调用 setTitle() 和 setPrice() 方法。但是,此构造函数将为每个对象调用,因此每个对象都具有相同标题和价格属性值。
要使用不同的值初始化每个对象,请使用参数定义__construct()函数。
将__construct()函数的定义更改为:
function __construct($param1, $param2) { $this->title = $param1; $this->price = $param2; }
要初始化对象,请在声明中将值传递给括号内的参数。
$b1 = new Book("PHP Fundamentals", 375);
示例
现在,您可以使每个对象的成员变量具有不同的值。
<?php class Book { /* Member variables */ var $price; var $title; /*Constructor*/ function __construct($param1, $param2) { $this->title = $param1; $this->price = $param2; } /* Member functions */ function getPrice(){ echo "Price: $this->price \n"; } function getTitle(){ echo "Title: $this->title \n"; } } $b1 = new Book("PHP Fundamentals", 375); $b2 = new Book("PHP Programming", 450); $b1->getTitle(); $b1->getPrice(); $b2->getTitle(); $b2->getPrice(); ?>
它将产生以下输出:
Title: PHP Fundamentals Price: 375 Title: PHP Programming Price: 450
构造函数重载
方法重载是面向对象编程中的一个重要概念,其中一个类可能有多个构造函数定义,每个构造函数具有不同数量的参数。但是,PHP 不支持方法重载。可以通过在构造函数中使用具有默认值的参数来克服此限制。
将 __construct() 函数更改为:
function __construct($param1="PHP Basics", $param2=380) { $this->title = $param1; $this->price = $param2; }
现在,声明一个对象而不传递参数,另一个对象传递参数。一个不带参数的对象将使用默认参数初始化,另一个对象将使用传递的值初始化。
$b1 = new Book(); $b2 = new Book("PHP Programming", 450);
它将产生以下输出:
Title: PHP Basics Price: 380 Title: PHP Programming Price: 450
构造函数中的类型声明
PHP 7.0 及以后版本允许为函数参数声明标量类型,因此构造函数 `__construct()` 可以定义为:
function __construct(string $param1="PHP Basics", int $param2=380) { $this->title = $param1; $this->price = $param2; }
在 PHP 的早期版本中,允许使用类名来定义构造函数,但是自 PHP 8.0 起,此特性已被弃用。
__destruct() 函数
PHP 也具有 `__destruct()` 函数。它实现了类似于其他面向对象语言(如 C++)中的析构函数的概念。一旦没有其他对特定对象的引用,就会调用析构方法。
__destruct(): void
__destruct() 函数没有任何参数,也没有任何返回值。可以通过在函数内部放置 `var_dump($this)` 来验证 `__destruct()` 函数在任何对象超出作用域时自动调用的事实。
如上所述,**$this** 携带对调用对象的引用,转储显示成员变量被设置为 NULL。
在 Book 类中添加析构函数如下:
function __destruct() { var_dump($this); echo "object destroyed"; }
程序退出时,将显示以下**输出**:
object(Book)#1 (2) { ["price"]=> NULL ["title"]=> NULL } object destroyed
PHP – 访问修饰符
在 PHP 中,关键字 **public、private** 和 **protected** 被称为**访问修饰符**。这些关键字控制类属性和方法的可访问性或可见性范围。在声明成员变量和定义成员函数时,会在前面加上这些关键字中的一个。
PHP 代码是否可以自由访问类成员,或者是否限制其访问,或者是否有条件访问,取决于这些关键字:
**public** – 类成员可以从任何地方访问,即使是从类的作用域之外,但只能通过对象引用。
**private** – 类成员只能在类本身内部访问。它阻止外部类访问成员,即使使用类实例的引用也不行。
**protected** – 成员只能在类及其子类内部访问,其他地方都不能访问。
数据封装的原则的面向对象编程方法学的基石。它指的是将对象的成员变量或属性与类外部的环境隔离开来的机制,只允许通过类中可用的方法或函数进行受控访问。
为了实现封装,类的成员变量被设置为**private**,而方法被设置为**public**。
公共成员
在 PHP 中,类成员(成员变量和成员函数)默认为 public。
示例
在下面的程序中,对象的成员变量 title 和 price 可以自由地从类外部访问,因为它们默认为 public,除非另有指定。
<?php class Book { /* Member variables */ var $price; var $title; /*Constructor*/ function __construct(string $param1="PHP Basics", int $param2=380) { $this->title = $param1; $this->price = $param2; } function getPrice() { echo "Title: $this->price \n"; } function getTitle() { echo "Price: $this->title \n"; } } $b1 = new Book(); echo "Title : $b1->title Price: $b1->price"; ?>
它将产生以下输出:
Title : PHP Basics Price: 380
私有成员
如上所述,封装的原则要求不应该直接访问成员变量。只有方法才能访问数据成员。因此,我们需要将成员变量设置为 private,并将方法设置为 public。
<?php class Book { /* Member variables */ private $price; private $title; /*Constructor*/ function __construct(string $param1="PHP Basics", int $param2=380) { $this->title = $param1; $this->price = $param2; } public function getPrice() { echo "Price: $this->price \n"; } public function getTitle() { echo "Title: $this->title \n;"; } } $b1 = new Book(); $b1->getTitle(); $b1->getPrice(); echo "Title : $b1->title Price: $b1->price"; ?>
输出
现在,`getTitle()` 和 `getPrice()` 函数是 public 的,可以访问私有成员变量 title 和 price。但是,在尝试直接显示 title 和 price 时,会遇到错误,因为它们不是 public 的。
Title: PHP Basics Price: 380 Fatal error: Uncaught Error: Cannot access private property Book::$title in hello.php:31
受保护成员
指定对类成员的受保护访问的效果在类继承的情况下是有效的。我们知道,public 成员可以从类外部的任何地方访问,而 private 成员则不允许从类外部的任何地方访问。
**protected** 关键字允许访问同一类的对象及其继承类的对象,而拒绝任何其他环境访问。
让我们将 Book 类示例中的 title 成员设置为 protected,并将 price 保持为 private。
class Book { /* Member variables */ private $price; protected $title; # rest of the code kept as it is } $b1 = new Book(); $b1->getTitle(); $b1->getPrice();
PHP 允许访问这两个成员变量,因为对象属于同一类。
让我们添加一个继承 Book 类的 **mybook** 类:
class mybook extends Book { # no additional members defined }
其对象仍然能够访问成员变量,因为子类继承了父类的 public 和 protected 成员。
但是,将 **mybook** 类作为一个独立的类(不扩展 Book 类),并定义一个 `getmytitle()` 函数,该函数尝试访问 Book 类的受保护的 title 成员变量。
class mybook { public function getmytitle($b) { echo "Title: $b->title <br/>"; } } $b1 = new mybook(); $b = new Book(); $b1->getmytitle($b);
由于 `getmytitle()` 函数试图打印 Book 对象的 title,因此会引发显示 **Cannot access protected property Book::$title** 的错误消息。
示例
尝试运行以下代码:
<?php class Book { private $price; protected $title; function __construct(string $param1="PHP Basics", int $param2=380) { $this->title = $param1; $this->price = $param2; } public function getPrice(){ echo "Price: $this->price <br/>"; } public function getTitle(){ echo "Title: $this->title <br/>"; } } class mybook { public function getmytitle($b) { echo "Title: $b->title <br/>"; } } $b1 = new mybook(); $b = new Book(); $b1->getmytitle($b); ?>
它将产生以下输出:
PHP Fatal error: Uncaught Error: Cannot access protected property Book::$title in /home/cg/root/97848/main.php:18
因此,可以看出,受保护的成员只能被同一类和继承类的对象访问。对于所有其他环境,受保护的成员都是不可访问的。
可访问性规则可以由下表概括:
PHP – 继承
继承是面向对象编程方法学的基石之一。继承是一种软件建模方法,它能够扩展现有类的功能来构建新类,而不是从头开始构建。
PHP 提供了在其对象模型中实现继承的所有功能。在 PHP 软件开发中加入继承可以重用代码,消除冗余代码重复,并实现逻辑组织。
假设您需要设计一个新类,其大部分功能已经在现有类中定义好了。继承允许您扩展现有类,添加或删除其功能并开发新类。事实上,PHP 有 "extends" 关键字来建立现有类和新类之间的继承关系。
class newclass extends oldclass { ... ... }
当一个新类(以下称为继承类、子类、子类等)与现有类(称为基类、超类、父类等)具有 "IS A" 关系时,继承就会出现。
在 PHP 中,当通过扩展另一个类来定义一个新类时,子类会继承父类的 public 和 protected 方法、属性和常量。您可以自由地覆盖继承方法的功能,否则它将保留在父类中定义的功能。
示例
请看以下示例:
<?php class myclass { public function hello() { echo "Hello from the parent class" . PHP_EOL; } public function thanks() { echo "Thank you from parent class" . PHP_EOL; } } class newclass extends myclass { public function thanks() { echo "Thank you from the child class" . PHP_EOL; } } # object of parent class $obj1 = new myclass; $obj1->hello(); $obj1->thanks(); # object of child class $obj2 = new newclass; $obj2->hello(); $obj2->thanks(); ?>
它将产生以下输出:
Hello from the parent class Thank you from parent class Hello from the parent class Thank you from the child class
如前所述,子类继承父类的 public 和 protected 成员(属性和方法)。子类可以引入额外的属性或方法。
在下面的示例中,我们使用 **Book 类**作为父类。在这里,我们创建一个扩展 Book 类的 **ebook 类**。新类有一个额外的属性 - **format**(指示电子书的文件格式 - EPUB、PDF、MOBI 等)。ebook 类定义了两个新方法来初始化和输出电子书数据 - **getebook()** 和 **dispebook()**。
示例
继承示例的完整代码如下:
<?php class Book { /* Member variables */ protected int $price; protected string $title; public function getbook(string $param1, int $param2) { $this->title = $param1; $this->price = $param2; } public function dispbook() { echo "Title: $this->title Price: $this->price \n"; } } class ebook extends Book { private string $format; public function getebook(string $param1, int $param2, string $param3) { $this->title = $param1; $this->price = $param2; $this->format = $param3; } public function dispebook() { echo "Title: $this->title Price: $this->price\n"; echo "Format: $this->format \n"; } } $eb = new ebook; $eb->getebook("PHP Fundamentals", 450, "EPUB"); $eb->dispebook(); ?>
浏览器**输出**如下所示:
Title: PHP Fundamentals Price: 450 Format: EPUB
如果您仔细查看 `getebook()` 函数,前两个赋值语句实际上是 `getbook()` 函数,`ebook` 类继承了该函数。因此,我们可以使用 `parent` 关键字和作用域解析运算符来调用它。
将 `getebook()` 函数代码更改为以下内容:
public function getebook(string $param1, int $param2, string $param3) { parent::getbook($param1, $param2); $this->format = $param3; }
类似地,`dispebook()` 函数中的第一个 `echo` 语句被对父类中 `dispbook()` 函数的调用所取代:
public function dispebook() { parent::dispbook(); echo "Format: $this->format<br/>"; }
继承中的构造函数
父类的构造函数会被子类继承,但是如果子类定义了构造函数,则不能直接在子类中调用它。
为了运行父构造函数,需要在子构造函数中调用 `parent::__construct()`。
示例
请看以下示例:
<?php class myclass{ public function __construct(){ echo "This is parent constructor". PHP_EOL; } } class newclass extends myclass { public function __construct(){ parent::__construct(); echo "This is child class destructor" . PHP_EOL; } } $obj = new newclass(); ?>
它将产生以下输出:
This is parent constructor This is child class destructor
但是,如果子类没有构造函数,那么它可以像普通的类方法一样从父类继承(如果它没有声明为 private)。
示例
请看以下示例:
<?php class myclass{ public function __construct(){ echo "This is parent constructor". PHP_EOL; } } class newclass extends myclass{ } $obj = new newclass(); ?>
它将产生以下输出:
This is parent constructor
PHP 不允许通过扩展多个父类来开发类。您可以进行**层次继承**,其中类 B 扩展类 A,类 C 扩展类 B,依此类推。但是 PHP 不支持**多重继承**,其中类 C 试图同时扩展类 A 和类 B。但是,我们可以扩展一个类并实现一个或多个**接口**。我们将在后续章节中学习接口。
PHP – 类常量
PHP 允许在类中定义一个标识符为“类常量”,其值为常量值,该值在每个类中保持不变。为了与类中的变量或属性区分开来,常量的名称前面不加通常的“$”符号,而是用“const”限定符定义。请注意,PHP 程序还可以使用 `define()` 函数创建全局常量。
常量的默认可见性是 public,尽管可以在定义中使用其他修饰符。常量的值必须是一个表达式,而不是一个变量,也不是一个函数调用/属性。常量的值可以通过类名使用作用域解析运算符来访问。但在方法内部,可以通过 `self` 变量来引用它。
class SomeClass { const CONSTANT = 'constant value'; } echo SomeClass::CONSTANT;
**常量名称区分大小写**。按照惯例,常量的名称使用大写字母。
示例
此示例演示了如何定义和访问类常量:
<?php class square { const PI=M_PI; var $side=5; function area() { $area=$this->side**2*self::PI; return $area; } } $s1=new square(); echo "PI=". square::PI . "\n"; echo "area=" . $s1->area(); ?>
它将产生以下输出:
PI=3.1415926535898 area=78.539816339745
类常量作为表达式
在此示例中,类常量被赋值一个表达式:
<?php const X = 22; const Y=7; class square { const PI=X/Y; var $side=5; function area() { $area=$this->side**2*self::PI; return $area; } } $s1=new square(); echo "PI=". square::PI . "\n"; echo "area=" . $s1->area(); ?>
它将产生以下输出:
PI=3.1428571428571 area=78.571428571429
类常量可见性修饰符
请看以下示例:
<?php class example { const X=10; private const Y=20; } $s1=new example(); echo "public=". example::X. "\n"; echo "private=" . $s1->Y ."\n"; echo "private=" . $example::Y ."\n"; ?>
它将产生以下输出:
public=10 PHP Notice: Undefined property: example::$Y in line 11 private= PHP Fatal error: Uncaught Error: Cannot access private const example::Y
PHP – 抽象类
PHP 的保留字列表包括 "abstract" 关键字。当用 "abstract" 关键字定义一个类时,它不能被实例化,也就是说,您不能声明该类的新的对象。抽象类可以被另一个类扩展。
abstract class myclass { // class body }
如上所述,**您不能声明此类的对象**。因此,以下语句:
$obj = new myclass;
将导致如下所示的**错误**消息:
PHP Fatal error: Uncaught Error: Cannot instantiate abstract class myclass
抽象类可以包含属性、常量或方法。类成员可以是 public、private 或 protected 类型。类中的一个或多个方法也可以定义为 abstract。
如果类中的任何方法是 abstract 的,则类本身必须是抽象类。换句话说,普通类不能包含抽象方法。
这将引发**错误**:
class myclass { abstract function myabsmethod($arg1, $arg2); function mymethod() #this is a normal method { echo "Hello"; } }
**错误消息**将显示为:
PHP Fatal error: Class myclass contains 1 abstract method and must therefore be declared abstract
您可以使用抽象类作为父类,并用子类扩展它。但是,子类必须为父类中的每个抽象方法提供具体的实现,否则将遇到错误。
示例
在下面的代码中,**myclass** 是一个带有 **myabsmethod()** 作为抽象方法的**抽象类**。它的派生类是 **mynewclass**,但是它没有在其父类中实现抽象方法。
<?php abstract class myclass { abstract function myabsmethod($arg1, $arg2); function mymethod() { echo "Hello"; } } class newclass extends myclass { function newmethod() { echo "World"; } } $m1 = new newclass; $m1->mymethod(); ?>
在这种情况下,**错误消息**是:
PHP Fatal error: Class newclass contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (myclass::myabsmethod)
这表明 newclass 应该实现抽象方法,或者应该声明为抽象类。
示例
在下面的 PHP 脚本中,我们有一个名为 marks 的抽象类,其中包含一个抽象方法 percent()。另一个名为 student 的类扩展了 marks 类并实现了它的 percent() 方法。
<?php abstract class marks { protected int $m1, $m2, $m3; abstract public function percent(): float; } class student extends marks { public function __construct($x, $y, $z) { $this->m1 = $x; $this->m2 = $y; $this->m3 = $z; } public function percent(): float { return ($this->m1+$this->m2+$this->m3)*100/300; } } $s1 = new student(50, 60, 70); echo "Percentage of marks: ". $s1->percent() . PHP_EOL; ?>
它将产生以下输出:
Percentage of marks: 60
PHP 中接口和抽象类的区别
PHP 中抽象类的概念与接口非常相似。但是,接口和抽象类之间存在一些区别。
抽象类 | 接口 |
---|---|
使用 abstract 关键字定义抽象类 | 使用 interface 关键字定义接口 |
抽象类不能被实例化 | 接口不能被实例化。 |
抽象类可以包含普通方法和抽象方法 | 接口必须仅声明带参数和返回类型的方法,而不能包含任何方法体。 |
子类扩展抽象类,必须实现所有抽象方法 | 另一个类必须实现接口,并且必须提供接口中所有方法的功能。 |
可以具有公共、私有或受保护的属性 | 接口中不能声明属性 |
PHP – 接口
正如类是其对象的模板一样,PHP 中的接口可以称为类的模板。我们知道,当实例化一个类时,类中定义的属性和方法都可用。类似地,PHP 中的接口声明方法及其参数和返回值。这些方法没有任何方法体,即接口中未定义任何功能。
具体类必须实现接口中的方法。换句话说,当一个类实现一个接口时,它必须为接口中的所有方法提供功能。
接口的定义方式与类的定义方式相同,只是使用关键字“interface”代替 class。
interface myinterface { public function myfunction(int $arg1, int $arg2); public function mymethod(string $arg1, int $arg2); }
请注意,接口内部的方法没有提供任何功能。这些方法的定义必须由实现此接口的类提供。
当我们定义子类时,我们使用关键字“extends”。在这种情况下,该类必须使用关键字“implements”。
接口中声明的所有方法都必须定义,并且参数和返回值的数量和类型必须相同。
class myclass implements myinterface { public function myfunction(int $arg1, int $arg2) { ## implementation of myfunction; } public function mymethod(string $arg1, int $arg2) { # implementation of mymethod; } }
注意,接口中声明的所有方法都必须是公共的。
示例
让我们定义一个名为 shape 的接口。形状具有一定的面积。您有不同几何形状的形状,例如矩形、圆形等,每个形状都有一个面积,用不同的公式计算。因此,shape 接口声明一个返回浮点值的方法 area()。
interface shape { public function area(): float; }
接下来,我们将定义一个实现 shape 接口的 circle 类,要实现该接口,类必须提供接口中函数的具体实现。这里,circle 类中的 area() 函数计算给定半径的圆的面积。
class circle implements shape { var $radius; public function __construct($arg1) { $this->radius = $arg1; } public function area(): float { return pow($this->radius,2)*pi(); } }
现在我们可以声明一个 circle 类的对象,并调用 area() 方法。
$cir = new circle(5); echo "Radius : " . $cir->radius . " Area of Circle: " . $cir->area(). PHP_EOL;
只要实现类提供了接口中每个方法的功能,任何数量的类(可能彼此无关)都可以实现一个接口。
这是一个实现 shape 接口的 Square 类。area() 方法返回 side 属性的平方。
class square implements shape { var $side; public function __construct($arg1) { $this->side = $arg1; } public function area(): float { return pow($this->side, 2); } }
同样,创建一个 Square 对象并调用 area() 方法。
示例
以下是 shape 接口的完整代码,由 circle 和 Square 类实现:
<?php interface shape { public function area(): float; } class square implements shape { var $side; public function __construct($arg1) { $this->side = $arg1; } public function area(): float { return pow($this->side, 2); } } class circle implements shape { var $radius; public function __construct($arg1) { $this->radius = $arg1; } public function area(): float { return pow($this->radius,2)*pi(); } } $sq = new square(5); echo "Side: " . $sq->side . " Area of Square: ". $sq->area() . PHP_EOL; $cir = new circle(5); echo "Radius: " . $cir->radius . " Area of Circle: " . $cir->area(). PHP_EOL; ?>
它将产生以下输出:
Side: 5 Area of Square: 25 Radius: 5 Area of Circle: 78.539816339745
PHP 中的多重继承
PHP 没有提供构建扩展两个父类的子类的功能。换句话说,语句:
class child extends parent1, parent2
不被接受。但是,PHP 确实支持具有扩展一个父类并实现一个或多个接口的子类。
让我们来看下面的例子,它展示了一个扩展另一个类并实现接口的类。
首先是父类 marks。它有三个实例变量或属性 $m1、$m2、$m3,分别代表三个科目的分数。提供了一个构造函数来初始化对象。
class marks { protected int $m1, $m2, $m3; public function __construct($x, $y, $z) { $this->m1 = $x; $this->m2 = $y; $this->m3 = $z; } }
现在我们提供一个名为 percent 的接口,它声明一个方法 percent(),该方法应该返回一个浮点数,但没有函数体。
interface percent { public function percent(): float; }
现在我们开发一个扩展 marks 类并为接口中的 percent() 方法提供实现的类。
class student extends marks implements percent { public function percent(): float { return ($this->m1+$this->m2+$this->m3)*100/300; } }
student 类继承了父构造函数,但提供了 parent() 方法的实现,该方法返回分数的百分比。
示例
完整的代码如下:
<?php class marks { protected int $m1, $m2, $m3; public function __construct($x, $y, $z) { $this->m1 = $x; $this->m2 = $y; $this->m3 = $z; } } interface percent { public function percent(): float; } class student extends marks implements percent { public function percent(): float { return ($this->m1+$this->m2+$this->m3)*100/300; } } $s1 = new student(50, 60, 70); echo "Percentage of marks: ". $s1->percent() . PHP_EOL; ?>
它将产生以下输出:
Percentage of marks: 60
PHP 中的接口定义了一个方法框架,类使用该框架来提供自己不同的但具体的实现。
PHP – 特性 (Traits)
在 PHP 中,一个类只能继承自一个父类,PHP 中未定义多重继承。PHP 中的特性是为了克服这个限制而引入的。您可以在特性中定义一个或多个方法,这些方法可以在各种独立的类中自由重用。
语法
使用以下语法使用“trait”关键字:
trait mytrait { function method1() { /*function body*/ } function method2() { /*function body*/ } }
为了能够调用特性中的方法,需要使用 use 关键字将其提供给另一个类。
示例
特性类似于类,但仅用于以细粒度和一致的方式组合功能。无法自行实例化特性。
<?php trait mytrait { public function hello() { echo "Hello World from " . __TRAIT__ . ""; } } class myclass { use mytrait; } $obj = new myclass(); $obj->hello(); ?>
它将产生以下输出:
Hello World from mytrait
示例
一个特性可以在多个类中使用。下面的例子有一个包含 avg() 函数的 mytrait。它在 marks 类中使用。percent() 方法内部调用特性中的 avg() 函数。
请看以下示例:
<?php trait mytrait { function avg($x, $y) { return ($x+$y)/2; } } class marks { use mytrait; private int $m1, $m2; function __construct($x, $y) { $this->m1 = $x; $this->m2 = $y; } function percent():float { return $this->avg($this->m1, $this->m2); } } $obj = new marks(50, 60); echo "percentage: " . $obj->percent(); ?>
它将产生以下输出:
percentage: 55
使用多个特性
一个类可以使用多个特性。这里我们有两个特性,每个特性都有一个函数,分别执行两个数字的加法和乘法。两者都在第三个类中使用。
<?php trait addition { function add($x, $y) { return $x+$y; } } trait multiplication { function multiply($x, $y) { return $x*$y; } } class numbers { use addition, multiplication; private int $m1, $m2; function __construct($x, $y) { $this->m1 = $x; $this->m2 = $y; } function calculate():array { $arr = [$this->add($this->m1, $this->m2), $this->multiply($this->m1, $this->m2)]; return $arr; } } $obj = new numbers(50, 60); $res = $obj->calculate(); echo "Addition: " . $res[0] . PHP_EOL; echo "Multiplication: " . $res[1] . PHP_EOL; ?>
它将产生以下输出:
Addition: 110 Multiplication: 3000
覆盖特性函数
当一个类使用某个特性时,它的函数就像子类继承父方法一样可用。特性函数也可以被重写。
<?php trait mytrait { public function sayHello() { echo 'Hello World!'; } } class myclass { use mytrait; public function sayHello() { echo 'Hello PHP!'; } } $o = new myclass(); $o->sayHello(); ?>
它将产生以下输出:
Hello PHP!
“insteadof”关键字
有时,两个或更多特性可能具有相同名称的函数。因此,在类中使用它们会产生歧义的情况。PHP 提供 insteadof 关键字来告诉解析器您打算使用哪个特性的函数。
<?php trait mytrait { public function sayHello() { echo 'Hello World!'; } } trait newtrait { public function sayHello() { echo 'Hello PHP!'; } } class myclass { use mytrait, newtrait{ newtrait::sayHello insteadof mytrait; } } $o = new myclass(); $o->sayHello(); ?>
它将产生以下输出:
Hello PHP!
特性函数的别名
如果您希望能够调用来自两个特性的函数,即使它们具有相同名称的函数,一种解决方法是对其中一个函数指定别名。
示例
在下面的示例中,我们将 mytrait 中的 sayHello() 称为 hello():
<?php trait mytrait { public function sayHello() { echo 'Hello World!' . PHP_EOL; } } trait newtrait { public function sayHello() { echo 'Hello PHP!' . PHP_EOL; } } class myclass { use mytrait, newtrait{ mytrait::sayHello as hello; newtrait::sayHello insteadof mytrait; } } $o = new myclass(); $o->hello(); $o->sayHello(); ?>
它将产生以下输出:
Hello World! Hello PHP!
PHP – 静态方法
PHP 中的“static”关键字用于在 PHP 类中定义静态属性和静态方法。需要注意的是,static 关键字也用于定义静态变量和静态匿名函数。本章讨论 PHP 类中的静态方法。
在类定义中,用 static 修饰符声明的函数成为其静态方法。
class myclass { public static function myStaticMethod() { // ... }
您不需要创建类的实例即可调用其静态方法。静态方法通过类名和作用域解析运算符来调用。静态方法调用的语法为:
myclass::myStaticMethod();
由于静态方法无需创建类的实例即可调用,因此伪变量 $this 在静态方法内部不可用。静态方法允许被对象调用,尽管将实例方法作为静态方法调用会引发错误。
示例
请看以下示例:
<?php class myclass { /* Member variables */ static int $var1 = 0; public static function mystaticmethod() { echo "This is a static method". PHP_EOL; } public function myinstancemethod() { echo "This is an instance method". PHP_EOL; } } myclass::mystaticmethod(); $obj = new myclass; $obj->myinstancemethod(); $obj->mystaticmethod(); myclass::myinstancemethod(); ?>
它将产生以下输出:
This is a static method This is an instance method This is a static method PHP Fatal error: Uncaught Error: Non-static method myclass::myinstancemethod() cannot be called statically
静态方法中的“self”关键字
如果您需要从同一类中定义的实例方法内部调用静态方法,则必须使用 self 关键字引用类名,后跟作用域解析运算符(例如 self::mystaticmethod)
<?php class myclass { /* Member variables */ static int $var1 = 0; public static function mystaticmethod() { echo "This is a static method". PHP_EOL; } public function myinstancemethod() { echo "This is an instance method". PHP_EOL; echo "calling static method from instance method" . PHP_EOL; self::mystaticmethod(); } } $obj = new myclass; $obj->myinstancemethod(); ?>
它将产生以下输出:
This is an instance method calling static method from instance method This is a static method
使用“parent”关键字
在继承的情况下,基类中定义的静态方法可以通过派生类的对象或从派生类的实例方法内部调用,方法是使用“parent”关键字引用它。
示例
请看以下示例:
<?php class myclass { /* Member variables */ static int $var1 = 0; public static function mystaticmethod() { echo "This is a static method". PHP_EOL; } public function myinstancemethod() { echo "This is an instance method". PHP_EOL; echo "calling static method from instance method" . PHP_EOL; self::mystaticmethod(); } } class mynewclass extends myclass { public function myfunction() { echo "This an instance method of the derived class" . PHP_EOL; echo "Calling static method of the parent class" . PHP_EOL; parent::mystaticmethod(); } } $obj = new mynewclass; mynewclass::mystaticmethod(); $obj->myfunction(); ?>
它将产生以下输出:
This is a static method This an instance method of the derived class Calling static method of the parent class This is a static method
另一个类中的静态方法
完全可以在一个类中调用另一个类的静态方法。您必须使用其类名前缀其名称,后跟作用域解析运算符。
示例
请看以下示例:
<?php class myclass { /* Member variables */ static int $var1 = 0; public static function mystaticmethod() { echo "This is a static method". PHP_EOL; } } #this is not a derived class class mynewclass { public function myfunction() { echo "This an instance method" . PHP_EOL; echo "Calling static method of the another class" . PHP_EOL; myclass::mystaticmethod(); } } $obj = new mynewclass; $obj->myfunction(); ?>
它将产生以下输出:
This an instance method Calling static method of another class This is a static method
由于$this伪变量对静态方法不可用,因此无法在静态方法内部访问对象的实例变量。它只能处理类的静态属性。
示例
请看以下示例:
<?php class myclass { /* Member variables */ static int $var1 = 0; function __construct() { self::$var1++; echo "object number ". self::$var1 . PHP_EOL; } public static function mystaticmethod() { echo "Number of objects available: " . self::$var1 . PHP_EOL; } } for ($i=1; $i<=3; $i++) { $obj = new myclass; } myclass::mystaticmethod(); ?>
它将产生以下输出:
object number 1 object number 2 object number 3 Number of objects available: 3
PHP – 静态属性
PHP 中的“static”关键字用于在 PHP 类中定义静态属性和静态方法。需要注意的是,static 关键字也用于定义静态变量和静态匿名函数。阅读本章以了解 PHP 类中的静态属性。
在类定义中,用 static 修饰符声明的变量成为其静态属性。static 关键字可以出现在访问修饰符之前或之后。
static private $var1; public static $var2;
如果您想使用类型提示,则类型不能在 static 关键字之前。
static private string $var1; public static float $var2;
类的静态属性的值无法通过其对象(使用 -> 运算符)访问。这样做会导致一条通知,指出将静态属性 myclass::$var1 作为非静态属性访问。相反,静态属性是使用作用域解析运算符(由“::”符号表示)访问的。
示例
请看以下示例:
<?php class myclass { static string $var1 = "My Class"; function __construct() { echo "New object declared" . PHP_EOL; } } $obj = new myclass; echo "accessing static property with scope resolution operator: " . myclass::$var1 . PHP_EOL; echo "accessing static property with -> operator: ". $obj->var1 . PHP_EOL; ?>
它将产生以下输出:
New object declared accessing static property with scope resolution operator: My Class PHP Notice: Accessing static property myclass::$var1 as non static in hello.php on line 14
“self”关键字
要从方法内部访问静态属性,请使用 self 关键字引用当前类。在下面的示例中,类具有一个整数静态属性,每次声明新对象时都会递增。
<?php class myclass { /* Member variables */ static int $var1 = 0; function __construct(){ self::$var1++; echo "object number ". self::$var1 . PHP_EOL; } } for ($i=1; $i<=3; $i++) { $obj = new myclass; } ?>
它将产生以下输出:
object number 1 object number 2 object number 3
“parent”关键字
可以通过使用 parent 关键字引用基类来在继承类的函数内部使用基类的静态属性。您需要使用“parent::static_property”语法。
示例
请看下面的例子:
<?php class myclass { /* Member variables */ static int $var1 = 0; function __construct() { self::$var1++; echo "object number ". self::$var1 . PHP_EOL; } } class newclass extends myclass{ function getstatic() { echo "Static property in parent class: " . parent::$var1 . PHP_EOL; } } $obj = new newclass; $obj->getstatic(); ?>
它将产生以下输出:
object number 1 Static property in parent class: 1
PHP 命名空间
我们经常将文件组织在不同的文件夹中。通常,一个文件夹包含与特定目标、应用程序或类别相关的文件。一个文件夹不能包含两个同名的文件,尽管不同的文件夹可能有同名的文件,以便每个文件的路径不同。
PHP 中命名空间的概念与此有些类似。在 PHP 中,命名空间允许在不同的上下文中使用同名的类、函数或常量,而不会发生任何冲突,从而封装这些项目。
PHP 命名空间是类/函数等的逻辑分组,取决于它们的关联性。正如同名文件可以存在于两个不同的文件夹中一样,特定名称的类也可以在两个命名空间中定义。此外,正如我们指定文件的完整路径以访问一样,我们需要指定类的全名以及命名空间。
随着应用程序规模的扩大,涉及许多类和函数定义,为每个类/函数赋予唯一的名称可能会变得繁琐且不优雅。使用命名空间可以让您以整洁的方式组织这些代码块。例如,如果我们需要声明一个 calculate() 函数来计算面积和税,而不是将它们定义为 calculate_area() 和 calculate_tax() 之类的东西,我们可以创建两个命名空间 area 和 tax,并在其中使用 calculate()。
命名空间的优点
以下是使用 PHP 命名空间的一些优点:
命名空间有助于避免由某人定义的类/函数/常量与第三方类/函数/常量之间的名称冲突。
命名空间提供了一种为 Extra_Long_Names 设置别名(或缩写)的功能,从而提高了源代码的可读性。
PHP 命名空间提供了一种对相关的类、接口、函数和常量进行分组的方法。命名空间名称不区分大小写。
定义命名空间
PHP 的 `namespace` 关键字用于定义新的命名空间。
namespace myspace;
包含命名空间的“.php”文件必须在任何其他代码(除了 `declare` 指令)之前在文件的顶部声明命名空间。在命名空间内声明类、函数和常量会影响其访问权限。
PHP 脚本可能包含除命名空间定义之外的其他代码。要加载在同一代码中定义的命名空间,PHP 使用 “use” 关键字。
use myspace;
示例
在下面的 “hello.php” 脚本中,我们在 `myspace` 命名空间内定义了一个 `hello()` 函数,并在当前脚本中加载命名空间后调用它。
<?php namespace myspace; function hello() { echo "Hello World"; } use myspace; myspace\hello(); ?>
它将产生以下输出:
Hello World
请注意,必须使用包含命名空间的完整名称(`myspace\hello()`)限定 `hello()` 函数。
包含命名空间
一个脚本可以包含命名空间声明,另一个脚本使用 `include` 语句加载该命名空间。
a.php
<?php namespace myspace { function hello() { echo "Hello World in myspace"; } } ?>
b.php
<?php include 'a.php'; myspace\hello(); ?>
它将产生以下输出:
Hello World in myspace
可能出现这种情况:当前脚本(如上面的 “b.php”)也包含与包含文件中同名的函数。在函数名前添加命名空间的限定名有助于解析器解决名称冲突。
示例
请看以下示例:
<?php include 'a.php'; function hello() { echo "Hello World from current namespace"; } hello(); myspace\hello(); ?>
它将产生以下输出:
Hello World from current namespace Hello World in myspace
示例
如上所述,命名空间声明必须位于顶部,紧跟在起始 `< ?php` 标记之后。否则,解析器将抛出致命错误。
<?php echo "hello" namespace myspace; function hello() { echo "Hello World"; } use myspace; myspace\hello(); ?>
它将产生以下输出:
PHP Parse error: syntax error, unexpected token "namespace", expecting "," or ";" in /home/cg/root/67771/main.php on line 4
上述错误消息清楚地表明,只有 “declare 语句” 允许出现在命名空间声明之前。
<?php declare (strict_types=1); namespace myspace; function hello() { echo "Hello World"; } use myspace; myspace\hello(); ?>
相对命名空间
可以通过引用相对命名空间路径来访问当前命名空间中的对象,例如函数、类和常量。
在下面的示例中,“b.php”包含一个 `space1\myspace` 命名空间,其中包含 `hello()` 函数和 `TEMP` 常量。“a.php”中也定义了相同空间下的对象。
显然,当 “b.php” 包含在 “a.php” 中时,“myspace” 是 “space1” 的子空间。因此,通过在其前面添加其相对命名空间(以及 `TEMP` 常量)来调用 “myspace” 中的 `hello()`。
b.php
<?php namespace space1\myspace; const TEMP = 10; function hello() { echo "Hello from current namespace:" . __NAMESPACE__ . ; } ?>
a.php
<?php namespace space1; include 'b.php'; function hello() { echo "Hello from current namespace:" . __NAMESPACE__ . ; } const TEMP = 100; hello(); // current namespace myspace\hello(); // sub namespace echo "TEMP : " . TEMP . " in " . __NAMESPACE__ . ; echo "TEMP : " . myspace\TEMP . " \\in space1\\myspace\n"; ?>
它将产生以下输出:
Hello from current namespace:space1 Hello from current namespace:space1\myspace TEMP : 100 in space1 TEMP : 10 in space1\myspace
绝对命名空间
您还可以通过添加绝对命名空间路径来访问任何命名空间中的函数/常量。例如,“b.php”中的 `hello()` 是 `\space\myspace\hello()`。
a.php
<?php namespace space1; include 'b.php'; function hello() { echo "Hello from current namespace:" . __NAMESPACE__ . ; } const TEMP = 100; \space1\hello(); //current namespace \space1\myspace\hello(); //sub namespace echo "TEMP: " . \space1\TEMP . " in " . __NAMESPACE__ . ; echo "TEMP: " . \space1\myspace\TEMP . " in space1\\myspace\n"; ?>
`__NAMESPACE__` 是 PHP 中一个预定义的常量,它返回当前命名空间的名称。
命名空间规则
不同命名空间中出现的函数/类/常量名称的任何冲突都将按照以下规则解决:
没有命名空间分隔符(/)的命名空间标识符表示它指的是当前命名空间。这是一个非限定名称。
如果它包含分隔符,例如 `myspace\space1`,则它解析为 `myspace` 下的子命名空间 `space1`。这种类型的命名是相对命名空间。
完全限定命名空间的名称以 “\” 字符开头。例如,`\myspace` 或 `\myspace\space1`。
完全限定名称解析为绝对命名空间。例如 `\myspace\space1` 解析为 `myspace\space1` 命名空间。
如果名称出现在全局命名空间中,则会删除 “namespace\” 前缀。例如,“namespace\space1” 解析为 `space1`。
但是,如果它出现在另一个命名空间中,则处理方式不同。例如,如果 `namespace\space1` 在 `myspace` 中,则它等效于 “myspace\space1”。
限定名称中的第一段根据当前类/命名空间导入表进行转换。
如果没有应用导入规则,则将当前命名空间添加到名称前面。
类名根据类/命名空间导入表进行转换,函数名根据函数导入表进行转换,常量根据常量导入表进行转换。
对于非限定名称,如果没有应用导入规则并且名称指的是函数或常量并且代码不在全局命名空间中,则在运行时解析名称。它首先查找当前命名空间中的函数,然后尝试查找并调用全局函数。
PHP 对象迭代
可以使用 `foreach` 循环迭代 PHP 类对象的公开可见的所有成员。此功能在 PHP 5 及更高版本中可用。当然,您可以在实例方法内访问私有属性列表。PHP 还定义了 `Iterator` 接口,可用于此目的。
使用 foreach 循环
在下面的示例中,使用 `foreach` 循环列出了类的公共属性。
示例
<?php class myclass { private $var; protected $var1; public $x, $y, $z; public function __construct() { $this->var="Hello World"; $this->var1=array(1,2,3); $this->x=100; $this->y=200; $this->z=300; } } $obj = new myclass(); foreach($obj as $key => $value) { print "$key => $value\n"; } ?>
它将产生以下输出:
x => 100 y => 200 z => 300
请注意,只有公共成员才能在类外部访问。如果类包含方法,则可以使用 `foreach` 循环从内部遍历所有成员(公共、私有或受保护)。
让我们在上面的 `myclass` 中添加一个迭代方法。
public function iterate() { foreach ($this as $k=>$v) { if (is_array($v)) { var_dump($v); echo PHP_EOL; } else { echo "$k : $v". PHP_EOL; } } }
调用此实例方法以获取所有成员的列表。
它将产生以下输出:
var : Hello World array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } x : 100 y : 200 z : 300
使用 Iterator 接口
PHP 提供 `Iterator` 接口用于外部迭代器或可以内部自行迭代的对象。它定义了以下需要在用户定义的类中实现的抽象方法。
interface Iterator extends Traversable { /* Methods */ public current(): mixed public key(): mixed public next(): void public rewind(): void public valid(): bool }
`rewind()` 方法将迭代器重绕到第一个元素。这是启动 `foreach` 循环时调用的第一个方法。它不会在 `foreach` 循环后执行。
`current()` 方法返回当前元素。
`key()` 方法在 `foreach` 循环的每次迭代中返回当前元素的键。
`next()` 方法在 `foreach` 循环的每次迭代后调用,并向前移动到下一个元素。
`valid()` 方法检查当前位置是否有效。
示例
以下示例演示了通过实现 `Iterator` 接口进行对象迭代。
<?php class myclass implements Iterator { private $arr = array('a','b','c'); public function rewind():void { echo "rewinding\n"; reset($this->arr); } public function current() { $var = current($this->arr); echo "current: $var\n"; return $var; } public function key() { $var = key($this->arr); echo "key: $var\n"; return $var; } public function next() : void { $var = next($this->arr); echo "next: $var\n"; # return $var; } public function valid() : bool { $key = key($this->arr); $var = ($key !== NULL && $key !== FALSE); echo "valid: $var\n"; return $var; } } $obj = new myclass(); foreach ($obj as $k => $v) { print "$k: $v\n"; } ?>
它将产生以下输出:
rewinding valid: 1 current: a key: 0 0: a next: b valid: 1 current: b key: 1 1: b next: c valid: 1 current: c key: 2 2: c next:
PHP 封装
PHP 实现 **封装**,这是 OOP 的重要原则之一,它使用访问控制关键字:**public、private** 和 **protected**。
封装是指将对象的成员变量或属性与类外部的环境隔离,只允许通过类中可用的方法或函数进行受控访问的机制。
下图说明了面向对象编程方法中封装的原则。
PHP 的关键字列表包含以下关键字,这些关键字确定对象的属性和方法的可访问性,该对象是 PHP 中类的实例:
**Public** - 类成员可以从任何地方访问,甚至可以从类的范围之外访问,但只能通过对象引用访问。
**Private** - 类成员只能在类本身内访问。它可以防止外部类成员甚至通过类实例的引用进行访问。
**Protected** - 成员只能在类及其子类中访问,其他地方都不能访问。
这三个关键字“**public、private** 和 **protected**”通常称为访问修饰符。它们也称为可见性模式,因为它们决定特定类成员在多大程度上可用。
公共成员
在 PHP 中,类成员(成员变量和成员函数)默认为 public。
示例
在下面的程序中,对象的成员变量 title 和 price 可以自由地从类外部访问,因为它们默认为 public,除非另有指定。
<?php class Person { /* Member variables */ var $name; var $age; /*Constructor*/ function __construct(string $param1="Ravi", int $param2=28) { $this->name = $param1; $this->age = $param2; } function getName() { echo "Name: $this->name" . PHP_EOL;; } function getAge() { echo "Age: $this->age" . PHP_EOL;; } } $b1 = new Person(); $b1->getName(); $b1->getAge(); echo "Name : $b1->name Age: $b1->age" . PHP_EOL; ?>
它将产生以下输出:
Name: Ravi Age: 28 Name : Ravi Age: 28
**注意**,默认情况下所有类成员的属性都是公共的,如果需要,您可以显式地将它们声明为公共的。因此,实例方法 `getName()` 和 `getAge()` 可以从类外部调用。
由于属性 `name` 和 `age` 也是公共的,因此它们也可以从类外部访问,这与封装的原则不符。
私有成员
如上所述,封装的原则要求不应该直接访问成员变量。只有方法才能访问数据成员。因此,我们需要将成员变量设置为 private,并将方法设置为 public。
示例
让我们将 `name` 和 `age` 属性的声明更改为私有,并运行以下 PHP 脚本:
<?php class Person { /* Member variables */ private $name; private $age; /*Constructor*/ function __construct(string $param1="Ravi", int $param2=28) { $this->name = $param1; $this->age = $param2; } public function getName() { echo "Name: $this->name" . PHP_EOL;; } public function getAge(){ echo "Age: $this->age" . PHP_EOL;; } } $b1 = new Person(); $b1->getName(); $b1->getAge(); echo "Name : $b1->name Age: $b1->age" . PHP_EOL; ?>
它将产生以下输出:
Name: Ravi Age: 28 PHP Fatal error: Uncaught Error: Cannot access private property Person::$name in person.php:27
错误消息说明了为什么无法从公共作用域访问私有属性。
受保护成员
指定对类成员的受保护访问的效果在类继承的情况下是有效的。我们知道,public 成员可以从类外部的任何地方访问,而 private 成员则不允许从类外部的任何地方访问。
**protected** 关键字允许访问同一类的对象及其继承类的对象,而拒绝任何其他环境访问。
示例
让我们继承 `person` 类并定义一个 `student` 类。我们将 `name` 属性从私有更改为受保护。`student` 类有一个新的公共方法 `getDetails()`,它打印 `name` 和 `age` 属性的值。
Person 类
<?php class Person { /* Member variables */ protected $name; private $age; /*Constructor*/ function __construct(string $param1="Ravi", int $param2=28) { $this->name = $param1; $this->age = $param2; } public function getName(){ echo "Name: $this->name" . PHP_EOL;; } public function getAge() { echo "Age: $this->age" . PHP_EOL;; } }
Student 类
class student extends Person { public function getDetails() { echo "My Name: $this->name" . PHP_EOL; echo "My age: $this->age" . PHP_EOL; } } $s1 = new student(); $s1->getDetails(); ?>
它将产生以下输出:
My Name: Ravi PHP Warning: Undefined property: student::$age in person.php on line 28 My age:
下表说明了 PHP 中类成员的可访问性规则:
PHP - “Final” 关键字
PHP 中的 “final” 关键字用于类的定义、类中的方法定义以及类的常量属性定义。
带有 “final” 关键字的类
让我们看看如何使用 “final” 关键字创建类:
final class myclass { /*class members*/ }
类定义中的 “final” 关键字阻止该类被扩展。换句话说,您不能使用 final 类作为父类。如果您尝试这样做,PHP 解析器会抛出错误。
<?php final class myclass { /* class body */ } class newclass extends myclass { /* class body */ } ?>
运行此代码时,它将显示一个 **错误**:
PHP Fatal error: Class newclass may not inherit from final class (myclass)
带有 “final” 关键字的方法
以下是如何使用 “final” 关键字创建方法:
class myclass { final function myfunction() { /* function body */ } }
用 **final** 关键字作为方法定义的前缀可以防止它在子类中被重写。带有 **final** 方法的类可以扩展,但子类不能重写它。
示例
请看以下示例:
<?php class myclass { final public function hello() { echo "Hello World!"; } } class newclass extends myclass { public function hello() { echo "Hello PHP!"; } } ?>
运行此代码时,它将显示一个 **错误**:
PHP Fatal error: Cannot override final method myclass::hello() in hello.php
带有 “final” 关键字的常量
从 PHP 8.1.0 开始,您还可以使用 **final** 关键字声明类中的常量。
final public const NAME = "My Class";
如果您尝试在子类中重写父类中的 final 常量,则会遇到错误。
<?php class myclass { final public const NAME = "My Class"; final public function hello() { echo "Hello World!"; } } class newclass extends myclass { public const NAME = "New Class"; } ?>
运行此代码时,它将显示一个 **错误**:
Fatal error: newclass::NAME cannot override final constant myclass::NAME
示例
下面的 PHP 脚本包含一个父类 `ellipse`,它具有声明为 final 的 `PI` 常量和 `area()` 方法。它们被 `circle` 类继承。`area()` 函数计算圆的面积。
<?php class ellipse { final public const PI=22/7; private float $a, $b; public function __construct($x, $y) { $this->a = $x; $this->b = $y; } final public function area() : float { return self::PI*$this->a*$this->b; } } class circle extends ellipse { public function __construct(float $x) { parent::__construct($x, $x); } } $c1 = new circle(5); echo "Area: " . $c1->area() . PHP_EOL; ?>
它将产生以下输出:
Area: 78.571428571429
请注意,不能将类的实例变量或属性声明为 final。
PHP 重载
在 C++ 或 Java 中,该术语表示一个类可以多次拥有相同名称但参数和/或返回类型不同的类方法。在 PHP 中,该术语的解释不同。它是一个可以动态创建属性和方法的功能。PHP 的魔术方法(方法名称以双下划线开头)用于设置动态属性和方法。
用于重载的魔术方法在与未声明或在当前作用域中不可见的属性或方法交互时被调用。
属性重载
PHP 的魔术方法示例包括 __construct()、__destruct()、__tostring() 等。PHP 使用以下魔术方法来重载属性。
public __set ( string $name , mixed $value ) : void public __get ( string $name ) : mixed public __isset ( string $name ) : bool public __unset ( string $name ) : void
这里:
__set() 用于向不可访问的属性(受保护的、私有的或不存在的属性)写入数据。
__get() 从不可访问的属性读取数据。
__isset() 对不可访问的属性调用 isset() 或 empty()。
__unset() 在对不可访问的属性调用 unset() 时被调用。
上面使用的 $name 参数是要设置或检索的属性的名称。__set() 方法的 $value 参数指定要分配给属性的值。
__isset() 方法检查某个属性是否已设置。__unset() 方法删除该属性。
属性重载仅在对象上下文中有效。在任何静态上下文中,这些魔术方法都不会被触发。因此,它们不应该声明为静态的。
示例
在下面的代码中,设置并检索了一个名为 myprop 的动态属性,该属性未在类中声明。
<?php class myclass { public function __set($name, $value) { echo "setting $name property to $value \n"; $this->$name = $value; } public function __get($name) { echo "value of $name property is "; return $this->$name; } } $obj = new myclass(); # This calls __set() method $obj->myproperty="Hello World!"; # This call __get() method echo "Retrieving myproperty: " . $obj->myproperty . PHP_EOL; ?>
它将产生以下输出:
setting myproperty property to Hello World! Retrieving myproperty: Hello World!
__set() 和 __get() 魔术方法还可以设置和检索声明为私有的属性。在 myclass 中添加以下语句(在函数定义之前)
private $myproperty;
您可以检查属性,在myclass中定义__isset()方法:
public function __isset($name) { return isset($this->$name); }
使用以下语句检查属性是否已设置:
var_dump (isset($obj->myproperty));
在这种情况下,它返回true。
要使用在myclass中定义的__unset()方法取消设置动态创建的属性:
public function __unset($name) { unset($this->$name); }
以下代码将返回false:
var_dump (isset($obj->myproperty));
方法重载
用于动态设置方法的两个魔术方法是__call()和__callStatic()。
public __call (string $name , array $arguments) : mixed public static __callStatic (string $name , array $arguments) : mixed
当在对象上下文中调用不可访问的方法(未定义或私有的方法)时,将触发 __call()。另一方面,当在静态上下文中调用不可访问的方法时,将触发 __callStatic()。
示例
以下示例演示了 PHP 中的方法重载
<?php class myclass { public function __call($name, $args) { // Value of $name is case sensitive. echo "Calling object method $name with " . implode(" ", $args). "\n"; } public static function __callStatic($name, $args) { echo "Calling static method $name with " . implode(" ", $args). "\n"; } } $obj = new myclass(); # This invokes __call() magic method $obj->mymethod("Hello World!"); # This invokes __callStatic() method myclass::mymethod("Hello World!"); ?>
它将产生以下输出:
Calling object method mymethod with Hello World! Calling static method mymethod with Hello World!
请注意,使用 "->" 运算符表示该方法是实例方法,而 "::" 运算符表示该方法是静态方法。
PHP 克隆对象
PHP 语句 "$obj1 = $obj2" 仅仅创建了对内存中同一对象的另一个引用。因此,属性的更改会在原始对象和副本对象中都反映出来。PHP 中的clone关键字创建对象的浅拷贝。
$obj2 = $obj1
原始对象的更改不会反映在浅拷贝中。
示例
请看以下示例:
<?php class foo { var $var1 = 'Hello'; } $x = new foo(); $y = $x; # reference copy echo $x->var1 . " " . $y->var1 . PHP_EOL; $x->var1 = "Hello World"; echo $x->var1 . " " . $y->var1 . PHP_EOL; ?>
它将产生以下输出:
Hello Hello Hello World Hello World
在第一种情况下,$y只是$x的引用副本。因此,var1属性的任何更改都会反映在两者中。
但是,如果我们将$y声明为$x的克隆,则原始对象的任何更改都不会反映在其浅拷贝中。
示例
请看以下示例:
<?php class foo { var $var1 = 'Hello World'; } $x = new foo(); # shallow copy $y = clone $x; echo $x->var1 . " " . $y->var1 . PHP_EOL; $x->var1 = "Hello PHP"; echo $x->var1 . " " . $y->var1 . PHP_EOL; ?>
它将产生以下输出:
Hello World Hello World Hello PHP Hello World
示例
在下面的代码中,myclass的一个属性是 address 类的对象。通过赋值复制 myclass 的对象。其嵌入的 address 对象的值的任何更改都将反映在这两个对象中,但 name 属性的更改不会影响克隆的对象。
<?php class address { var $city="Nanded"; var $pin="431601"; function setaddr($arg1, $arg2) { $this->city=$arg1; $this->pin=$arg2; } } class myclass { var $name="Raja"; var $obj; function setname($arg) { $this->name=$arg; } } $obj1=new myclass(); $obj1->obj=new address(); echo "original object\n"; print_r($obj1); echo "\n"; $obj2=$obj1; # reference copy $obj1->setname("Ravi"); $obj1->obj->setaddr("Mumbai", "400001"); echo "after change: Original object\n"; print_r($obj1); echo "\nCopied object\n"; print_r($obj2); ?>
它将产生以下输出:
original object myclass Object ( [name] => Raja [obj] => address Object ( [city] => Nanded [pin] => 431601 ) ) after change: Original object myclass Object ( [name] => Ravi [obj] => address Object ( [city] => Mumbai [pin] => 400001 ) ) Copied object myclass Object ( [name] => Ravi [obj] => address Object ( [city] => Mumbai [pin] => 400001 ) )
使用“clone”关键字
在浅拷贝中,原始对象的任何引用其他变量的属性都将保持引用。clone 关键字不会复制已复制对象的包含对象。
我们现在创建一个 myclass 对象的克隆,以便$obj2是$obj1的克隆。我们将$obj1的 name 属性从Raja更改为Ravi,并修改嵌入的 address 对象。属性更改不会反映在其克隆中,但引用的 address 对象将被更改。
示例
请看以下示例:
<?php class address { var $city="Nanded"; var $pin="431601"; function setaddr($arg1, $arg2) { $this->city=$arg1; $this->pin=$arg2; } } class myclass { var $name="Raja"; var $obj; function setname($arg) { $this->name=$arg; } } $obj1=new myclass(); $obj1->obj=new address(); echo "original object\n"; print_r($obj1); echo "\n"; $obj2=clone $obj1; # clone copy $obj1->setname("Ravi"); $obj1->obj->setaddr("Mumbai", "400001"); echo "after change: Original object\n"; print_r($obj1); echo "\nCopied object\n"; print_r($obj2); ?>
它将产生以下输出:
original object myclass Object ( [name] => Raja [obj] => address Object ( [city] => Nanded [pin] => 431601 ) ) after change: Original object myclass Object ( [name] => Ravi [obj] => address Object ( [city] => Mumbai [pin] => 400001 ) ) Copied object myclass Object ( [name] => Raja [obj] => address Object ( [city] => Mumbai [pin] => 400001 ) )
使用 __clone() 方法
clone 关键字创建对象的浅拷贝。当克隆对象时,PHP 将执行其所有属性的浅拷贝。任何引用其他变量的属性都将保持引用。因此,对原始对象所做的任何更改也将在克隆对象中出现。
如果您希望阻止复制的对象自动更新,我们需要使用 __clone() 方法创建对象的深拷贝。它是 PHP 中的一种魔术方法。
克隆完成后,如果定义了 __clone() 方法,则将调用新创建对象的 __clone() 方法,以允许更改任何需要更改的属性。
示例
在上面的示例中,我们有一个 myclass 对象,其一个属性 $obj 保持对 address 类对象的引用。为了实现深拷贝,我们重写了 myclass 中的 __clone() 魔术方法。
<?php class address { var $city="Nanded"; var $pin="431601"; function setaddr($arg1, $arg2) { $this->city=$arg1; $this->pin=$arg2; } } class myclass { var $name="Raja"; var $obj; function setname($arg) { $this->name=$arg; } public function __clone() { $this->obj = clone $this->obj ; } } $obj1=new myclass(); $obj1->obj=new address(); echo "original object\n"; print_r($obj1); echo "\n"; $obj2=clone $obj1; # cloned deep copy $obj1->setname("Ravi"); $obj1->obj->setaddr("Mumbai", "400001"); echo "after change: Original object\n"; print_r($obj1); echo "\nCloned object\n"; print_r($obj2); ?>
您现在将看到原始对象的更改(我们更改了地址属性)不会反映在克隆对象中,如下所示的输出:
original object myclass Object ( [name] => Raja [obj] => address Object ( [city] => Nanded [pin] => 431601 ) ) after change: Original object myclass Object ( [name] => Ravi [obj] => address Object ( [city] => Mumbai [pin] => 400001 ) ) Cloned object myclass Object ( [name] => Raja [obj] => address Object ( [city] => Nanded [pin] => 431601 ) )
PHP 匿名类
7.0版本的发布是PHP语言发展的一个重要里程碑,当时引入了许多新特性。匿名类的特性也在PHP 7.0版本中可用。
顾名思义,“匿名”类是没有(程序员声明的)名称的类。通常的做法是使用某个标识符定义一个类,以便可以重复使用它。另一方面,匿名类仅供一次性使用。
$obj = new class() { /* class body */ };
除了这个类没有名称之外,它与普通的命名类相似,因为它可以包含属性和方法。其功能与命名类的对象没有什么不同。
当不需要为类编写文档,并且类在执行期间仅使用一次时,可以使用匿名类而不是命名类。当需要创建简单的一次性对象时,匿名类非常有用。
示例
在下面的代码中,实例化一个匿名类并将其存储在 $obj 对象中。该类包含 addition() 和 division() 方法的定义,这些方法使用$obj对象调用。
<?php $obj = new class(10) { private int $x; function __construct($x) { $this->x = $x; } public function addition($x) { return $this->x+$x; } public function division($x) { return $this->x/$x; } }; echo "Addition: " . $obj->addition(20) . PHP_EOL; echo "Division: " . $obj->division(20) . PHP_EOL; ?>
它将产生以下输出:
Addition: 30 Division: 0.5
匿名类作为子类
匿名类可以完成普通类可以完成的所有操作。它可以扩展另一个类,实现一个接口,甚至可以使用一个 trait。
示例
在下面的示例中,匿名类是一个子类,扩展了已经存在的父类。
<?php class myclass { public function hello() { echo "Hello World!" . PHP_EOL; } } $obj = new class("Neena") extends myclass { private string $nm; function __construct($x) { $this->nm = $x; } public function greeting() { parent::hello(); echo "Welcome " . $this->nm . PHP_EOL; } }; $obj->greeting(); ?>
它将产生以下输出:
Hello World! Welcome Neena
示例
虽然匿名类没有任何用户定义的名称,但 PHP 确实为其分配了一个内部名称,可以使用内置的 get_class() 函数如下获取:
<?php $obj = new class() { function greeting() { echo "Hello World" . PHP_EOL; } }; $obj->greeting(); echo "Name of class: " . get_class($obj); ?>
它将产生以下输出:
Hello World Name of class: class@anonymousC:\xampp\htdocs\hello.php:2$0
PHP 解析器随机分配内部名称。
PHP Web 概念
PHP 是一种服务器端脚本语言,用于创建动态网页。它是 Web 开发中最流行的编程语言之一。本章旨在让您熟悉使用 PHP 进行 Web 应用程序开发的某些重要概念。
一个基于 Web 的应用程序是网页的集合。网页主要由 HTML 标签创建。HTML 由不同的 HTML 标签组成,这些标签需要定义页面元素(如文本、图像、表格等)的外观。因此,HTML 本质上创建的是静态网页。
Web 应用程序托管在安装了 PHP 模块的 HTTP 服务器上。浏览器充当 http 客户端,以遵循 HTTP 协议与服务器建立通信。
如何在网页上添加动态内容?
要在网页上添加动态内容,有两种可能性。
JavaScript 是一种客户端脚本语言,可以访问 HTML 文档对象模型并在客户端浏览器上呈现动态内容。JavaScript 代码可以嵌入到 HTML 页面中。
浏览器可以以 HTML 表单元素的形式从用户那里收集数据,并将其发送到 HTTP 服务器进行处理。PHP 是一种广泛使用的服务器端处理语言。PHP 脚本也可以嵌入到 HTML 页面中。
示例
在下面的脚本中,嵌入在 HTML 中的 JavaScript 代码根据客户端浏览器呈现当前日期,而 PHP 代码显示托管此脚本的服务器上的当前日期。
<!DOCTYPE html> <html> <body> <script type="text/JavaScript"> document.write("Client's date :"+Date()+"\n"); </script> <?php date_default_timezone_set("Asia/Calcutta"); echo "server's date is " . date("Y-m-d") . "\n"; echo "The time is " . date("h:i:sa"); ?> </body> </html>
PHP 可以拦截和处理来自 HTML 表单的数据。这允许您收集用户的信息。下一章讨论 PHP 的表单处理。
PHP 可用于与数据库(如 MySQL 和 PostgreSQL)交互。这允许您存储和检索数据库中的数据,并动态填充网页或为 Web 应用程序提供动力。PHP 包含用于数据库处理的 mysql、mysqli 和 PDO 扩展。
PHP 可以使用 HTTP GET 和 POST 方法处理从客户端接收到的数据。我们将在后面的章节中详细讨论 PHP 如何处理 GET/POST 方法。
HTTP 是一种无状态协议。但是,它允许分别在服务器和客户端上维护会话和 Cookie。PHP 可用于创建和管理会话和 Cookie。会话允许您在用户浏览您的网站时跟踪单个用户,而 Cookie 允许您将信息存储在用户的计算机上以供以后使用。在后面的章节中,我们将学习 PHP 如何处理会话和 Cookie。
PHP 可用于将文件上传到您的 Web 服务器。这允许您创建允许用户上传文件(如图像、视频或文档)的 Web 应用程序。
您可以使用 PHP 为您的网站创建登录页面。当用户输入其用户名和密码时,PHP 可以检查数据库以查看用户是否有效。如果用户有效,PHP 可以登录用户并将其重定向到网站的主页。
识别浏览器和平台
PHP 创建了一些有用的环境变量,这些变量可以在用于设置 PHP 环境的 phpinfo.php 页面中看到。
PHP 设置的环境变量之一是HTTP_USER_AGENT,它标识用户的浏览器和操作系统。
PHP 提供了一个 getenv() 函数来访问所有环境变量的值。HTTP_USER_AGENT 环境变量中包含的信息可用于创建适合浏览器的动态内容。
示例
以下示例演示如何识别客户端浏览器和操作系统。
注意 - preg_match() 函数在PHP 正则表达式 部分讨论。
<?php function getBrowser() { $u_agent = $_SERVER['HTTP_USER_AGENT']; $bname = 'Unknown'; $platform = 'Unknown'; $version = ""; //First get the platform if (preg_match('/linux/i', $u_agent)) { $platform = 'linux'; } elseif (preg_match('/macintosh|mac os x/i', $u_agent)) { $platform = 'mac'; } elseif (preg_match('/windows|win32/i', $u_agent)) { $platform = 'windows'; } // Next get the name of the useragent yes seperately and for good reason if(preg_match('/MSIE/i',$u_agent) && !preg_match('/Opera/i',$u_agent)) { $bname = 'Internet Explorer'; $ub = "MSIE"; } elseif(preg_match('/Firefox/i',$u_agent)) { $bname = 'Mozilla Firefox'; $ub = "Firefox"; } elseif(preg_match('/Chrome/i',$u_agent)) { $bname = 'Google Chrome'; $ub = "Chrome"; } elseif(preg_match('/Safari/i',$u_agent)) { $bname = 'Apple Safari'; $ub = "Safari"; } elseif(preg_match('/Opera/i',$u_agent)) { $bname = 'Opera'; $ub = "Opera"; } elseif(preg_match('/Netscape/i',$u_agent)) { $bname = 'Netscape'; $ub = "Netscape"; } // finally get the correct version number $known = array('Version', $ub, 'other'); $pattern = '#(?<browser>' . join('|', $known) . ') [/ ]+(?<version>[0-9.|a-zA-Z.]*)#'; if (!preg_match_all($pattern, $u_agent, $matches)) { // we have no matching number just continue } // see how many we have $i = count($matches['browser']); if ($i != 1) { //we will have two since we are not using 'other' argument yet //see if version is before or after the name if (strripos($u_agent,"Version") < strripos($u_agent,$ub)){ $version= $matches['version'][0]; } else { $version= $matches['version'][1]; } } else { $version= $matches['version'][0]; } // check if we have a number if ($version == null || $version == "") {$version = "?";} return array( 'userAgent' => $u_agent, 'name' => $bname, 'version' => $version, 'platform' => $platform, 'pattern' => $pattern ); } // now try it $ua = getBrowser(); $yourbrowser = "Your browser: " . $ua['name'] . " " . $ua['version'] . " on " .$ua['platform'] . " reports: <br >" . $ua['userAgent']; print_r($yourbrowser); ?>
这在我的机器上产生了以下结果。根据您使用的计算机的不同,此结果可能会有所不同。
它将产生以下结果 -
Your browser: Google Chrome 54.0.2840.99 on windows reports: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
随机显示图像
PHP 的rand()函数用于生成随机数。此函数可以在给定范围内生成数字。应为随机数生成器设置种子,以防止生成规则的数字模式。这是通过使用srand()函数实现的,该函数将其参数指定为种子数。
示例
以下示例演示如何每次从四张图像中显示不同的图像:
<?php srand( microtime() * 1000000 ); $num = rand( 1, 4 ); switch( $num ) { case 1: $image_file = "/php/images/php_image_sample_1.jpg"; break; case 2: $image_file = "/php/images/php_image_sample_2.jpg"; break; case 3: $image_file = "/php/images/php_image_sample_3.jpg"; break; case 4: $image_file = "/php/images/php_image_sample_4.jpg"; break; } echo "Random Image : <img src=$image_file />"; ?>
它将产生以下结果 -
使用 HTML 表单
处理 HTML 表单和 PHP 时需要注意的最重要的事情是,HTML 页面中的任何表单元素都将自动可用于您的 PHP 脚本。
示例
通过将源代码放入 test.php 脚本中来尝试以下示例。
<?php if( $_POST["name"] || $_POST["age"] ) { if (preg_match("/[^A-Za-z'-]/",$_POST['name'] )) { die ("invalid name and name should be alpha"); } echo "Welcome ". $_POST['name']. "<br />"; echo "You are ". $_POST['age']. " years old."; exit(); } ?> <form action = "<?php <b>$_PHP_SELF</b> ?>" method = "POST"> Name: <input type = "text" name = "name" /> Age: <input type = "text" name = "age" /> <input type = "submit" /> </form>
它将产生以下结果 -
PHP 默认变量$_PHP_SELF用于 PHP 脚本名称,当您单击“提交”按钮时,将调用相同的 PHP 脚本并产生以下结果:
method = "POST" 方法用于将用户数据发布到服务器脚本。将数据发布到服务器脚本的方法有两种,在PHP GET & POST章节中讨论。
浏览器重定向
PHP 的header()函数向浏览器提供原始 HTTP 标头,可用于将其重定向到另一个位置。重定向脚本应位于页面的最顶部,以防止页面的任何其他部分加载。
目标由Location:标头指定为header()函数的参数。调用此函数后,可以使用exit()函数来停止解析其余代码。
示例
以下示例演示如何将浏览器请求重定向到另一个网页。通过将源代码放入 test.php 脚本中来尝试此示例。
<?php if( $_POST["location"] ) { $location = $_POST["location"]; header( "Location:$location" ); exit(); } ?> <p>Choose a site to visit :</p> <form action = "<?php <b>$_SERVER['PHP_SELF']</b> ?>" method ="POST"> <select name = "location">. <option value = "https://tutorialspoint.com"> Tutorialspoint.com </option> <option value = "http://www.google.com"> Google Search Page </option> </select> <input type = "submit" /> </form>
它将产生以下结果 -
PHP 表单处理
HTML 表单在 PHP Web 应用程序中扮演着重要的角色。虽然纯 HTML 组成的网页是静态网页,但 HTML 表单组件是一个重要的功能,有助于增强交互性和呈现动态内容。PHP 的表单处理功能可以在处理之前验证从用户收集的数据。
HTML 表单是由各种表单控件(例如文本字段、复选框、单选按钮等)组成的集合,用户可以与这些控件交互,输入或选择某些数据。这些数据可以通过 JavaScript 在本地处理(客户端处理),也可以借助于 PHP 等服务器端编程脚本发送到远程服务器进行处理。
一个或多个表单控件元素放在 <form> 和 </form> 标签内。表单元素具有不同的属性,例如 name、action 和 method。
<form [attributes]> Form controls </form>
表单属性
在 HTML 表单元素的众多属性中,以下属性通常是必需且已定义的:
Action 属性
一个字符串,表示处理表单提交的 URL。例如,http://example.com/test.php。要将表单数据提交到定义 HTML 表单的同一 PHP 脚本,请使用 PHP_SELF 服务器变量:
<form action="<?php echo $_SERVER['PHP_SELF'];?>" method="post">
Enctype 属性
指定在将表单数据发送到服务器之前应使用哪种方法对其进行编码。可能的值包括:
application/x-www-form-urlencoded − 默认值。
multipart/form-data − 如果表单包含 type=file 的 <input> 元素,则使用此值。
text/plain − 用于调试目的。
Method 属性
一个字符串,表示提交表单时使用的 HTTP 方法。method 属性的可能值为:
post − POST 方法;表单数据作为请求正文发送。
get (默认) − GET 方法;表单数据使用“?”分隔符附加到 action URL。如果表单没有副作用,请使用此方法。
dialog − 当表单位于 <dialog> 内时,关闭对话框并触发提交事件,而无需提交数据或清除表单。
Name 属性
表单的名称。值不能是空字符串,如果同一 HTML 文档中有多个表单,则必须唯一。
Target 属性
一个字符串,指示在提交表单后在哪里显示响应。应为以下值之一:
_self (默认) − 加载到与当前浏览器上下文相同的浏览器上下文。
_blank − 加载到新的未命名浏览器上下文。
_parent − 加载到当前浏览器的父级上下文。
_top − 加载到顶级浏览器上下文(当前浏览器的祖先,且没有父级)。
因此,在 PHP Web 应用程序中使用的典型 HTML 表单如下所示:
<form name="form1" action="<?php echo $_SERVER['PHP_SELF'];?>" action="POST"> Form controls </form>
表单元素
HTML 表单使用不同类型的控件或元素设计。用户可以与这些控件交互以输入数据或从提供的可用选项中进行选择。下面描述了一些元素:
Input 元素
input 元素表示数据字段,用户可以在其中输入和/或编辑数据。
INPUT 元素的 type 属性控制数据。INPUT 元素可能有以下类型:
Text
用于输入单行文本的文本字段。
<input type="text" name="employee">
Password
单行文本字段,会掩盖输入的字符。
<input type="password" name="pwd"><br>
Checkbox
一个矩形的可选中复选框,它是一组来自预定义列表的零个或多个值。
<input type="checkbox" id="s1" name="sport1" value="Cricket"> <label for="s1">I like Cricket</label><br> <input type="checkbox" id="s2" name="sport2" value="Football"> <label for="s2">I like Football</label><br> <input type="checkbox" id="s3" name="sport3" value="Tennis"> <label for="s3">I like Tennis</label><br><br>
Radio
此类型呈现一个圆形的可点击按钮,具有两种状态(ON 或 OFF),通常是单选组中多个按钮的一部分。
<input type="radio" id="g1" name="gender" value="Male"> <label for="g1">Male</label><br> <input type="radio" id="g2" name="female" value="Female"> <label for="g2">Female</label><br>
File
此输入类型呈现一个标题为“文件”的按钮,允许用户从客户端文件系统选择文件,通常用于上传到服务器。表单的 enctype 属性必须设置为“multipart/form-data”。
<input type="file" name="file">
邮箱
单行文本字段,自定义为接受符合有效电子邮件 ID 的字符串。
URL
单行文本字段,自定义为接受符合有效 URL 的字符串。
Submit
此输入元素呈现一个按钮,单击时会启动将表单数据提交到当前表单 action 属性中指定的 URL 的操作。
<input type="submit" name="Submit">
Select 元素
select 元素表示一个用于在一组选项中进行选择的控件。每个选项都使用 Select 控件的 option 属性定义。例如:
<select name="Subjects" id="subject"> <option value="Physics">Physics</option> <option value="Chemistry">Chemistry</option> <option value="Maths">Maths</option> <option value="English">English</option> </select>
表单示例
让我们使用这些表单元素来设计一个 HTML 表单并将其发送到 PHP_SELF 脚本。
<html> <body> <form method = "post" action = "<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"> <table> <tr> <td>Name:</td> <td><input type = "text" name = "name"></td> </tr> <tr> <td>E-mail: </td> <td><input type = "email" name = "email"></td> </tr> <tr> <td>Website:</td> <td><input type = "url" name = "website"></td> </tr> <tr> <td>Classes:</td> <td><textarea name = "comment" rows = "5" cols = "40"></textarea></td> </tr> <tr> <td>Gender:</td> <td> <input type = "radio" name = "gender" value = "female">Female <input type = "radio" name = "gender" value = "male">Male </td> </tr> <td> <input type = "submit" name = "submit" value = "Submit"> </td> </table> </form> <?php $name = $email = $gender = $comment = $site = ""; if ($_SERVER["REQUEST_METHOD"] == "POST") { $name = $_POST["name"]; $email = $_POST["email"]; $name = $_POST["name"]; $comment = $_POST["comment"]; $gender = $_POST["gender"]; $site = $_POST["website"]; } echo "<h2>Your given values are as:</h2>"; echo $name; echo "<br>"; echo $email; echo "<br>"; echo $site; echo "<br>"; echo $comment; echo "<br>"; echo $gender; ?> </body> </html>
它将产生以下输出:
PHP 表单验证
术语“表单验证”是指确定用户在各种表单元素中输入的数据是否可以进一步处理的过程。在后续处理之前验证数据可以避免可能的异常和运行时错误。
验证可以在客户端和服务器端进行。当客户端提交表单时,服务器上运行的 PHP 脚本会拦截表单数据。使用 PHP 中提供的各种函数,可以进行服务器端表单验证。
客户端验证
根据 HTML5 规范,新的输入控件具有内置验证功能。例如,类型为“email”的 input 元素,即使是文本字段,也自定义为接受符合电子邮件地址协议的字符串。
验证发生在数据提交到服务器之前。其他输入类型(如 URL、数字等)也是如此。
示例
下面是一个 HTML 表单,其中包含数字类型、电子邮件类型和 URL 类型的输入元素。如果输入的数据不符合所需格式,则在尝试提交表单时会显示相应的错误消息。
<h1>Input Validation</h1> <form> <p><Label for "name">Enter your name</label> <input type = "text" id="name" name="name"></p> <p><label for="age">Enter age</label> <input type = "text" id = "age" name="age"></p> <p><label for="email">Enter your email:</label> <input type="text" id="email" name="email"></p> <p><label for="URL">Enter your website<label> <input type = "text" id="URL" name="url"></p> <input type="submit"> </form>
数字类型文本字段在右侧显示上下计数箭头。只接受数字,并且可以递增或递减。
如果电子邮件字段中的数据无效,则会显示如下错误消息。
同样,URL 的任何不正确格式也会显示如下错误:
验证函数
服务器端使用 PHP 进行的验证,要么在表单数据通过客户端验证时发生,要么根本没有客户端验证。
在上例中使用的 HTML 表单中,让我们移除所有特殊输入类型,并使用所有文本类型的文本字段。表单使用 POST 方法提交到服务器上的 hello.php。
<form action="hello.php" method="POST"> <p><Label for "name">Enter your name</label> <input type = "text" id="name" name="name"></p> <p><label for="age">Enter age</label> <input type = "text" id = "age" name="age"></p> <p><label for="email">Enter your email:</label> <input type="text" id="email" name="email"></p> <p><label for="URL">Enter your website<label> <input type = "text" id="URL" name="url"></p> <input type="submit"> </form>
表单为空
如果用户(可能是无意中)单击提交按钮,您可以要求 PHP 再次显示表单。您需要使用 isset() 函数检查 $_POST 数组是否已初始化。如果没有,header() 函数会将控制权重定向回表单。
<?php if ($_SERVER["REQUEST_METHOD"] == "POST") { if (isset($_POST)) { header("Location: hello.html", true, 301); exit(); } // form processing if the form is not empty } ?>
示例
您还可以检查提交表单时任何字段是否为空。
<?php if ($_SERVER["REQUEST_METHOD"] == "POST") { foreach($_POST as $k=>$v) { if (empty($v)==true) { echo "One or more fields are empty \n"; echo "<a href = 'hello.html'>Click here to go back </a>"; exit; } else echo "$k => $v \n"; } } ?>
年龄字段不是数字
在 HTML 表单中,名称的输入字段为文本类型,因此它可以接受任何字符。但是,我们希望它是数字。这可以通过 is_numeric() 函数来确保。
<?php if (is_numeric($_POST["age"])==false) { echo "Age cannot be non-numeric \n"; echo "<a href = 'hello.html'>Click here to go back</a>"; } ?>
PHP 还具有 is_string() 函数来检查字段是否包含字符串。另外两个函数 trim() 和 htmlspecialchars() 也对表单验证很有用。
trim() − 删除字符串开头和结尾的空格
htmlspecialchars() − 将特殊字符转换为 HTML 实体,以防止跨站点脚本 (XSS) 攻击。
PHP 表单邮件/URL
PHP 提供了两种替代方法来验证表单数据项,这些数据项是字符串,但应表示电子邮件 ID 或 URL。检查表单元素是否包含电子邮件/URL 的一种方法是使用正则表达式 (RegEx),另一种更方便的方法是使用 filter_var() 函数。让我们应用这两种方法并验证表单提交到 PHP 脚本的电子邮件和 URL。
本章使用的 HTML 表单如下所示:
<h1>Email and URL Validation</h1> <form action="hello.php" method="POST"> <p><label for="email">Enter your email:</label> <input type="text" id="email" name="email"></p> <p><label for="URL">Enter your website<label> <input type = "text" id="URL" name="url"></p> <input type="submit"> </form>
使用正则表达式进行验证
PHP 的内置函数库包含preg_match() 函数,该函数执行正则表达式匹配。
preg_match( string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0 ): int|false
此函数在 subject 中搜索与 pattern 中给定的正则表达式匹配的内容。如果 pattern 与给定的 subject 匹配,preg_match() 返回 1;如果不匹配,则返回 0;如果失败,则返回false。
有效的电子邮件 ID 应满足以下正则表达式:
"/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix"
同样,有效的 URL 应满足以下正则表达式:
"/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i"
以下函数如果字符串是有效的电子邮件 ID,则返回“1”或“0”。
function checkemail($str) { return (!preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $str)) ? FALSE : TRUE; }
示例
让我们使用checkmail() 函数来检查上面 HTML 中的电子邮件字段是否有效,方法如下面的 PHP 代码所示:
<?php function checkemail($str) { return (!preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@ ([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $str)) ? FALSE : TRUE; } if ($_SERVER["REQUEST_METHOD"] == "POST") { $email = $_POST['email']; if(!checkemail($email)){ echo "Invalid email address."; } else { echo "Valid email address."; } } ?>
HTML 表单呈现如下:
通过在电子邮件字段中输入有效/无效的电子邮件字符串来测试 PHP 代码。
以下checkURL() 函数检查字符串是否表示有效或无效的 URL,并返回“1”或“0”。
function checkURL($str) { return (!preg_match("/\b(?:(?:https?|ftp):\/\/|www\.) [-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i", $str)) ? FALSE : TRUE; }
示例
从 $_POST 数组中提取的 URL 字段作为参数传递给上述函数。
<?php function checkURL($str) { return (!preg_match("/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;] *[-a-z0-9+&@#\/%=~_|]/i", $str)) ? FALSE : TRUE; } if ($_SERVER["REQUEST_METHOD"] == "POST") { $url = $_POST['url']; if(!checkURL($url)){ echo "Invalid URL."; } else { echo "Valid URL."; } } ?>
您可以通过在上表表单的 URL 字段中输入 URL 字符串来测试上述代码。
使用 filter_var() 函数
内置的 filter_var() 函数使用指定的过滤器过滤变量。
filter_var(mixed $value, int $filter = FILTER_DEFAULT, array|int $options = 0): mixed
根据$filter参数值的枚举过滤器 ID,检查$value参数,如果过滤器失败,则函数返回已过滤的数据,否则返回 false。
有各种预定义的过滤器 ID 常量可用:
序号 | ID & 描述 |
---|---|
1 | FILTER_VALIDATE_BOOL 对于“1”、“true”、“on”和“yes”返回 true。否则返回 false。 |
2 | FILTER_VALIDATE_DOMAIN 验证域名标签长度是否有效。 |
3 | FILTER_VALIDATE_EMAIL 验证值是否为有效的电子邮件地址。 |
4 | FILTER_VALIDATE_IP 将值验证为 IP 地址 |
5 | FILTER_VALIDATE_URL 将值验证为 URL |
示例
以下 PHP 脚本验证上面 HTML 表单提交的电子邮件和 URL 数据:
<?php if ($_SERVER["REQUEST_METHOD"] == "POST") { $email = $_POST['email']; $url = $_POST['url']; if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { echo "Invalid email format and please re-enter valid email\n"; } else echo "Email entered is in valid format\n"; if (!filter_var($url, FILTER_VALIDATE_URL)) { echo "Invalid URL format and please re-enter valid URL\n"; } else echo "URL entered is in valid format\n"; } ?>
您可以通过输入有效/无效的电子邮件/URL 来测试上述脚本的性能。
PHP 完整表单
本章将表单验证和从 HTML 表单数据提取到 PHP 代码中的所有概念都整合在一起。下面给出的完整的表单处理代码包含三个部分:开头的 PHP 代码部分,用于检查提交表单时是否存在任何验证错误;带有各种元素(例如文本字段、单选按钮、选择控件、复选框等)的 HTML 表单;第三部分再次是 PHP 代码,用于呈现用户输入的数据。
PHP 错误跟踪
捕获错误的代码位于整个脚本的开头。显然,每次加载页面时都会执行此代码。如果在提交表单后加载此代码,则以下段落会检查每个元素是否为空,电子邮件字段是否格式正确,以及是否单击了复选框(表示用户同意条款)。
<?php // define variables and set to empty values $nameErr = $emailErr = $genderErr = $websiteErr = ""; $name = $email = $gender = $class = $course = $subject = ""; if ($_SERVER["REQUEST_METHOD"] == "POST") { if (empty($_POST["name"])) { $nameErr = "Name is required"; } else { $name = test_input($_POST["name"]); } if (empty($_POST["email"])) { $emailErr = "Email is required"; } else { $email = test_input($_POST["email"]); // check if e-mail address is well-formed if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $emailErr = "Invalid email format"; } } if (empty($_POST["course"])) { $course = ""; } else { $course = test_input($_POST["course"]); } if (empty($_POST["class"])) { $class = ""; } else { $class = test_input($_POST["class"]); } if (empty($_POST["gender"])) { $genderErr = "Gender is required"; } else { $gender = test_input($_POST["gender"]); } if (empty($_POST["subject"])) { $subjectErr = "You must select one or more subjects"; } else { $subject = $_POST["subject"]; } } function test_input($data) { $data = trim($data); $data = stripslashes($data); $data = htmlspecialchars($data); return $data; } ?>
HTML 表单
呈现输入表单的 HTML 脚本位于错误捕获代码之后。表单设计中使用了各种表单元素。
<h2>Absolute Classes Registration Form</h2> <p><span class = "error">* required field.</span></p> <form method = "POST" action = "<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"> <table> <tr> <td>Name:</td> <td> <input type = "text" name = "name"> <span class = "error">* <?php echo $nameErr;?></span> </td> </tr> <tr> <td>E-mail: </td> <td> <input type = "text" name = "email"> <span class = "error">* <?php echo $emailErr;?></span> </td> </tr> <tr> <td>Time:</td> <td> <input type = "text" name = "course"> <span class = "error"><?php echo $websiteErr;?></span> </td> </tr> <tr> <td>Classes:</td> <td><textarea name = "class" rows = "5" cols = "40"></textarea></td> </tr> <tr> <td>Gender:</td> <td> <input type = "radio" name = "gender" value = "female">Female <input type = "radio" name = "gender" value = "male">Male <span class = "error">* <?php echo $genderErr;?></span> </td> </tr> <tr> <td>Select:</td> <td> <select name = "subject[]" size = "4" multiple> <option value = "Android">C</option> <option value = "Java">Java</option> <option value = "C#">C#</option> <option value = "Data Base">C++</option> <option value = "Hadoop">PHP</option> <option value = "VB script">Python</option> </select> </td> </tr> <tr> <td>Agree</td> <td><input type = "checkbox" name = "checked" value = "1"></td> <?php if(!isset($_POST['checked'])){ ?> <span class = "error">* <?php echo "You must agree to terms";?></span> <?php } ?> </tr> <tr> <td> <input type = "submit" name = "submit" value = "Submit"> </td> </tr> </table> </form>
请注意,表单数据提交回同一脚本,因此表单的 action 属性设置为 $_SERVER["PHP_SELF"] 超全局变量。此部分还包含某些内联 PHP 代码,这些代码会在相应的表单控件旁边显示错误消息——例如,如果在提交表单时名称字段为空,则名称文本框旁边会显示“名称必填”消息。
显示表单数据
脚本的第三部分再次是 PHP 代码,它会回显用户提交的每个表单字段的值。
<?php if ($_SERVER["REQUEST_METHOD"] == "POST") { echo "<h2>Your given values are as :</h2>"; echo ("<p><b>Name</b> : $name</p>"); echo ("<p><b>Email address</b> : $email</p>"); echo ("<p><b>Preffered class time</b> : $course</p>"); echo ("<p><b>Class info</b> : $class </p>"); echo ("<p><b>Gender</b> : $gender</p>"); echo "<p><b>Subjcts Chosen:</b><p>"; if (!empty($subject)) { echo "<ul>"; for($i = 0; $i < count($subject); $i++) { echo "<li>$subject[$i]</u/li>"; } echo "</ul>"; } } ?>
这是从服务器的文档根文件夹运行脚本时在表单中填写的示例数据:
提交后,输出如下所示:
示例
PHP 处理 HTML 表单的完整代码如下:
<html> <head> <style> .error {color: #FF0000;} </style> </head> <body> <?php // define variables and set to empty values $nameErr = $emailErr = $genderErr = $websiteErr = ""; $name = $email = $gender = $class = $course = $subject = ""; if ($_SERVER["REQUEST_METHOD"] == "POST") { if (empty($_POST["name"])) { $nameErr = "Name is required"; }else { $name = test_input($_POST["name"]); } if (empty($_POST["email"])) { $emailErr = "Email is required"; } else { $email = test_input($_POST["email"]); // check if e-mail address is well-formed if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $emailErr = "Invalid email format"; } } if (empty($_POST["course"])) { $course = ""; } else { $course = test_input($_POST["course"]); } if (empty($_POST["class"])) { $class = ""; } else { $class = test_input($_POST["class"]); } if (empty($_POST["gender"])) { $genderErr = "Gender is required"; } else { $gender = test_input($_POST["gender"]); } if (empty($_POST["subject"])) { $subjectErr = "You must select one or more subjects"; } else { $subject = $_POST["subject"]; } } function test_input($data) { $data = trim($data); $data = stripslashes($data); $data = htmlspecialchars($data); return $data; } ?> <h2>Absolute Classes Registration Form</h2> <p><span class = "error">* required field.</span></p> <form method = "POST" action = "<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"> <table> <tr> <td>Name:</td> <td> <input type = "text" name = "name"> <span class = "error">* <?php echo $nameErr;?></span> </td> </tr> <tr> <td>E-mail: </td> <td> <input type = "text" name = "email"> <span class = "error">* <?php echo $emailErr;?></span> </td> </tr> <tr> <td>Time:</td> <td> <input type = "text" name = "course"> <span class = "error"><?php echo $websiteErr;?></span> </td> </tr> <tr> <td>Classes:</td> <td><textarea name = "class" rows = "5" cols = "40"></textarea></td> </tr> <tr> <td>Gender:</td> <td> <input type = "radio" name = "gender" value = "female">Female <input type = "radio" name = "gender" value = "male">Male <span class = "error">* <?php echo $genderErr;?></span> </td> </tr> <tr> <td>Select:</td> <td> <select name = "subject[]" size = "4" multiple> <option value = "C">C</option> <option value = "Java">Java</option> <option value = "C#">C#</option> <option value = "c++">C++</option> <option value = "PHP">PHP</option> <option value = "Python">Python</option> </select> </td> </tr> <tr> <td>Agree</td> <td><input type = "checkbox" name = "checked" value = "1"></td> <?php if(!isset($_POST['checked'])){ ?> <span class = "error">* <?php echo "You must agree to terms";?></span> <?php } ?> </tr> <tr> <td> <input type = "submit" name = "submit" value = "Submit"> </td> </tr> </table> </form> <?php if ($_SERVER["REQUEST_METHOD"] == "POST") { echo "<h2>Your given values are as :</h2>"; echo ("<p><b>Name</b> : $name</p>"); echo ("<p><b>Email address</b> : $email</p>"); echo ("<p><b>Preffered class time</b> : $course</p>"); echo ("<p><b>Class info</b> : $class </p>"); echo ("<p><b>Gender</b> : $gender</p>"); echo "<p><b>Subjcts Chosen:</b><p>"; if (!empty($subject)) { echo "<ul>"; for($i = 0; $i < count($subject); $i++) { echo "<li>$subject[$i]</u/li>"; } echo "</ul>"; } } ?> </body> </html>
它将产生以下输出:
PHP 文件包含
您可以在服务器执行之前将一个 PHP 文件的内容包含到另一个 PHP 文件中。可以使用两个 PHP 函数将一个 PHP 文件包含到另一个 PHP 文件中。
include() 函数
require() 函数
这是PHP的一个强大之处,它有助于创建可在多个页面上重复使用的函数、页眉、页脚或元素。这将帮助开发人员轻松地以最小的努力更改整个网站的布局。如果需要任何更改,则只需更改包含的文件,而无需更改数千个文件。
include() 函数
include() 函数获取指定文件中的所有文本,并将其复制到使用 include 函数的文件中。如果加载文件时出现任何问题,则include() 函数会生成警告,但脚本将继续执行。
假设您想为您的网站创建一个公共菜单。然后创建一个名为 menu.php 的文件,内容如下。
<a href="https://tutorialspoint.com/index.htm">Home</a> <a href="https://tutorialspoint.com/ebxml">ebXML</a> <a href="https://tutorialspoint.com/ajax">AJAX</a> <a href="https://tutorialspoint.com/perl">PERL</a>
现在创建任意数量的页面,并包含此文件以创建页眉。例如,现在您的 test.php 文件可以包含以下内容。
<?php <b>include("menu.php");</b> ?> <p>This is an example to show how to include PHP file!</p>
它将产生以下结果 -
require() 函数
require() 函数获取指定文件中的所有文本,并将其复制到使用 include 函数的文件中。如果加载文件时出现任何问题,则require() 函数会生成致命错误并停止脚本执行。
因此,require() 和 include() 之间的区别仅在于它们处理错误条件的方式。建议使用 require() 函数而不是 include() 函数,因为如果文件丢失或名称错误,脚本不应继续执行。
您可以尝试使用上述示例和 require() 函数,它将生成相同的结果。但是,如果您尝试以下两个不存在文件的示例,您将得到不同的结果。
<?php include("xxmenu.php"); ?> <p>This is an example to show how to include wrong PHP file!</p>
这将产生以下结果:
This is an example to show how to include wrong PHP file!
现在让我们尝试使用 require() 函数的相同示例。
<?php <b>require("xxmenu.php");</b> ?> <p>This is an example to show how to include wrong PHP file!</p>
这次文件执行停止,没有任何内容显示。
注意 - 您可能会收到简单的警告消息、致命错误消息或根本没有任何消息。这取决于您的 PHP 服务器配置。
PHP GET 和 POST
由于PHP主要用于Web应用程序开发,浏览器客户端发送的数据主要采用GET和POST类型的HTTP请求方法。HTTP协议还定义了其他用于向服务器发送请求的方法。它们是PUT、DELETE、HEAD和OPTIONS(除了GET和POST方法)。在本章中,我们将重点介绍PHP如何处理GET和POST方法。
GET方法
GET方法发送附加到页面请求的编码用户信息。页面和编码信息由?字符分隔。
http://www.test.com/index.htm?name1=value1&name2=value2
GET 方法会产生一个长字符串,该字符串会出现在您的服务器日志中以及浏览器的“位置:”框中。
GET方法仅限于发送最多1024个字符。
如果要发送密码或其他敏感信息到服务器,切勿使用GET方法。
GET不能用于向服务器发送二进制数据,例如图像或Word文档。
通过GET方法发送的数据可以使用QUERY_STRING环境变量访问。
PHP提供$_GET关联数组,可以使用GET方法访问所有发送的信息。
通过将源代码放入 test.php 脚本中来尝试以下示例。
<?php if( $_GET["name"] || $_GET["age"] ) { echo "Welcome ". $_GET['name']. "<br />"; echo "You are ". $_GET['age']. " years old."; exit(); } ?> <form action = "<?php <b>$_PHP_SELF</b> ?>" method = "GET"> Name: <input type = "text" name = "name" /> Age: <input type = "text" name = "age" /> <input type = "submit" /> </form>
它将产生以下结果 -
POST方法
POST方法通过HTTP标头传输信息。信息按照GET方法中描述的方式进行编码,并放入名为QUERY_STRING的标头中。
POST方法对要发送的数据大小没有任何限制。
POST方法可用于发送ASCII和二进制数据。
通过POST方法发送的数据通过HTTP标头,因此安全性取决于HTTP协议。通过使用安全HTTP,您可以确保您的信息安全。
PHP提供$_POST关联数组,可以使用POST方法访问所有发送的信息。
通过将源代码放入 test.php 脚本中来尝试以下示例。
<?php if( $_POST["name"] || $_POST["age"] ) { if (preg_match("/[^A-Za-z'-]/",$_POST['name'] )) { die ("invalid name and name should be alpha"); } echo "Welcome ". $_POST['name']. "<br />"; echo "You are ". $_POST['age']. " years old."; exit(); } ?> <form action = "<?php <b>$_PHP_SELF</b> ?>" method = "POST"> Name: <input type = "text" name = "name" /> Age: <input type = "text" name = "age" /> <input type = "submit" /> </form>
它将产生以下结果 -
GET和POST的区别
GET和POST方法的主要区别在于,虽然附加到URL的请求参数在浏览器的URL中公开,但POST数据包含在消息正文中,并且不会在URL中显示。因此,不应使用GET方法向服务器发送敏感数据。
其次,GET方法中的请求数据不能超过2048个字符,并且只能包含ASCII字符,而POST方法对请求数据没有限制,也可以是二进制数据(POST数据的默认最大大小由php.ini文件中的post_max_size设置确定)。
PHP提供以下三个超级全局变量来检索和处理请求参数:
$_GET - 一个关联数组,用于使用GET方法访问所有发送的信息。
$_POST - 一个关联数组,用于使用POST方法访问所有发送的信息。
$_REQUEST - 一个关联数组,可用于获取通过GET和POST方法发送的表单数据的結果。
$_GET数组
您可以将请求参数以直接附加到URL的查询字符串的形式传递。
将以下PHP脚本保存在文档根文件夹(htdocs)中,命名为“hello.php”:
<?php echo "First name: " . $_REQUEST['first_name'] . " " . "Last Name: " . $_REQUEST['last_name'] . ""; ?>
在浏览器窗口中输入https://127.0.0.1/hello.php?first_name=Amar&last_name=Sharma作为URL(确保PHP服务器正在运行)。
$_GET数组将从请求中填充,输出如下所示:
First name: Amar Last Name: Sharma
如果HTML表单的method属性为GET,您也可以使用HTML表单数据填充$_GET数组。
使用以下HTML表单收集数据并将其发送到“hello.php”。在文档根目录下,将以下脚本保存为“hello.html”:
<form action="hello.php" method="get"> First Name: <input type="text" name="first_name"/> <br/> Last Name: <input type="text" name="last_name" /> <input type="submit" value="Submit" /> </form>
在您的浏览器中,输入URL“https://127.0.0.1/hello.html”:
您应该在浏览器窗口中获得类似的输出。
$_POST数组
向服务器发送POST请求数据的最简单方法是将HTML表单的method属性指定为POST。假设浏览器中的URL是“https://127.0.0.1/hello.php”,method=POST设置在HTML表单“hello.html”中,如前面的示例所示:
<form action="hello.php" method="post"> First Name: <input type="text" name="first_name"/> <br/> Last Name: <input type="text" name="last_name" /> <input type="submit" value="Submit" /> </form>
“hello.php”脚本(在文档根文件夹中)在$_POST数组中检索表单数据,并将其呈现为HTTP响应返回给浏览器:
<?php echo "First name: " . $_POST['first_name'] . " " . "Last Name: " . $_POST['last_name'] . ""; ?>
在浏览器中打开“https://127.0.0.1/hello.html”。输入的数据将由服务器检索,并如前面的示例一样呈现回客户端。
PHP 文件上传
典型PHP Web应用程序所需的一个常见功能是允许用户上传文件的功能。在PHP中,从客户端上传文件非常容易。在本章中,我们将学习如何使用PHP脚本进行文件上传过程。
上传文件的过程遵循以下步骤:
用户打开包含HTML表单的页面,该表单包含文本文件、浏览按钮和提交按钮。
用户单击浏览按钮,并从本地PC中选择要上传的文件。
选定文件的完整路径显示在文本字段中,然后用户单击提交按钮。
选定的文件被发送到服务器上的临时目录。
在表单的action属性中指定为表单处理程序的PHP脚本检查文件是否已到达,然后将文件复制到目标目录。
PHP脚本向用户确认成功。
为了执行此操作,我们必须首先确保在“php.ini”中启用了与文件上传相关的配置设置。
打开“php.ini”文件,并确保通过删除file_uploads、upload_tmp_dir、upload_max_filesize和max_file_uploads参数开头的分号(;)符号来启用以下设置:
;;;;;;;;;;;;;;;; ; File Uploads ; ;;;;;;;;;;;;;;;; ; Whether to allow HTTP file uploads. ; https://php.net/file-uploads file_uploads=On ; Temporary directory for HTTP uploaded files (will use system ; default if not specified). ; https://php.net/upload-tmp-dir upload_tmp_dir="C:\xampp\tmp" ; Maximum allowed size for uploaded files. ; https://php.net/upload-max-filesize upload_max_filesize=40M ; Maximum number of files that can be uploaded via a single request max_file_uploads=20
临时位置和最终位置的文件夹必须设置允许文件写入的权限。如果任一设置为只读,则过程将失败。
创建文件上传表单
接下来,我们需要设计一个用于文件上传的HTML表单。表单的method属性必须为POST,enctype必须为multipart/form-data。使用input类型为file,允许用户浏览并选择要上传的文件。
<h2>File Upload Form</h2> <form method = "POST" action = "uploadfile.php" enctype="multipart/form-data"> <label for="file">File name:</label> <input type="file" name="uploadfile" /> <input type="submit" name="submit" value="Upload" /> </form>
创建上传脚本
uploadfile.php脚本接收上传的文件。文件数据收集在一个超级全局变量$_FILES中。获取上传文件的名称、文件类型、大小和tmp_name属性。
move_uploaded_file()函数将选定的文件复制到文档文件夹。
<?php echo "<b>File to be uploaded: </b>" . $_FILES["uploadfile"]["name"] . "<br>"; echo "<b>Type: </b>" . $_FILES["uploadfile"]["type"] . "<br>"; echo "<b>File Size: </b>" . $_FILES["uploadfile"]["size"]/1024 . "<br>"; echo "<b>Store in: </b>" . $_FILES["uploadfile"]["tmp_name"] . "<br>"; if (file_exists($_FILES["uploadfile"]["name"])){ echo "<h3>The file already exists</h3>"; } else { move_uploaded_file($_FILES["uploadfile"]["tmp_name"], $_FILES["uploadfile"]["name"]); echo "<h3>File Successfully Uploaded</h3>"; } ?>
假设myform.php和uploadfile.php这两个文件都存储在文档文件夹中。
在浏览器中打开“myform.php”(https://127.0.0.1/myform.php):
单击文件按钮,浏览到要上传的目标文件,然后单击上传按钮。
服务器将返回以下消息:
PHP Cookie
万维网由HTTP协议提供支持,HTTP协议是一种无状态协议。Cookie机制帮助服务器维护先前请求的信息。PHP透明地支持HTTP Cookie。
当客户端第一次发送请求时,服务器会将其响应作为Cookie的一部分包含一小部分数据。PHP提供setcookie()方法来在响应中注入Cookie。
此Cookie数据作为文本文件存储在客户端的计算机中。在相同客户端的后续访问中,这些Cookie作为请求标头的一部分包含。
服务器使用客户端请求中存在的所有Cookie填充PHP超级全局变量“$_COOKIE”。
本章将教你如何设置Cookie,如何访问它们以及如何删除它们。
Cookie的结构
Cookie通常设置在HTTP标头中(尽管JavaScript也可以直接在浏览器上设置Cookie)。设置Cookie的PHP脚本可能会发送如下所示的标头:
HTTP/1.1 200 OK Date: Fri, 04 Feb 2000 21:03:38 GMT Server: Apache/1.3.9 (UNIX) PHP/4.0b3 Set-Cookie: name=xyz; expires=Friday, 04-Feb-07 22:03:38 GMT; path=/; domain=tutorialspoint.com Connection: close Content-Type: text/html
如您所见,Set-Cookie标头包含一个名称值对、一个GMT日期、一个路径和一个域。名称和值将进行URL编码。expires字段是指示浏览器在给定的时间和日期后“忘记”Cookie的指令。
如果浏览器配置为存储Cookie,它将保留此信息,直到过期日期。如果用户将浏览器指向与Cookie的路径和域匹配的任何页面,它将把Cookie重新发送到服务器。浏览器的标头可能如下所示:
GET / HTTP/1.0 Connection: Keep-Alive User-Agent: Mozilla/4.6 (X11; I; Linux 2.2.6-15apmac ppc) Host: zink.demon.co.uk:1126 Accept: image/gif, */* Accept-Encoding: gzip Accept-Language: en Accept-Charset: iso-8859-1,*,utf-8 Cookie: name=xyz
然后,PHP脚本可以通过环境变量$_COOKIE或$HTTP_COOKIE_VARS[]访问Cookie,该变量包含所有Cookie名称和值。可以使用$HTTP_COOKIE_VARS["name"]访问上面的Cookie。
如何在PHP中设置Cookie?
PHP包含setcookie函数,用于创建一个Cookie对象,以便与HTTP响应一起发送到客户端。
setcookie(name, value, expire, path, domain, security);
参数
以下是所有参数的详细信息:
名称 - 这将设置Cookie的名称,并存储在一个名为HTTP_COOKIE_VARS的环境变量中。访问Cookie时使用此变量。
值 - 这将设置命名变量的值,并且是您实际要存储的内容。
过期时间 - 这指定自1970年1月1日00:00:00 GMT以来的秒数。在此时间之后,Cookie将变得不可访问。如果未设置此参数,则Cookie将在Web浏览器关闭时自动过期。
路径 - 这指定Cookie有效的目录。单个正斜杠字符允许Cookie对所有目录都有效。
域 - 这可用于在非常大的域中指定域名,并且必须包含至少两个点才能有效。所有Cookie仅对创建它们的宿主和域有效。
安全性 - 这可以设置为1,以指定Cookie应该只通过使用HTTPS的安全传输发送,否则设置为0,这意味着Cookie可以通过常规HTTP发送。
示例
下面的PHP脚本检查名为username的Cookie是否已设置,如果已设置,则检索其值。如果没有,则设置一个新的Cookieusername。
<?php if (isset($_COOKIE['username'])) { echo "<h2>Cookie username already set:" . $_COOKIE['username'] . "</h2>"; } else { setcookie("username", "MohanKumar"); echo "<h2>Cookie username is now set</h2>"; } ?>
从Apache服务器的文档根目录运行此脚本。您应该看到此消息:
Cookie username is now set
如果重新执行此脚本,则 Cookie 现在已设置。
Cookie username already set: MohanKumar
您的浏览器的开发者工具是一个非常有用的工具。您可以使用它来设置、检索和删除Cookie。上述程序设置的Cookie可以在浏览器开发者工具的“应用程序”选项卡下查看。
如下所示的foreach循环检索所有Cookie:
<?php $arr=$_COOKIE; foreach ($arr as $key=>$val); echo "<h2>$key=>$val </h2>"; ?>
下面的脚本包含一个HTML表单。它将表单数据发送到setcookie.php脚本,该脚本使用从$_POST数组检索到的数据设置cookie。
HTML表单由以下代码呈现:
<form action="setcookie.php" method="POST"> <input type="text" name="name"> <input type="text" name="age"> <input type="submit" name="Submit"> </form>
SetCookie.php读取表单数据并设置cookie。
if (isset($_POST["submit"]) { setcookie("name", $_POST["name"]); setcookie("age", $_POST["age"]); }
使用另一个getcookie.php代码,我们可以检索设置的cookie。
if (isset($_COOKIE["name"]) echo "Cookie: name => " . $_COOKIE["name"]. "<br>"; if (isset($_COOKIE["age"]) echo "Cookie: age => " . $_COOKIE["age"]. "<br>";
使用PHP访问Cookie
PHP提供了许多访问cookie的方法。最简单的方法是使用$_COOKIE或$HTTP_COOKIE_VARS变量。以下示例将访问在上述示例中设置的所有cookie。
<?php echo $_COOKIE["name"]. "<br />"; /* is equivalent to */ echo $HTTP_COOKIE_VARS["name"]. "<br />"; echo $_COOKIE["age"] . "<br />"; /* is equivalent to */ echo $HTTP_COOKIE_VARS["age"] . "<br />"; ?>
您可以使用isset()函数检查是否设置了cookie。
<?php if( isset($_COOKIE["name"])) echo "Welcome " . $_COOKIE["name"] . "<br />"; else echo "Sorry... Not recognized" . "<br />"; ?>
删除Cookie
要删除cookie,请设置一个已过期日期的cookie,以便浏览器触发cookie删除机制。
示例
请看以下示例:
<?php setcookie("username", "", time() - 3600); echo "<h2>Cookie username is now removed</h2>"; ?>
浏览器显示以下响应:
Cookie username is now removed
您也可以通过在cookie名称中使用数组表示法来设置数组cookie。
setcookie("user[three]", "Guest"); setcookie("user[two]", "user"); setcookie("user[one]", "admin");
如果cookie名称包含点(.),PHP会将它们替换为下划线(_)。
尽管cookie背后的主要目的是帮助Web开发者提供更个性化和便捷的用户体验,但它可能会对您的隐私和个人信息构成风险。
在某些情况下,如果您不接受其cookie,应用程序可能会拒绝您完全访问。在这种情况下,建议定期清除浏览器缓存中与cookie相关的 数据。
PHP Session
Web会话是从用户与服务器建立连接的时间到连接终止的时间段。与cookie一起,会话变量使数据可在整个网站的各个页面之间访问。
在会话期间,网站会维护有关用户操作和偏好的信息。会话数据填充在超全局关联数组$_SESSION中。
要在PHP中启动新会话,您需要调用session_start()函数。
启动会话
为了启用对会话数据的访问,必须调用session_start()函数。session_start()根据通过GET或POST请求传递的会话标识符,或通过cookie传递的会话标识符,创建会话或恢复当前会话。
session_start(array $options = []): bool
如果会话成功启动,此函数返回true,否则返回false。
PHP首先为该特定会话创建一个唯一的标识符,这是一个32个十六进制数字的随机字符串。
session_id()函数设置或检索唯一的会话ID。
session_id(?string $id = null): string|false
如果没有给出$id参数,PHP将生成一个随机的会话ID。您可以指定您自己的ID。该函数返回当前会话的会话ID,如果当前没有会话,则返回空字符串。失败时,它返回false。
示例
请看以下示例:
<?php // Starting the session session_start(); $id = session_id(); echo "Session Id: ".$id ; ?>
浏览器将显示一个随机字符串作为输出:
Session Id: mi3976f8ssethe9f04vq1ag6it
名为PHPSESSID的cookie会自动发送到用户的计算机,以存储唯一的会话标识符字符串。
会话在服务器上的临时目录中创建一个文件,其中存储注册的会话变量及其值。在此访问期间,此数据将可用于网站上的所有页面。
临时文件的位置由"php.ini"文件中名为"session.save_path"的设置确定。
处理会话变量
会话变量存储在名为$_SESSION[]的关联数组中。这些变量可以在会话的生命周期内访问。
要创建一个新的会话变量,请在$_SESSION数组中添加一个键值对:
$_SESSION[ "var"]=value;
要读取会话变量的值,您可以使用echo/print语句,或var_dump()或print_r()函数。
echo $_SESSION[ "var"];
要获取当前会话中所有会话变量的列表,您可以使用foreach循环遍历$_SESSION:
foreach ($_SESSION as $key=>$val) echo $key . "=>" . $val;
示例
以下示例启动一个会话,然后注册一个名为counter的变量,该变量在会话期间每次访问页面时都会递增。
使用isset()函数检查会话变量是否已设置。
以下PHP脚本在第一次运行时启动一个会话,并设置一个名为counter的会话变量。当客户端再次访问相同的URL时,由于会话变量已设置,因此计数器会递增。
<?php session_start(); if( isset( $_SESSION['counter'] ) ) { $_SESSION['counter'] += 1; } else { $_SESSION['counter'] = 1; } $msg = "Number of visits in this session: ". $_SESSION['counter']; ?> <?php echo "$msg"; ?>
多次刷新浏览器以模拟重复访问。浏览器显示计数器:
Number of visits in this session: 5
销毁PHP会话
可以使用session_destroy()函数销毁PHP会话。此函数不需要任何参数,一次调用即可销毁所有会话变量。如果您想销毁单个会话变量,则可以使用unset()函数来取消设置会话变量。
这是一个取消设置单个变量的示例:
<?php unset($_SESSION['counter']); ?>
这是将销毁所有会话变量的调用:
<?php session_destroy(); ?>
如果您可以在php.ini文件中将session.auto_start变量设置为1,则当用户访问您的网站时,您不需要调用start_session()函数来启动会话。
示例
以下PHP脚本呈现一个HTML表单。表单数据用于创建三个会话变量。超链接将浏览器带到另一个页面,该页面读取会话变量。
<html> <body> <form action="<?php echo $_SERVER['PHP_SELF'];?>" method="post"> <h3>User's ID: <input type="text" name="ID"/></h3> <h3>User's Name: <input type="text" name="name"/></h3> <h3>User Type: <input type="text" name="type"/></h3> <input type="submit" value="Submit" /> </form> <?php session_start(); if ($_SERVER["REQUEST_METHOD"] == "POST") { $_SESSION['ID'] = $_POST['ID']; $_SESSION['Name'] = $_POST['name']; $_SESSION['type'] = $_POST['type']; echo "<h2>Following Session variables Created</h2>"; foreach ($_SESSION as $key=>$val) { echo "<h3>" . $key . "=>" . $val . "</h3>"; } echo "<a href='test.php'><b>Click Here</b></a>"; } ?> </body> </html>
将此代码另存为文档根文件夹中的"hello.php",并在客户端浏览器中打开它。
按下提交按钮。浏览器将显示创建的会话变量:
浏览器通过遵循显示的链接导航到另一个页面。它读取回会话变量。
PHP Session 选项
从PHP 7版本开始,session_start()函数接受一个选项数组,以覆盖在"php.ini"中设置的会话配置指令。"php.ini"中的[session]部分定义了各种选项的默认值。
如果提供选项,则其形式为选项的关联数组,这些选项将覆盖当前设置的会话配置指令。键不应包含"session."前缀。
示例
例如,您可以使用定义为session_start()函数参数的两个会话选项启动HTTP会话:
<?php session_start([ 'cache_limiter' => 'private', 'read_and_close' => true, ]); ?>
HTTP会话的可配置选项
PHP中HTTP会话的一些可配置选项如下:
session.name
它指定用作cookie名称的会话名称。它应该只包含字母数字字符。默认为PHPSESSID。
session.save_handler
它定义用于存储和检索与会话关联的数据的处理程序的名称。默认为files。
session.auto_start
它指定会话模块是否在请求启动时自动启动会话。默认为0(禁用)。
session.cookie_lifetime
它以秒为单位指定发送到浏览器的cookie的生命周期。值0表示“直到浏览器关闭”。默认为0。
session.cache_limiter
它指定用于会话页面的缓存控制方法。它可以是以下值之一:nocache、private、private_no_expire或public。默认为nocache。
session.sid_length
它允许您指定会话ID字符串的长度。会话ID长度可以在22到256之间。默认为32。
session.upload_progress.enabled
它启用上传进度跟踪,填充$_SESSION变量。默认为1,启用。
session.lazy_write
当它设置为1时,这意味着只有在会话数据更改时才会重写它。默认为1,启用。
PHP 发送邮件
发送电子邮件是典型的PHP驱动Web应用程序的常用功能之一。您希望通过PHP应用程序本身发送包含通知、更新和其他通信的电子邮件给注册用户,而不是使用不同的邮件服务。您可以通过采用本章中描述的技术,将此功能添加到您的PHP应用程序中。
PHP有一个内置的mail()函数来发送电子邮件。但是,您需要正确配置"php.ini"设置才能这样做。首先,您必须知道您正在使用的Web托管平台的SMTP域。例如,如果您的网站托管在GoDaddy托管服务上,则SMTP域为"smtp.secureserver.net",您应该在配置中使用它。
如果您使用GoDaddy的基于Windows的托管,您应该确保在php.ini文件中启用了两个指令。第一个称为SMTP,它定义您的电子邮件服务器地址。第二个称为sendmail_from,它定义您自己的电子邮件地址。
Windows的配置如下所示:
[mail function] ; For Win32 only. SMTP = smtp.secureserver.net ; For win32 only sendmail_from = [email protected]
Linux用户只需让PHP知道其sendmail应用程序的位置即可。路径和任何所需的开关都应指定给sendmail_path指令。
Linux的配置如下所示:
[mail function] ; For Win32 only. SMTP = ; For win32 only sendmail_from = ; For Unix only sendmail_path = /usr/sbin/sendmail -t -i
PHP中的mail()函数需要三个必填参数,它们指定收件人的电子邮件地址、邮件的主题和实际邮件,此外还有另外两个可选参数。
mail( to, subject, message, headers, parameters );
参数
to - 必需。指定电子邮件的接收者/接收者
subject - 必需。指定电子邮件的主题。此参数不能包含任何换行符
message - 必需。定义要发送的消息。每一行都应该用LF(\n)分隔。行不应超过70个字符
headers - 可选。指定其他标头,如From、Cc和Bcc。其他标头应以CRLF(\r\n)分隔
parameters - 可选。向sendmail程序指定附加参数
多个收件人可以作为mail()函数的第一个参数以逗号分隔的列表的形式指定。
发送HTML电子邮件
当您使用PHP发送文本消息时,所有内容都将被视为纯文本。即使您在文本消息中包含HTML标记,它也会显示为纯文本,并且HTML标记不会根据HTML语法进行格式化。但是PHP提供了将HTML消息作为实际HTML消息发送的选项。
发送电子邮件时,您可以指定Mime版本、内容类型和字符集以发送HTML电子邮件。
示例
以下示例显示如何将HTML电子邮件消息发送到"[email protected]",并将其抄送至"[email protected]"。您可以编写此程序,使其接收用户的所有内容,然后发送电子邮件。
它应该接收用户的所有内容,然后发送电子邮件。
<?php $to = "[email protected]"; $subject = "This is subject"; $message = "<b>This is HTML message.</b>"; $message .= "<h1>This is headline.</h1>"; $header = "From:[email protected] \r\n"; $header .= "Cc:[email protected] \r\n"; $header .= "MIME-Version: 1.0\r\n"; $header .= "Content-type: text/html\r\n"; $retval = mail ($to,$subject,$message,$header); if( $retval == true ) { echo "Message sent successfully..."; }else { echo "Message could not be sent..."; } ?>
它将产生以下输出:
Message could not be sent... sh: 1: /usr/sbin/sendmail: not found
从本地主机发送电子邮件
以上调用PHP mail()的方法可能无法在您的本地主机上运行。在这种情况下,有一种替代的发送电子邮件的解决方案。您可以使用PHPMailer通过本地主机的SMTP发送电子邮件。
PHPMailer是一个开源库,用于连接SMTP来发送电子邮件。您可以从PEAR或Composer存储库下载它,也可以从https://github.com/PHPMailer/PHPMailer下载它。从此处下载ZIP文件,并将PHPMailer文件夹的内容复制到PHP配置中指定的include_path目录之一,并手动加载每个类文件。
示例
使用以下PHP脚本使用PHPMailer库发送电子邮件:
Phpmailer.php
<?php use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\SMTP; use PHPMailer\PHPMailer\Exception; require_once __DIR__ . '/vendor/phpmailer/src/Exception.php'; require_once __DIR__ . '/vendor/phpmailer/src/PHPMailer.php'; require_once __DIR__ . '/vendor/phpmailer/src/SMTP.php'; require 'vendor/autoload.php'; $mail = new PHPMailer; if(isset($_POST['send'])){ // getting post values $fname=$_POST['fname']; $toemail=$_POST['toemail']; $subject=$_POST['subject']; $message=$_POST['message']; $mail->isSMTP(); // Set mailer to use SMTP $mail->Host = 'smtp.gmail.com'; $mail->SMTPAuth = true; $mail->Username = '[email protected]'; // SMTP username $mail->Password = 'mypassword'; // SMTP password // Enable TLS encryption, 'ssl' also accepted $mail->SMTPSecure = 'tls'; $mail->Port = 587; $mail->setFrom([email protected]', 'My_Name'); $mail->addReplyTo([email protected]', 'My_Name'); $mail->addAddress($toemail); // Add a recipient $mail->isHTML(true); // Set email format to HTML $bodyContent=$message; $mail->Subject =$subject; $body = 'Dear'.$fname; $body .='<p>'.$message.'</p>'; $mail->Body = $body; if(!$mail->send()) { echo 'Message could not be sent.'; echo 'Mailer Error: ' . $mail->ErrorInfo; } else { echo 'Message has been sent'; } } ?>
使用以下HTML表单撰写邮件。表单提交到上面的phpmail.php脚本
Email.html
<h1>PHP - Sending Email</h1> <form action="PHPmailer.php" method="post"> <label for="inputName">Name</label> <input type="text" id="inputName" name="fname" required> <label for="inputEmail">Email</label> <input type="email" id="inputEmail" name="toemail" required> <label for="inputSubject">Subject</label> <input type="text" id="inputSubject" name="subject" required> <label for="inputMessage">Message</label> <textarea id="inputMessage" name="message" rows="5" required></textarea> <button type="submit" name="send">Send</button> </form>
发送带有附件的电子邮件
要发送包含混合内容的电子邮件,应将 Content-type 头设置为 multipart/mixed。然后可以在边界内指定文本和附件部分。
边界以两个连字符开头,后面跟着一个唯一的数字,该数字不能出现在电子邮件的消息部分中。PHP 函数 md5() 用于创建一个 32 位十六进制数字来创建唯一数字。表示电子邮件最后一部分的最终边界也必须以两个连字符结尾。
示例
请看以下示例:
<?php // request variables $from = $_REQUEST["from"]; $emaila = $_REQUEST["emaila"]; $filea = $_REQUEST["filea"]; if ($filea) { function mail_attachment ($from , $to, $subject, $message, $attachment){ $fileatt = $attachment; // Path to the file $fileatt_type = "application/octet-stream"; // File Type $start = strrpos($attachment, '/') == -1 ? strrpos($attachment, '//') : strrpos($attachment, '/')+1; // Filename that will be used for the file as the attachment $fileatt_name = substr($attachment, $start, strlen($attachment)); $email_from = $from; // Who the email is from $subject = "New Attachment Message"; $email_subject = $subject; // The Subject of the email $email_txt = $message; // Message that the email has in it $email_to = $to; // Who the email is to $headers = "From: ".$email_from; $file = fopen($fileatt,'rb'); $data = fread($file,filesize($fileatt)); fclose($file); $msg_txt="\n\n You have recieved a new attachment message from $from"; $semi_rand = md5(time()); $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x"; $headers .= "\nMIME-Version: 1.0\n" . "Content-Type: multipart/mixed;\n" . " boundary=\"{$mime_boundary}\""; $email_txt .= $msg_txt; $email_message .= "This is a multi-part message in MIME format.\n\n" . "--{$mime_boundary}\n" . "Content-Type:text/html; charset = \"iso-8859-1\"\n" . "Content-Transfer-Encoding: 7bit\n\n" . $email_txt . "\n\n"; $data = chunk_split(base64_encode($data)); $email_message .= "--{$mime_boundary}\n" . "Content-Type: {$fileatt_type};\n" . " name = \"{$fileatt_name}\"\n" . //"Content-Disposition: attachment;\n" . //" filename = \"{$fileatt_name}\"\n" . "Content-Transfer-Encoding: "base64\n\n" . $data . "\n\n" . "--{$mime_boundary}--\n"; $ok = mail($email_to, $email_subject, $email_message, $headers); if($ok) { echo "File Sent Successfully."; // delete a file after attachment sent. unlink($attachment); } else { die("Sorry but the email could not be sent. Please go back and try again!"); } } move_uploaded_file($_FILES["filea"]["tmp_name"], 'temp/'.basename($_FILES['filea']['name'])); mail_attachment("$from", "[email protected]", "subject", "message", ("temp/".$_FILES["filea"]["name"])); } ?> <html> <head> <script language = "javascript" type = "text/javascript"> function CheckData45() { with(document.filepost) { if(filea.value ! = "") { document.getElementById('one').innerText = "Attaching File ... Please Wait"; } } } </script> </head> <body> <table width = "100%" height = "100%" border = "0" cellpadding = "0" cellspacing = "0"> <tr> <td align = "center"> <form name = "filepost" method = "post" action = "file.php" enctype = "multipart/form-data" id = "file"> <table width = "300" border = "0" cellspacing = "0" cellpadding = "0"> <tr valign = "bottom"> <td height = "20">Your Name:</td> </tr> <tr> <td><input name = "from" type = "text" id = "from" size = "30"></td> </tr> <tr valign = "bottom"> <td height = "20">Your Email Address:</td> </tr> <tr> <td class = "frmtxt2"><input name = "emaila" type = "text" id = "emaila" size = "30"></td> </tr> <tr> <td height = "20" valign = "bottom">Attach File:</td> </tr> <tr valign = "bottom"> <td valign = "bottom"><input name = "filea" type = "file" id = "filea" size = "16"></td> </tr> <tr> <td height = "40" valign = "middle"> <input name = "Reset2" type = "reset" id = "Reset2" value = "Reset"> <input name = "Submit2" type = "submit" value = "Submit" onClick = "return CheckData45()"> </td> </tr> </table> </form> <center> <table width = "400"> <tr> <td id = "one"></td> </tr> </table> </center> </td> </tr> </table> </body> </html>
它将产生以下输出:
PHP 输入过滤
在 PHP 中,务必确保通过删除任何不需要的字符来正确清理输入数据,然后再由服务器端代码处理。通常,用户通过 HTML 表单将其数据输入到 PHP Web 应用程序中。如果表单数据包含任何不需要的字符,则可能会造成危害,因此必须执行适当的清理操作。
可以使用 PHP 中的一个或多个以下函数进行输入清理。
htmlspecialchars() 函数
此函数将特殊字符转换为 HTML 实体。
htmlspecialchars( string $string, int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, ?string $encoding = null, bool $double_encode = true ): string
在 HTML 中,某些字符具有特殊的意义。此 htmlspecialchars() 函数用于将特殊字符编码为 HTML 实体。当您想将用户输入显示为 HTML 并想防止脚本注入攻击时,这非常有用。
以下 **特殊字符** 将按如下所示转换:
字符 | 替换为 |
---|---|
& (与号) | & |
" (双引号) | ",除非设置了 **ENT_NOQUOTES** |
' (单引号) | ' (对于 **ENT_HTML401**) 或 ' (对于 **ENT_XML1、ENT_XHTML** 或 **ENT_HTML5**), 但仅当设置了 **ENT_QUOTES** 时。 |
< (小于号) | < |
> (大于号) | > |
标志常量
**flags** 参数是一个或多个以下标志的位掩码,这些标志指定如何处理引号、无效代码单元序列和使用的文档类型。
序号 | 常量 & 说明 |
---|---|
1 | ENT_COMPAT 将转换双引号,而保留单引号。 |
2 | ENT_QUOTES 将转换双引号和单引号。 |
3 | ENT_NOQUOTES 将保留双引号和单引号。 |
4 | ENT_IGNORE 丢弃无效的代码单元序列,而不是返回空字符串。 |
5 | ENT_SUBSTITUTE 将无效的代码单元序列替换为 Unicode 替换字符 U+FFFD (UTF-8) 或 �。 |
6 | ENT_DISALLOWED 将给定文档类型中无效的代码点替换为 Unicode 替换字符 U+FFFD (UTF-8) 或 � (否则),而不是保留它们。这可能很有用。 |
7 | ENT_HTML401 将代码处理为 HTML 4.01。 |
8 | ENT_XML1 将代码处理为 XML 1。 |
9 | ENT_XHTML 将代码处理为 XHTML。 |
10 | ENT_HTML5 将代码处理为 HTML 5。 |
示例
请看以下示例:
<?php $str = 'Welcome To "PHP Tutorial" by <b>TutorialsPoint</b>'; echo htmlspecialchars($str); ?>
它将产生以下输出:
Welcome To "PHP Tutorial" by <b>TutorialsPoint</b>
strip_tags() 函数
strip_tags() 函数从给定的字符串中删除所有 HTML 和 PHP 标签。
strip_tags(string $string, array|string|null $allowed_tags = null): string
当您想确保用户输入不包含任何潜在的恶意标签时,此函数非常有用。
**allowed_tags** 参数是一个可选的第二个参数,用于指定不应去除的标签。这些标签可以作为字符串或数组给出。
示例
请看以下示例:
<?php $text = '<p>Hello World</p><!-- Comment --> <a href="/test.html">Click Here</a>'; echo strip_tags($text); echo "\n"; // Allow <p> and <a> echo strip_tags($text, '<p><a>'); ?>
它将产生以下输出:
Hello World Click Here Hello World Click Here
addslashes() 函数
addslashes() 函数在字符串中添加反斜杠。
addslashes(string $string): string
该函数返回一个字符串,其中在需要转义的字符前添加了反斜杠。这些字符是:
单引号 (')
双引号 (")
反斜杠 (\)
NUL (空字节)
当您将用户输入存储在数据库中并想防止 SQL 注入攻击时,请使用此函数。
示例
请看以下示例:
<?php $text = "Newton's Laws"; $str = addslashes($text); // prints the escaped string echo($str); ?>
它将产生以下输出:
Newton\'s Laws
filter_var() 函数
借助特定的过滤器标志,您可以使用 filter_var() 函数来清理用户输入。
filter_var(mixed $value, int $filter = FILTER_DEFAULT, array|int $options = 0): mixed
$value 参数是一个需要清理其值的变量。$filter 参数是任何预定义的过滤器常量。
序号 | ID & 描述 | |
---|---|---|
1 | FILTER_SANITIZE_EMAIL 删除除字母、数字和 !#$%&'*+-=?^_`{|}~@.[]. 之外的所有字符。 |
|
2 | FILTER_SANITIZE_ENCODED URL 编码字符串,可以选择性地去除或编码特殊字符。 |
|
3 | FILTER_SANITIZE_ADD_SLASHES 应用 addslashes()。(从 PHP 7.3.0 开始可用)。 |
|
4 | FILTER_SANITIZE_NUMBER_FLOAT 删除除数字、+- 和可选的 .,eE 之外的所有字符。 |
|
5 | FILTER_SANITIZE_NUMBER_INT 删除除数字、加号和减号之外的所有字符。 |
|
6 | FILTER_SANITIZE_SPECIAL_CHARS HTML 编码 '"<>& 和 ASCII 值小于 32 的字符,可以选择性地去除或编码其他特殊字符。 |
|
7 | FILTER_SANITIZE_FULL_SPECIAL_CHARS 等同于调用带有设置 **ENT_QUOTES** 的 htmlspecialchars()。可以通过设置 **FILTER_FLAG_NO_ENCODE_QUOTES** 来禁用编码引号。 | |
8 | FILTER_SANITIZE_URL 删除除字母、数字和 $-_.+!*'(),{}|\\^~[]`<>#%";/?:@&=. |
|
9 | FILTER_UNSAFE_RAW |
示例
以下代码显示如何清理电子邮件数据:
<?php $a = 'abc [email protected]'; $sa = filter_var($a, FILTER_SANITIZE_EMAIL); echo "$sa"; ?>
它将产生以下输出:
[email protected]
示例
以下代码显示如何清理 URL:
<?php $a = "http://example.c o m"; $sa = filter_var($a, FILTER_SANITIZE_URL); echo "$sa"; ?>
它将产生以下输出:
http://example.com
PHP POST-Redirect-GET (PRG)
在 PHP 中,PRG 代表“Post/Redirect/Get”。这是一种常用的技术,旨在防止在提交表单后重新提交表单。您可以轻松地在 PHP 中实现此技术以避免重复提交表单。
通常,HTML 表单使用 POST 方法将数据发送到服务器。服务器脚本获取数据以进行进一步处理,例如在后端数据库中添加新记录或运行查询以获取数据。如果用户意外刷新浏览器,则可能再次提交相同的表单数据,这可能会导致数据完整性丢失。PHP 中的 PRG 方法可帮助您避免此陷阱。
示例
首先,让我们考虑以下 PHP 脚本,该脚本呈现一个简单的 HTML 表单,并使用 POST 方法将其提交回自身。当用户填写数据并提交时,后端脚本获取数据、呈现结果并返回再次显示空白表单。
<?php if (isset($_POST["submit"])) { if ($_SERVER["REQUEST_METHOD"] == "POST") echo "First name: " . $_REQUEST['first_name'] . " " . "Last Name: " . $_REQUEST['last_name'] . ""; } ?> <html> <body> <form action="<?php echo $_SERVER['PHP_SELF'];?>" method="post"> First Name: <input type="text" name="first_name"> <br/> Last Name: <input type="text" name="last_name" /> <button type="submit" name="submit">Submit</button> </form> </body> </html>
假设服务器正在运行,上述脚本位于文档根文件夹中,并在浏览器中访问。
填写数据并提交。浏览器会回显结果,并重新渲染表单。现在,如果您尝试刷新浏览器页面,则会弹出如下所示的警告:
如果您按下 **继续**,则会再次发布相同的数据。
可以使用下图理解该问题:
PHP 脚本中采取以下步骤来避免此问题:
HTML 表单之前的 PHP 脚本启动一个新会话。
检查表单是否已使用 POST 方法提交。
如果是,则将表单数据存储在会话变量中
将浏览器重定向到结果页面。在我们的例子中,它是同一页面。使用 exit 命令终止此脚本,以确保不再执行任何代码。
如果 PHP 发现 REQUEST 方法不是 POST,则检查是否设置了会话变量。如果是,则将它们与表单的新副本一起呈现。
现在,即使刷新表单,您也已成功避免了重新提交的可能性。
示例
以下是使用 PRG 技术的 PHP 代码:
<?php session_start(); if (isset($_POST["submit"])) { $_SESSION['fname'] = $_POST['first_name']; $_SESSION['lname'] = $_POST['last_name']; header("Location: hello.php"); exit; } if (isset($_SESSION["fname"])) { echo "First name: " . $_SESSION['fname'] . " " . "Last Name: " . $_SESSION['lname'] . ""; unset($_SESSION["fname"]); unset($_SESSION["lname"]); } ?> <html> <body> <form action="<?php echo $_SERVER['PHP_SELF'];?>" method="post"> First Name: <input type="text" name="first_name"> <br /> Last Name: <input type="text" name="last_name" /> <button type="submit" name="submit">Submit</button> </form> </body> </html>
PHP 闪存消息
在 PHP Web 应用程序中,**消息闪现** 指的是使某些消息在浏览器窗口中弹出以供用户接收应用程序反馈的技术。能够为用户的交互提供有意义的反馈是一个重要的设计原则,它提供了更好的用户体验。
在 PHP Web 应用程序中,我们可以使用会话数据来不时地闪现有关某个操作成功或失败、通知或警告等的消息,以使用户了解情况。
**闪现消息** 允许您在一个页面上创建消息,并在另一个页面上显示一次。要将消息从一个页面传输到另一个页面,您可以使用 **$_SESSION** 超全局变量。
首先,您可以按照如下所示向 $_SESSION 数组添加变量:
<?php session_start(); $_SESSION['flash_message'] = "Hello World"; ?>
稍后,导航到另一个页面,并从 $_SESSION 变量中检索闪现的消息并将其分配给变量。然后,您可以显示消息,然后从 $_SESSION 中删除消息:
<?php session_start(); if(isset($_SESSION['flash_message'])) { $message = $_SESSION['flash_message']; unset($_SESSION['flash_message']); echo $message; } ?>
为了概括处理闪现消息的基本思想,我们将编写一个将消息添加到 $_SESSION 的函数:
session_start(); function create_flash_message(string $name, string $message): void { // remove existing message with the name if (isset($_SESSION[FLASH][$name])) { unset($_SESSION[FLASH][$name]); } // add the message to the session $_SESSION[FLASH][$name] = ['message' => $message]; }
让我们再编写另一个函数来读取消息,将其闪现在浏览器上,并将其从 $_SESSION 中删除。
function display_flash_message(string $name): void { if (!isset($_SESSION[FLASH][$name])) { return; } // get message from the session $flash_message = $_SESSION[FLASH][$name]; // delete the flash message unset($_SESSION[FLASH][$name]); // display the flash message echo format_flash_message($flash_message); }
**format_flash_message()** 函数使用适当的 CSS 规则对获得的字符串应用所需的格式。
如果应用程序闪现了多条消息,则可以使用以下示例检索和闪现所有消息:
function display_all_flash_messages(): void { if (!isset($_SESSION[FLASH])) { return; } // get flash messages $flash_messages = $_SESSION[FLASH]; // remove all the flash messages unset($_SESSION[FLASH]); // show all flash messages foreach ($flash_messages as $flash_message) { echo format_flash_message($flash_message); } }
使用以下 **flash() 函数** 来创建、格式化和闪现消息
function flash(string $name = '', string $message = ''): void { if ($name !== '' && $message !== '') { create_flash_message($name, $message); } elseif ($name !== '' && $message === '') { display_flash_message($name); // display a flash message } elseif ($name === '' && $message === '' ) { display_all_flash_messages(); // display all flash message } }
要实现上述方法,请在第一页上调用 **flash() 函数**。
flash('first', 'Hello World');
导航到另一个页面并调用 flash() 函数来检索和显示消息:
flash('first');
使用闪现消息的机制通常用于注册页面,以便在用户注册后将用户重定向到登录页面并显示欢迎消息。
PHP AJAX 简介
PHP 驱动的 Web 应用程序经常使用 AJAX,它们一起用于创建动态和交互式 Web 应用程序。AJAX 代表 **异步 JavaScript 和 XML**。它允许网页异步更新,无需重新加载整个页面。
在 AJAX 应用程序中,Web 浏览器和服务器端 PHP 脚本之间的数据交换是异步的。PHP 是一种服务器端脚本语言,可用于生成动态内容和处理数据。
由于 AJAX 在 Web 应用程序和 Web 服务器之间创建了一个称为 AJAX 引擎的附加层,因此我们可以使用 JavaScript 进行后台服务器调用并检索所需的数据,可以更新 Web 页面的请求部分,而无需强制重新加载页面。它减少了页面刷新时间,并为用户提供了快速且响应迅速的体验。
运行 AJAX 需要什么?
AJAX 使用的技术已经在所有现代浏览器中实现。因此,客户端不需要任何额外的模块来运行 AJAX 应用程序。AJAX 使用的技术是:
**JavaScript** - 它是 AJAX 的重要组成部分。它允许您创建客户端功能。或者我们可以说它用于创建 AJAX 应用程序。
**XML** - 用于在 Web 服务器和客户端之间交换数据。
**XMLHttpRequest** - 用于在 Web 浏览器和 Web 服务器之间执行异步数据交换。
**HTML 和 CSS** - 用于为网页文本提供标记和样式。
**DOM** - 用于动态地交互和更改网页布局和内容。
要将 AJAX 与 PHP 一起使用,您需要在 JavaScript 中使用 XMLHttpRequest 对象向 PHP 服务器发送请求。然后,PHP 服务器将处理请求并返回响应,通常以 JSON 或 XML 的形式。然后,JavaScript 代码可以解析响应并相应地更新网页。
JavaScript 中的 XMLHttpRequest 对象是一个基于浏览器的 API,允许开发人员向服务器发出 HTTP 请求而无需重新加载页面。这是 AJAX 编程的基础,它允许动态和交互式 Web 应用程序。
XMLHttpRequest 对象可用于:
从服务器检索数据,例如 JSON、XML 或 HTML。
向服务器发送数据,例如表单数据或文件上传。
更新网页而无需重新加载。
创建聊天应用程序和其他交互式功能。
要使用 XMLHttpRequest 对象,首先需要创建一个新的实例。然后,可以使用 open() 方法指定 HTTP 方法和请求 URL。接下来,如果需要,可以设置任何请求头。最后,可以使用 send() 方法发送请求。
示例
这是一个使用 XMLHttpRequest 对象从服务器检索数据的简单 JavaScript 代码示例:
// Create a new XMLHttpRequest object var xhr = new XMLHttpRequest(); // Set the HTTP method and request URL xhr.open("GET", "test.php"); // Send the request xhr.send(); // Listen for the onload event to be fired xhr.onload = function() { // Check the status code to ensure the request was successful if (xhr.status === 200) { // Get the response data. var users = JSON.parse(xhr.responseText); // Do something with the user data. } else { // Handle the error } };
服务器上的 PHP 脚本从 AJAX 请求中检索数据并发送回响应。
// Get the request data. $name = $_GET["name"]; // Create a response object. $response = new stdClass(); $response->message = "Hello, $name!"; // Send the response back to the client. header("Content-Type: application/json"); echo json_encode($response);
PHP AJAX 搜索
AJAX 是异步 JavaScript 和 XML 的缩写。Ajax 用于构建快速且动态的网页。下面的示例演示了使用 AJAX 函数与后端 PHP 脚本交互,以便在网页上提供搜索字段。
步骤 1
将以下脚本保存为“example.php”:
<html> <head> <style> span { color: green; } </style> <script> function showHint(str) { if (str.length == 0) { document.getElementById("txtHint").innerHTML = ""; return; } else { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { document.getElementById("txtHint").innerHTML = xmlhttp.responseText; } } xmlhttp.open("GET", "hello.php?q=" + str, true); xmlhttp.send(); } } </script> </head> <body> <p><b>Search your favourite tutorials:</b></p> <form> <input type = "text" onkeyup = "showHint(this.value)"> </form> <p>Entered Course name: <span id="txtHint"></span></p> </body> </html>
此代码本质上是一个 HTML 脚本,它呈现一个带有文本字段的 HTML 表单。在其 `onkeyup` 事件中,将调用 showHint() JavaScript 函数。该函数向服务器上的另一个 PHP 脚本发送 HTTP GET 请求。
步骤 2
将以下脚本保存为“php_ajax.php”:
<?php // Array with names $a[] = "Android"; $a[] = "B programming language"; $a[] = "C programming language"; $a[] = "D programming language"; $a[] = "euphoria"; $a[] = "F#"; $a[] = "GWT"; $a[] = "HTML5"; $a[] = "ibatis"; $a[] = "Java"; $a[] = "K programming language"; $a[] = "Lisp"; $a[] = "Microsoft technologies"; $a[] = "Networking"; $a[] = "Open Source"; $a[] = "Prototype"; $a[] = "QC"; $a[] = "Restful web services"; $a[] = "Scrum"; $a[] = "Testing"; $a[] = "UML"; $a[] = "VB Script"; $a[] = "Web Technologies"; $a[] = "Xerox Technology"; $a[] = "YQL"; $a[] = "ZOPL"; $q = $_REQUEST["q"]; $hint = ""; if ($q !== "") { $q = strtolower($q); $len = strlen($q); foreach($a as $name) { if (stristr($q, substr($name, 0, $len))) { if ($hint === "") { $hint = $name; } else { $hint .= ", $name"; } } } } echo $hint === "" ? "Please enter a valid course name" : $hint; ?>
步骤 3
我们将通过在浏览器中输入 URL `https://127.0.0.1/example.php` 来打开 example.php 来启动此应用程序。
在搜索字段中的每次按键操作中,都会向服务器发送一个 GET 请求。服务器脚本从 $_REQUEST 数组中读取字符,并搜索匹配的课程名称。匹配的值将显示在浏览器中的文本字段下方。
PHP AJAX XML 解析器
使用 PHP 和 AJAX,我们可以解析本地目录以及服务器上的 XML 文档。以下示例演示如何使用 Web 浏览器解析 XML。
客户端脚本呈现一个 HTML 表单,并定义一个 JavaScript 函数,用于使用 XMLHttpRequest 对象向服务器发送 HTTP 请求。
在服务器端,PHP 脚本从所需的 XML 文档加载 DOM 对象,从 $_REQUEST 变量中获取选定的课程,并将所选课程的详细信息作为响应呈现回客户端。
步骤 1
以下 XML 文档存储在 XAMPP 服务器的文档根目录中。
<?xml version = "1.0" encoding = "utf-8"?> <CATALOG> <SUBJECT> <COURSE>Android</COURSE> <COUNTRY>India</COUNTRY> <COMPANY>TutorialsPoint</COMPANY> <PRICE>$10</PRICE> <YEAR>2015</YEAR> </SUBJECT> <SUBJECT> <COURSE>Html</COURSE> <COUNTRY>India</COUNTRY> <COMPANY>TutorialsPoint</COMPANY> <PRICE>$15</PRICE> <YEAR>2015</YEAR> </SUBJECT> <SUBJECT> <COURSE>Java</COURSE> <COUNTRY>India</COUNTRY> <COMPANY>TutorialsPoint</COMPANY> <PRICE>$20</PRICE> <YEAR>2015</YEAR> </SUBJECT> <SUBJECT> <COURSE>Microsoft</COURSE> <COUNTRY>India</COUNTRY> <COMPANY>TutorialsPoint</COMPANY> <PRICE>$25</PRICE> <YEAR>2015</YEAR> </SUBJECT> </CATALOG>
步骤 2
下面的 AJAX 代码包含一个 HTML 表单和一个 JavaScript 函数,用于通过 XMLHttpRequest 对象发出 HTTP 请求。
<html> <head> <script> function showCD(str) { if (str == "") { document.getElementById("txtHint").innerHTML = ""; return; } if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp = new XMLHttpRequest(); } else { // code for IE6, IE5 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { document.getElementById("txtHint").innerHTML = xmlhttp.responseText; } } xmlhttp.open("GET","hello.php?q="+str,true); xmlhttp.send(); } </script> </head> <body> <form> Select a Course: <select name = "cds" onchange = "showCD(this.value)"> <option value = "">Select a course:</option> <option value = "Android">Android </option> <option value = "Html">HTML</option> <option value = "Java">Java</option> <option value = "Microsoft">MS technologies</option> </select> </form> <div id = "txtHint"><b>Course info will be listed here...</b></div> </body> </html>
步骤 3
服务器端用于在 XML 文档中搜索的 PHP 脚本如下:
<?php $q = $_GET["q"]; $xmlDoc = new DOMDocument(); $xmlDoc->load("test.xml"); $x = $xmlDoc->getElementsByTagName('COURSE'); for ($i = 0; $i<=$x->length-1; $i++) { if ($x->item($i)->nodeType == 1) { if ($x->item($i)->childNodes->item(0)->nodeValue == $q) { $y = ($x->item($i)->parentNode); } } } $cd = ($y->childNodes); for ($i = 0;$i<$cd->length;$i++) { if ($cd->item($i)->nodeType == 1) { echo("<b>" . $cd->item($i)->nodeName . ":</b> "); echo($cd->item($i)->childNodes->item(0)->nodeValue); echo("<br>"); } } ?>
访问“https://127.0.0.1/example.php”以允许用户选择课程。选择后,相关详细信息将从服务器提取并显示如下:
PHP AJAX 自动完成搜索
自动完成功能是一种键入提示机制,用于在用户在提供的搜索框中输入数据时显示输入建议。它也称为实时搜索,因为它会对用户的输入做出反应。在这个例子中,我们将使用 AJAX 和 PHP 中的 XML 解析器来演示自动完成文本框的使用。
此应用程序具有三个主要组成部分:
XML 文档
JavaScript 代码
PHP 中的 XML 解析器
现在让我们详细讨论这三个组成部分:
XML 文档
将以下 XML 脚本保存为“`autocomplete.xml`”到文档根文件夹
<?xml version = "1.0" encoding = "utf-8"?> <pages> <link> <title>android</title> <url>https://tutorialspoint.com/android/index.htm</url> </link> <link> <title>Java</title> <url>https://tutorialspoint.com/java/index.htm</url> </link> <link> <title>CSS </title> <url>https://tutorialspoint.com/css/index.htm</url> </link> <link> <title>angularjs</title> <url>https://tutorialspoint.com/angularjs/index.htm </url> </link> <link> <title>hadoop</title> <url>https://tutorialspoint.com/hadoop/index.htm </url> </link> <link> <title>swift</title> <url>https://tutorialspoint.com/swift/index.htm </url> </link> <link> <title>ruby</title> <url>https://tutorialspoint.com/ruby/index.htm </url> </link> <link> <title>nodejs</title> <url>https://tutorialspoint.com/nodejs/index.htm </url> </link> </pages>
JavaScript 代码
以下脚本呈现一个文本字段,供用户输入他选择的课程名称。每次按键操作都会调用一个 JavaScript 函数,并将输入值通过 GET 方法传递给服务器端的 PHP 脚本。服务器的响应将异步呈现。
将此代码保存为“`index.php`”。
<html> <head> <script> function showResult(str) { if (str.length == 0) { document.getElementById("livesearch").innerHTML = ""; document.getElementById("livesearch").style.border = "0px"; return; } if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { document.getElementById("livesearch").innerHTML = xmlhttp.responseText; document.getElementById("livesearch").style.border = "1px solid #A5ACB2"; } } xmlhttp.open("GET","livesearch.php?q="+str,true); xmlhttp.send(); } </script> </head> <body> <form> <h2>Enter Course Name</h2> <input type = "text" size = "30" onkeyup = "showResult(this.value)"> <div id = "livesearch"></div> <a href = "https://tutorialspoint.com">More Details</a> </form> </body> </html>
PHP 中的 XML 解析器
这是服务器上的 PHP 脚本。它解析给定的 XML 源文档,读取输入字段中输入的字符,在解析的 XNL 对象中搜索它,然后发送回响应。
将以下代码保存为“livesearch.php”。
<?php $xml_doc = new DOMDocument(); $xml_doc->load('autocomplete.xml'); $x=$xml_doc->getElementsByTagName('link'); $q = $_GET['q']; $result = ''; foreach($x as $node) { if (stripos("{$node->nodeValue}", $q) !== false) { $result .= "{$node->nodeValue}"; } } // Set $response to "No records found." in case no hint was found // or the values of the matching values if ($result == '') $result = 'No records found.'; // show the results or "No records found." echo $result; ?>
在 XAMPP 服务器运行的情况下,访问“https://127.0.0.1/index.php”,浏览器将显示一个输入文本字段。对于其中键入的每个字符,相关的建议都会显示在其下方。
PHP AJAX RSS Feed 示例
Really Simple Syndication (RSS)
RSS(代表 Really Simple Syndication)用于发布网站上经常更新的信息,例如音频、视频、图像等。我们可以使用 AJAX 和 PHP 将 RSS 提要集成到网站中。此代码演示如何在我们的网站上显示 RSS 提要。
Index.html
索引页面应如下所示:
<html> <head> <script> function showRSS(str) { if (str.length == 0) { document.getElementById("output").innerHTML = ""; return; } if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { document.getElementById("output").innerHTML = xmlhttp.responseText; } } xmlhttp.open("GET","rss.php?q="+str,true); xmlhttp.send(); } </script> </head> <body> <p>Please Select an option to get RSS:</p> <form> <select onchange = "showRSS(this.value)"> <option value = "">Select an RSS-feed:</option> <option value = "cnn">CNN</option> <option value = "bbc">BBC News</option> <option value = "pc">PC World</option> </select> </form> <br> <div id = "output">RSS-feeds</div> </body> </html>
rss.php
“rss.php”包含有关如何访问`RSS 提要`RSS 提要并将 RSS 提要返回到网页的语法。
<?php $q = $_GET["q"]; if($q == "cnn") { $xml = ("http://rss.cnn.com/rss/cnn_topstories.rss"); } elseif($q == "bbc") { $xml = ("http://newsrss.bbc.co.uk/rss/newsonline_world_edition/americas/rss.xml"); } elseif($q = "pcw"){ $xml = ("http://www.pcworld.com/index.rss"); } $xmlDoc = new DOMDocument(); $xmlDoc->load($xml); $channel = $xmlDoc->getElementsByTagName('channel')->item(0); $channel_title = $channel->getElementsByTagName('title') ->item(0)->childNodes->item(0)->nodeValue; $channel_link = $channel->getElementsByTagName('link') ->item(0)->childNodes->item(0)->nodeValue; $channel_desc = $channel->getElementsByTagName('description') ->item(0)->childNodes->item(0)->nodeValue; echo("<p><a href = '" . $channel_link . "'>" . $channel_title . "</a>"); echo("<br>"); echo($channel_desc . "</p>"); $x = $xmlDoc->getElementsByTagName('item'); for ($i = 0; $i<=2; $i++) { $item_title = $x->item($i)->getElementsByTagName('title') ->item(0)->childNodes->item(0)->nodeValue; $item_link = $x->item($i)->getElementsByTagName('link') ->item(0)->childNodes->item(0)->nodeValue; $item_desc = $x->item($i)->getElementsByTagName('description') ->item(0)->childNodes->item(0)->nodeValue; echo ("<p><a href = '" . $item_link . "'>" . $item_title . "</a>"); echo ("<br>"); echo ($item_desc . "</p>"); } ?>
它将产生以下输出:
PHP XML 简介
借助 PHP 的内置函数和库,我们可以处理 XML 数据的操作。XML(代表可扩展标记语言)是一种用于结构化文档交换的数据格式,尤其是在 Web 上。
XML 是一种流行的文件格式,用于序列化数据,存储数据,将其传输到另一个位置,并在目标位置重建它。
在本章中,我们将学习使用 PHP 进行 XML 处理的基础知识。
XML 的特性
XML 的一个特性是它既可以被人阅读也可以被机器阅读。XML 的规范由万维网联盟定义和标准化。PHP 解析器可以对 XML 数据执行读/写操作。
XML 标签
与 HTML 一样,XML 文档也是借助`标签`组成的。但是,您可以定义自己的标签,这与 HTML 不同,在 HTML 中您需要使用预定义标签来组成 HTML 文档。
HTML 标签主要对文本、图像、多媒体资源等应用格式化属性。XML 标签为数据元素定义用户指定的属性。
XML 文档
XML 文档具有标签的分层结构,这些标签定义文档内数据的元素和属性。每个 XML 文档都包含一个根元素,该元素包含其他元素。元素可以具有属性,这些属性提供有关元素的附加信息或属性。元素中的数据包含在开始和结束标签中。
示例
下面是一个典型 XML 文档的示例:
<?xml version = '1.0' encoding = 'UTF-8'?> <note> <Course>Android</Course> <Subject>Android</Subject> <Company>TutorialsPoint</Company> <Price>$10</Price> </note>
XML 解析器的类型
在 PHP 中,有两种类型的 XML 解析器可用:
基于树的解析器
基于事件的解析器
基于树的解析器
使用这种类型的解析器,PHP 会将整个 XML 文档加载到内存中,并将 XML 文档转换为树结构。它分析整个文档,并提供对树元素的访问。
`对于较小的文档,基于树的解析器效果很好`,但对于大型 XML 文档,它会导致主要的性能问题。`SimpleXML 解析器`和`DOM XML 解析器`是基于树的解析器的示例。
Simple XML 解析器
Simple XML 解析器也称为基于树的 XML 解析器,它将解析简单的 XML 文件。Simple XML 解析将调用 simplexml_load_file() 方法以访问特定路径中的 xml。
DOM 解析器
DOM 解析器也称为复杂节点解析器,用于解析高度复杂的 XML 文件。它用作修改 XML 文件的接口。DOM 解析器使用 UTF-8 字符编码进行编码。
基于事件的解析器
基于事件的解析器不会将整个 XML 文档加载到内存中。相反,它一次读取一个节点。解析器允许您实时交互。一旦您移动到下一个节点,旧节点将从内存中删除。
由于不涉及内存超载,这种类型的解析器适用于大型 XML 文档,并且文档的解析速度比任何基于树的解析器都快。XMLReader 和 XML Expat 解析器是基于事件的解析器的示例。
XML 解析器
XML 解析基于 SAX 解析。它比所有上述解析器都快。它将创建 XML 文件并解析 XML。XML 解析器使用 ISO-8859-1、US-ASCII 和 UTF-8 字符编码进行编码。
XML 阅读器
XML 阅读器解析也称为拉取 XML 解析。它用于更快地读取 XML 文件。它适用于具有 XML 验证的高度复杂的 XML 文档。
PHP 简单XML解析器
PHP 的 SimpleXML 扩展提供了一个非常简单易用的工具集,用于将 XML 转换为可以使用普通属性选择器和数组迭代器处理的对象。它是一个基于树的解析器,适用于简单的 XML 文件,但在处理较大且复杂的 XML 文档时可能会遇到问题。
SimpleXML 扩展中定义了以下函数:
simplexml_load_file
simplexml_load_file() 函数将 XML 文件解释为一个对象:
simplexml_load_file( string $filename, ?string $class_name = SimpleXMLElement::class, int $options = 0, string $namespace_or_prefix = "", bool $is_prefix = false ): SimpleXMLElement|false
给定文件中的格式良好的 XML 文档将转换为对象。
filename 参数是表示要解析的 XML 文件的字符串。class_name 是可选参数。它指定函数将返回其对象的类。该函数返回一个 SimpleXMLElement 类的对象,其属性包含 XML 文档中保存的数据,或者在失败时返回 `false`。
示例
请看以下示例:
<?php $xml = simplexml_load_file("test.xml") or die("Error: Cannot create object"); print_r($xml); ?>
它将产生以下输出:
SimpleXMLElement Object ( [Course] => Android [Subject] => Android [Company] => TutorialsPoint [Price] => $10 )
simplexml_load_string
simplexml_load_string() 函数将 XML 文件解释为一个对象。
simplexml_load_string( string $filename, ?string $class_name = SimpleXMLElement::class, int $options = 0, string $namespace_or_prefix = "", bool $is_prefix = false ): SimpleXMLElement|false
给定字符串中的格式良好的 XML 文档将转换为对象。
$data 参数是表示要解析的 XML 文档的字符串。class_name 是可选参数。它指定函数将返回其对象的类。该函数返回一个 SimpleXMLElement 类的对象,其属性包含 XML 文档中保存的数据,或者在失败时返回 `false`。
示例
请看以下示例:
<?php $data = "<?xml version = '1.0' encoding = 'UTF-8'?> <note> <Course>Android</Course> <Subject>Android</Subject> <Company>TutorialsPoint</Company> <Price>$10</Price> </note>"; $xml = simplexml_load_string($data) or die("Error: Cannot create object"); print_r($xml); ?>
它将产生以下输出:
SimpleXMLElement Object ( [Course] => Android [Subject] => Android [Company] => TutorialsPoint [Price] => $10 )
simplexml_import_dom
simplexml_import_dom() 函数从 DOM 节点构造一个 SimpleXMLElement 对象。
simplexml_import_dom(SimpleXMLElement|DOMNode $node, ?string $class_name = SimpleXMLElement::class): ?SimpleXMLElement
此函数获取 DOM 文档的节点并将其转换为 SimpleXML 节点。然后,此新对象可以用作本机 SimpleXML 元素。
node 参数是 DOM 元素节点。可以提供可选的 class_name,以便 simplexml_import_dom() 将返回 SimpleXMLElement 类的指定子类的对象。此函数返回的值是 SimpleXMLElement 或失败时的 null。
示例
请看以下示例:
<?php $dom = new DOMDocument; $dom->loadXML('<books><book><title>PHP Handbook</title></book></books>'); if (!$dom) { echo 'Error while parsing the document'; exit; } $s = simplexml_import_dom($dom); echo $s->book[0]->title; ?>
它将产生以下输出:
PHP Handbook
获取节点值
以下代码显示如何从 XML 文件中获取节点值,XML 应如下所示:
<?xml version = "1.0" encoding = "utf-8"?> <tutorialspoint> <course category = "JAVA"> <title lang = "en">Java</title> <tutor>Gopal</tutor> <duration></duration> <price>$30</price> </course> <course category = "HADOOP"> <title lang = "en">Hadoop</title>. <tutor>Satish</tutor> <duration>3</duration> <price>$50</price> </course> <course category = "HTML"> <title lang = "en">html</title> <tutor>raju</tutor> <duration>5</duration> <price>$50</price> </course> <course category = "WEB"> <title lang = "en">Web Technologies</title> <tutor>Javed</tutor> <duration>10</duration> <price>$60</price> </course> </tutorialspoint>
示例
PHP 代码应如下所示:
<?php $xml = simplexml_load_file("books.xml") or die("Error: Cannot create object"); foreach($xml->children() as $books) { echo $books->title . "<br> "; echo $books->tutor . "<br> "; echo $books->duration . "<br> "; echo $books->price . "<hr>"; } ?>
它将产生以下输出:
Java Gopal $30 ________________________________________ Hadoop Satish 3 $50 ________________________________________ html raju 5 $50 ________________________________________ Web Technologies Javed 10 $60 ________________________________________
PHP SAX 解析器示例
PHP 在 php.ini 设置文件中默认启用了 XML 解析器扩展。此解析器实现 SAX API,这是一种基于事件的解析算法。
基于事件的解析器不会将整个 XML 文档加载到内存中。相反,它一次读取一个节点。解析器允许您实时交互。一旦您移动到下一个节点,旧节点将从内存中删除。
基于 SAX 的解析机制比基于树的解析器更快。PHP 库包含用于处理 XML 事件的函数,如本章所述。
解析 XML 文档的第一步是使用 xml_parse_create() 函数创建一个解析器对象。
xml_parser_create(?string $encoding = null): XMLParser
此函数创建一个新的 XML 解析器,并返回一个 XMLParser 对象,供其他 XML 函数使用。
xml_parse() 函数开始解析 XML 文档。
xml_parse(XMLParser $parser, string $data, bool $is_final = false): int
xml_parse() 解析 XML 文档。配置事件的处理程序将根据需要调用多次。
XMLParser 扩展提供不同的事件处理程序函数。
xml_set_element_handler()
此函数设置 XML 解析器的元素处理程序函数。每当 XML 解析器遇到开始或结束标签时,都会发出元素事件。开始标签和结束标签有单独的处理程序。
xml_set_element_handler(XMLParser $parser, callable $start_handler, callable $end_handler): true
当打开新的 XML 元素时,调用 start_handler() 函数。当关闭 XML 元素时,调用 end_handler() 函数。
xml_set_character_data_handler()
此函数设置 XML 解析器的字符数据处理程序函数。字符数据大致包含 XML 文档的所有非标记内容,包括标签之间的空格。
xml_set_character_data_handler(XMLParser $parser, callable $handler): true
xml_set_processing_instruction_handler()
此函数设置 XML 解析器的处理指令 (PI) 处理程序函数。<?php ?> 是一个处理指令,其中 php 称为“PI 目标”。这些的处理是特定于应用程序的。
xml_set_processing_instruction_handler(XMLParser $parser, callable $handler): true
一个处理指令具有以下格式:
<?target data ?>
xml_set_default_handler()
此函数设置 XML 解析器的默认处理程序函数。未传递给其他处理程序的内容将传递给默认处理程序。您将在默认处理程序中获得诸如 XML 和文档类型声明之类的内容。
xml_set_default_handler(XMLParser $parser, callable $handler): true
示例
以下示例演示了使用 SAX API 解析 XML 文档。我们将使用如下所示的 SAX.xml:
<?xml version = "1.0" encoding = "utf-8"?> <tutors> <course> <name>Android</name> <country>India</country> <email>[email protected]</email> <phone>123456789</phone> </course> <course> <name>Java</name> <country>India</country> <email>[email protected]</email> <phone>123456789</phone> </course> <course> <name>HTML</name> <country>India</country> <email>[email protected]</email> <phone>123456789</phone> </course> </tutors>
示例
下面给出解析上述文档的 PHP 代码。它打开 XML 文件并调用 xml_parse() 函数,直到到达文件末尾。事件处理程序将数据存储在 tutors 数组中。然后逐个元素地输出该数组。
<?php // Reading XML using the SAX(Simple API for XML) parser $tutors = array(); $elements = null; // Called to this function when tags are opened function startElements($parser, $name, $attrs) { global $tutors, $elements; if(!empty($name)) { if ($name == 'COURSE') { // creating an array to store information $tutors []= array(); } $elements = $name; } } // Called to this function when tags are closed function endElements($parser, $name) { global $elements; if(!empty($name)) { $elements = null; } } // Called on the text between the start and end of the tags function characterData($parser, $data) { global $tutors, $elements; if(!empty($data)) { if ($elements == 'NAME' || $elements == 'COUNTRY' || $elements == 'EMAIL' || $elements == 'PHONE') { $tutors[count($tutors)-1][$elements] = trim($data); } } } $parser = xml_parser_create(); xml_set_element_handler($parser, "startElements", "endElements"); xml_set_character_data_handler($parser, "characterData"); // open xml file if (!($handle = fopen('sax.xml', "r"))) { die("could not open XML input"); } while($data = fread($handle, 4096)) { xml_parse($parser, $data); } xml_parser_free($parser); $i = 1; foreach($tutors as $course) { echo "course No - ".$i. '<br/>'; echo "course Name - ".$course['NAME'].'<br/>'; echo "Country - ".$course['COUNTRY'].'<br/>'; echo "Email - ".$course['EMAIL'].'<br/>'; echo "Phone - ".$course['PHONE'].'<hr/>'; $i++; } ?>
上述代码输出如下:
course No - 1 course Name - Android Country - India Email - [email protected] Phone - 123456789 ________________________________________ course No - 2 course Name - Java Country - India Email - [email protected] Phone - 123456789 ________________________________________ course No - 3 course Name - HTML Country - India Email - [email protected] Phone - 123456789 ________________________________________
PHP DOM 解析器示例
PHP 中的 DOM 扩展具有广泛的功能,我们可以使用这些功能对 XML 和 HTML 文档执行各种操作。我们可以动态构建 DOM 对象,从 HTML 文件或包含 HTML 标签树的字符串加载 DOM 文档。我们还可以将 DOM 文档保存到 XML 文件,或从 XML 文档中提取 DOM 树。
DOMDocument 类是 DOM 扩展中定义的最重要的类之一。
$obj = new DOMDocument($version = "1.0", $encoding = "")
它表示整个 HTML 或 XML 文档;作为文档树的根。DOMDocument 类包含许多静态方法的定义,其中一些方法在此介绍:
序号 | 方法与说明 |
---|---|
1 | createElement 创建新的元素节点 |
2 | createAttribute 创建新的属性 |
3 | createTextNode 创建新的文本节点 |
4 | getElementById 搜索具有特定 ID 的元素 |
5 | getElementsByTagName 搜索所有具有给定局部标签名称的元素 |
6 | load 从文件加载 XML |
7 | loadHTML 从字符串加载 HTML |
8 | loadHTMLFile 从文件加载 HTML |
9 | loadXML 从字符串加载 XML |
10 | save 将内部 XML 树转储回文件 |
11 | saveHTML 使用 HTML 格式将内部文档转储到字符串中 |
12 | saveHTMLFile 使用 HTML 格式将内部文档转储到文件中 |
13 | saveXML 将内部 XML 树转储回字符串中 |
示例
让我们为此示例使用以下 HTML 文件:
<html> <head> <title>Tutorialspoint</title> </head> <body> <h2>Course details</h2> <table border = "0"> <tbody> <tr> <td>Android</td> <td>Gopal</td> <td>Sairam</td> </tr> <tr> <td>Hadoop</td> <td>Gopal</td> <td>Satish</td> </tr> <tr> <td>HTML</td> <td>Gopal</td> <td>Raju</td> </tr> <tr> <td>Web technologies</td> <td>Gopal</td> <td>Javed</td> </tr> <tr> <td>Graphic</td> <td>Gopal</td> <td>Satish</td> </tr> <tr> <td>Writer</td> <td>Kiran</td> <td>Amith</td> </tr> <tr> <td>Writer</td> <td>Kiran</td> <td>Vineeth</td> </tr> </tbody> </table> </body> </html>
我们现在将通过在以下 PHP 代码中调用 loadHTMLFile() 方法来从上述 HTML 文件中提取文档对象模型:
<?php /*** a new dom object ***/ $dom = new domDocument; /*** load the html into the object ***/ $dom->loadHTMLFile("hello.html"); /*** discard white space ***/ $dom->preserveWhiteSpace = false; /*** the table by its tag name ***/ $tables = $dom->getElementsByTagName('table'); /*** get all rows from the table ***/ $rows = $tables[0]->getElementsByTagName('tr'); /*** loop over the table rows ***/ foreach ($rows as $row) { /*** get each column by tag name ***/ $cols = $row->getElementsByTagName('td'); /*** echo the values ***/ echo 'Designation: '.$cols->item(0)->nodeValue.'<br />'; echo 'Manager: '.$cols->item(1)->nodeValue.'<br />'; echo 'Team: '.$cols->item(2)->nodeValue; echo '<hr />'; } ?>
它将产生以下输出:
Designation: Android Manager: Gopal Team: Sairam ________________________________________ Designation: Hadoop Manager: Gopal Team: Satish ________________________________________ Designation: HTML Manager: Gopal Team: Raju ________________________________________ Designation: Web technologies Manager: Gopal Team: Javed ________________________________________ Designation: Graphic Manager: Gopal Team: Satish ________________________________________ Designation: Writer Manager: Kiran Team: Amith ________________________________________ Designation: Writer Manager: Kiran Team: Vineeth ________________________________________
PHP 登录示例
典型的 PHP Web 应用程序会在登录前对用户进行身份验证,方法是询问其凭据,例如用户名和密码。然后将凭据与服务器上可用的用户数据进行检查。在此示例中,用户数据以关联数组的形式提供。下面解释以下 PHP 登录脚本:
HTML 表单
代码的 HTML 部分呈现一个简单的 HTML 表单,该表单接受用户名和密码,并将数据发布给自己。
<form action = "<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>" method="post"> <div> <label for="username">Username:</label> <input type="text" name="username" id="name"> </div> <div> <label for="password">Password:</label> <input type="password" name="password" id="password"> </div> <section style="margin-left:2rem;"> <button type="submit" name="login">Login</button> </section> </form>
PHP 身份验证
PHP 脚本解析 POST 数据,并检查 users 数组中是否存在用户名。如果找到,它将进一步检查密码是否与数组中注册的用户相对应。
<?php if (array_key_exists($user, $users)) { if ($users[$_POST['username']]==$_POST['password']) { $_SESSION['valid'] = true; $_SESSION['timeout'] = time(); $_SESSION['username'] = $_POST['username']; $msg = "You have entered correct username and password"; } else { $msg = "You have entered wrong Password"; } } else { $msg = "You have entered wrong user name"; } ?>
用户名和相应的消息将添加到 $_SESSION 数组中。系统将提示用户输入正确的凭据或错误消息。
完整代码
这是完整的代码:
Login.php
<?php ob_start(); session_start(); ?> <html lang = "en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="loginstyle.css"> <title>Login</title> </head> <body> <h2 style="margin-left:10rem; margin-top:5rem;">Enter Username and Password</h2> <?php $msg = ''; $users = ['user'=>"test", "manager"=>"secret", "guest"=>"abc123"]; if (isset($_POST['login']) && !empty($_POST['username']) && !empty($_POST['password'])) { $user=$_POST['username']; if (array_key_exists($user, $users)){ if ($users[$_POST['username']]==$_POST['password']){ $_SESSION['valid'] = true; $_SESSION['timeout'] = time(); $_SESSION['username'] = $_POST['username']; $msg = "You have entered correct username and password"; } else { $msg = "You have entered wrong Password"; } } else { $msg = "You have entered wrong user name"; } } ?> <h4 style="margin-left:10rem; color:red;"><?php echo $msg; ?></h4> <br/><br/> <form action = "<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>" method="post"> <div> <label for="username">Username:</label> <input type="text" name="username" id="name"> </div> <div> <label for="password">Password:</label> <input type="password" name="password" id="password"> </div> <section style="margin-left:2rem;"> <button type="submit" name="login">Login</button> </section> </form> <p style="margin-left: 2rem;"> <a href = "logout.php" tite = "Logout">Click here to clean Session.</a> </p> </div> </body> </html>
Logout.php
要注销,用户单击指向logout.php的链接。
<?php session_start(); unset($_SESSION["username"]); unset($_SESSION["password"]); echo '<h4>You have cleaned session</h4>'; header('Refresh: 2; URL = login.php'); ?>
输入“https://127.0.0.1/login.php”启动应用程序。以下是不同场景:
正确的用户名和密码
密码错误
用户名错误
当用户单击底部的链接时,会话变量将被删除,并且登录屏幕将重新出现。
PHP Facebook 登录
可以使用社交媒体登录(也称为 SSO)要求用户登录 Web 应用程序。这样,用户无需创建新帐户。相反,用户可以使用其现有的社交媒体帐户信息登录。社交媒体登录的一些示例包括:Google、Facebook、LinkedIn、Apple。
在本章中,我们将解释如何使用 Facebook 凭据激活登录 PHP 应用程序。
添加 Facebook 登录功能的第一步是创建一个 Facebook 应用程序。访问https://developers.facebook.com/apps/creation/ 并使用您的 Facebook 帐户登录。
接下来,输入要创建的 Facebook 应用的名称:
进入应用设置并获取应用程序 ID 和密钥:
选择平台为网站:
接下来,您需要在 PHP 中设置 Facebook SDK。从“https://packagist.org.cn/packages/facebook/php-sdk”下载 PHP 版 Facebook SDK,或使用composer:composer require "facebook/graph-sdk-v5"。将 SDK 文件解压缩到您的 PHP 应用程序可以访问的目录中。
要在 PHP 代码中配置 Facebook SDK,请在您的 PHP 文件中包含 Facebook SDK 自动加载器:require_once __DIR__ . '/vendor/autoload.php';
设置您的应用的访问令牌和应用密钥:
$app_id = 'YOUR_APP_ID'; $app_secret = 'YOUR_APP_SECRET';
接下来,创建 Facebook 登录按钮。创建一个 HTML 按钮,并添加 Facebook 登录 JavaScript SDK 来触发登录流程:
<button id="facebook-login-button">Login with Facebook</button>
包含 Facebook JavaScript SDK:
<script src="https://127.0.0.1/en_US/sdk.js#xfbml=1&version=v13.0&appId=YOUR_APP_ID&autoLogApp=true" async defer></script>
创建一个 PHP 脚本以处理 Facebook 登录回调:
<?php session_start(); $fb = new Facebook\Facebook([ 'app_id' => $app_id, 'app_secret' => $app_secret, 'default_graph_version' => 'v13.0', ]); $helper = $fb->getRedirectLoginHelper(); $accessToken = $helper->getAccessToken(); if ($accessToken) { // User is logged in, handle their data $user = $fb->get('/me', ['fields' => 'id,name,email']); $_SESSION['user_data'] = $user; header('Location: profile.php'); } else { // User is not logged in, redirect to login page $loginUrl = $helper->getLoginUrl(['scope' => 'public_profile,email']); header('Location: ' . $loginUrl); } ?>
登录成功后,将用户数据存储在会话中,然后重定向到受保护的页面。在受保护的页面上,检查会话中的用户数据以验证访问权限。
PHP Paypal 集成
PayPal 是一个支付处理系统。我们可以使用 PHP 将 PayPal 与网站集成。
PayPal 集成文件系统
PayPal 集成文件系统包含四个文件,如下所示:
constants.php - 此文件包含 API 用户名、密码和签名。
CallerService.php - 此文件包含用于调用 PayPal 服务的 PayPal 服务。
confirmation.php - 此文件包含一个表单,其中包含进行支付流程所需的最小字段,它将返回支付成功或失败。
PayPal_entry.php - 此页面用于将用户数据发送到 PayPal。它充当 PayPal 和用户表单之间的适配器。
用户必须从此处下载 PayPal SDK 文件并解压缩 zip 文件。zip 文件包含四个 PHP 文件。我们不需要更改任何文件,除了“constants.php”。
constants.php
“constants.php”文件包含如下所示的代码:
<?php define('API_USERNAME', 'YOUR USER NAME HERE'); define('API_PASSWORD', 'YOUR PASSWORD HERE'); define('API_SIGNATURE', 'YOUR API SIGNATURE HERE'); define('API_ENDPOINT', 'https://api-3t.paypal.com/nvp'); define('USE_PROXY',FALSE); define('PROXY_HOST', '127.0.0.1'); define('PROXY_PORT', '808'); define('PAYPAL_URL', 'https://www.PayPal.com/webscr&cmd=_express-checkout&token='); define('VERSION', '53.0'); ?>
用户将以上语法中声明的用户名、密码和签名放在“constants.php”中。
这是一个实验性示例,因此最后的金额将添加到沙盒帐户。
PHP MySQL 登录
MySQL 是 PHP 驱动的 Web 应用程序的后端数据库的流行选择。在本章中,我们将学习为 PHP 应用程序开发一个登录页面,该页面验证给定的用户名和密码。
您应该有一个安装了 PHP 和 MySQL 的 Web 服务器,才能试验本章中讨论的示例。可以在您的操作系统上轻松安装 Apache、PHP 和 MySQL (MariaDB) 的捆绑二进制文件(例如 XAMPP)。
在运行示例代码之前,您应该有一个名为 mydb 的 MySQL 数据库,其中必须有一个名为 admin 的表。您可以使用以下 SQL 脚本创建表并插入测试数据
use mydb; CREATE TABLE `admin` ( `username` varchar(10) NOT NULL, `passcode` varchar(10) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; INSERT INTO `admin` (`username`, `passcode`) VALUES ('guest', 'abc123'), ('manager', 'secret'), ('user', 'test'); ALTER TABLE `admin` ADD PRIMARY KEY (`username`); COMMIT;
PHP 登录应用程序的第一部分是建立数据库连接对象。我们使用 myqli API 获取连接对象。将以下代码保存为“config.php”
Config.php
<?php define('DB_SERVER', 'localhost'); define('DB_USERNAME', 'root'); define('DB_PASSWORD', ''); define('DB_DATABASE', 'mydb'); $db = mysqli_connect(DB_SERVER,DB_USERNAME,DB_PASSWORD,DB_DATABASE); ?>
此 PHP 脚本在登录脚本中调用。它向用户显示一个 HTML 表单以输入用户名和密码。如果提交表单,PHP 将运行一个 SELECT 查询以检索 admin 表中用户名和密码与用户输入匹配的行。
$myusername = mysqli_real_escape_string($db,$_POST['username']); $mypassword = mysqli_real_escape_string($db,$_POST['password']); $sql = "SELECT * FROM admin WHERE username = '$myusername' and passcode = '$mypassword'"; $result = mysqli_query($db,$sql); $row = mysqli_num_rows($result);
如果行数为 1,则表示输入的用户名和密码匹配。用户名将保存到 $_SESSION 变量中,并将浏览器定向到 welcome.php 脚本。
Login.php
将以下代码保存为“login.php”:
<?php include("config.php"); session_start(); $error=''; if($_SERVER["REQUEST_METHOD"] == "POST") { // username and password sent from form $myusername = mysqli_real_escape_string($db,$_POST['username']); $mypassword = mysqli_real_escape_string($db,$_POST['password']); $sql = "SELECT * FROM admin WHERE username = '$myusername' and passcode = '$mypassword'"; $result = mysqli_query($db,$sql); $row = mysqli_num_rows($result); $count = mysqli_num_rows($result); if($count == 1) { // session_register("myusername"); $_SESSION['login_user'] = $myusername; header("location: welcome.php"); } else { $error = "Your Login Name or Password is invalid"; } } ?> <html> <head> <title>Login Page</title> <style type = "text/css"> body { font-family:Arial, Helvetica, sans-serif; font-size:14px; } label { font-weight:bold; width:100px; font-size:14px; } .box { border:#666666 solid 1px; } </style> </head> <body bgcolor = "#FFFFFF"> <div align = "center"> <div style = "width:300px; border: solid 1px #333333; " align = "left"> <div style = "background-color:#333333; color:#FFFFFF; padding:3px;"><b>Login</b></div> <div style = "margin:30px"> <form action = "" method = "post"> <label>UserName :</label><input type = "text" name = "username" class = "box"/><br /><br /> <label>Password :</label><input type = "password" name = "password" class = "box" /><br/><br /> <input type = "submit" value = " Submit "/><br /> </form> <div style = "font-size:11px; color:#cc0000; margin-top:10px"><?php echo $error; ?></div> </div> </div> </div> </body> </html>
Welcome.php
当用户经过身份验证时,“welcome.php”脚本将被调用。它读取会话变量以显示欢迎消息。
<?php include('session.php'); ?> <html> <head> <title>Welcome </title> </head> <body> <h1>Welcome <?php echo $login_session; ?></h1> <h2><a href = "logout.php">Sign Out</a></h2> </body> </html>
Logout.php
最后,注销脚本将删除会话并重定向用户到登录页面。
<?php session_start(); if(session_destroy()) { header("Location: login.php"); } ?>
要启动登录应用程序,请访问“https://127.0.0.1/login.php”
输入用户名和密码。按下提交按钮后,将针对 admin 表中的行检查这些输入。成功后,您将收到以下消息:
如果查询未获取任何匹配的行,则会显示错误消息,如下所示:
PHP 和 MySQL
PHP 几乎可以与所有数据库软件一起使用,包括 Oracle 和 Sybase,但最常用的数据库是免费的 MySQL 数据库。
您应该已经拥有了什么?
您已经学习过 MySQL 教程以了解 MySQL 基础知识。
下载并安装了最新版本的 MySQL。
创建了密码为guest123的数据库用户guest。
如果您尚未创建数据库,则需要 root 用户及其密码才能创建数据库。
我们将本章分为以下部分:
连接到 MySQL 数据库 - 学习如何使用 PHP 打开和关闭 MySQL 数据库连接。
使用 PHP 创建 MySQL 数据库 - 此部分解释如何使用 PHP 创建 MySQL 数据库和表。
使用 PHP 删除 MySQL 数据库 - 此部分解释如何使用 PHP 删除 MySQL 数据库和表。
将数据插入 MySQL 数据库 - 创建数据库和表后,您可能希望将数据插入创建的表中。本节将引导您完成数据插入的真实示例。
从 MySQL 数据库检索数据 - 学习如何使用 PHP 从 MySQL 数据库中提取记录。
使用 PHP 分页 - 此部分解释如何将查询结果显示在多个页面中以及如何创建导航链接。
将数据更新到 MySQL 数据库 - 此部分解释如何使用 PHP 将现有记录更新到 MySQL 数据库。
从 MySQL 数据库中删除数据 - 此部分解释如何使用 PHP 删除或清除 MySQL 数据库中的现有记录。
使用 PHP 备份 MySQL 数据库 - 学习以安全为目的备份 MySQL 数据库的不同方法。
PHP.INI 文件配置
在您的机器上安装 PHP 软件后,将在安装目录中创建 php.ini。对于 XAMPP,php.ini 位于 c:\xamm\php 文件夹中。这是一个重要的配置文件,它控制性能并设置所有与 PHP 相关的参数。
phpinfo() 函数显示 PHP、Apache、MySQL 和 Web 服务器安装的其他组件的不同参数及其当前值列表。
运行以下代码以显示设置,其中一个设置显示“php.ini”文件的路径。
<?php echo phpinfo(); ?>
已加载的配置文件
找到显示 php.ini 文件位置的“已加载的配置文件”设置。
C:\xampp\php\php.ini
PHP 的许多行为方面都由大量参数(称为指令)配置。“php.ini”文件中的大多数行以分号 (;) 开头,表示该行已注释。未注释的行才是有效的指令及其值。换句话说,要激活并为特定指令赋值,请删除开头的分号。
directive = value
指令名称*区分大小写*。指令是用于配置 PHP 或 PHP 扩展的变量。请注意,没有名称验证,因此如果找不到预期的指令,将使用默认值,该值可以是字符串、数字、PHP 常量(例如 E_ALL 或 M_PI)、INI 常量之一(On、Off、True、False、Yes、No 和 None)。
实际上,C:\XAMPP\PHP 文件夹包含两个 INI 文件,一个用于生产环境,另一个用于开发环境。
php.ini-development.ini 与其生产版本非常相似,只是在错误方面更为详细。在开发阶段,将其复制为 php.ini 以追踪代码中的错误。代码准备好部署后,使用 php.ini-production.ini 文件作为有效的 php.ini 文件,这实际上会在很大程度上抑制错误消息。
php.ini 中的指令分为不同的类别,例如错误处理、数据处理、路径和目录、文件上传、PHP 扩展和模块设置。
以下是“php.ini”文件中一些重要指令的列表:
short_open_tag = Off
短标签如下所示:<? ?>。如果要使用 XML 函数,则必须将此选项设置为 Off。
safe_mode = Off
如果将其设置为 On,则可能已使用 --enable-safe-mode 标志编译了 PHP。安全模式与 CGI 使用最相关。请参阅本章前面“CGI 编译时选项”部分中的说明。
safe_mode_exec_dir = [DIR]
此选项仅在安全模式开启时才相关;它也可以在 Unix 构建过程中使用 --with-exec-dir 标志进行设置。处于安全模式下的 PHP 仅执行此目录中的外部二进制文件。默认值为 /usr/local/bin。这与提供正常的 PHP/HTML 网页无关。
safe_mode_allowed_env_vars = [PHP_]
此选项设置用户在安全模式下可以更改的环境变量。默认情况下,只有以“PHP_”开头的变量。如果此指令为空,则大多数变量都是可更改的。
safe_mode_protected_env_vars = [LD_LIBRARY_PATH]
此选项设置用户在安全模式下不能更改的环境变量,即使 safe_mode_allowed_env_vars 设置得很宽松。
disable_functions = [function1, function2...]
PHP4 配置中一个受欢迎的补充,并在 PHP5 中得以延续的是能够出于安全原因禁用选定的函数。以前,这需要手动编辑 PHP 的 C 代码。文件系统、系统和网络函数可能是首先要删除的,因为允许通过 HTTP 写入文件和更改系统绝不是一个好主意。
max_execution_time = 30
set_time_limit() 函数在安全模式下不起作用,因此这是使脚本在安全模式下超时的主要方法。在 Windows 中,必须根据消耗的最大内存而不是时间来中止。如果使用 Apache,还可以使用 Apache 超时设置进行超时,但这也会应用于网站上的非 PHP 文件。
error_reporting = E_ALL & ~E_NOTICE
默认值为 E_ALL & ~E_NOTICE,除通知以外的所有错误。开发服务器应至少设置为默认值;只有生产服务器才应该考虑较小的值。
error_prepend_string = [""]
通过其结尾标记 error_append_string,此设置允许您使错误消息的颜色与其他文本不同,或者类似操作。
warn_plus_overloading = Off
如果 + 运算符与字符串一起使用(如在表单值中),此设置会发出警告。
variables_order = EGPCS
此配置设置取代了 gpc_order。两者现在都已弃用,register_globals 也已弃用。它设置不同变量的顺序:环境、GET、POST、COOKIE 和 SERVER(又名内置)。您可以更改此顺序。
变量将按从左到右的顺序依次被覆盖,最右边的变量每次都胜出。这意味着,如果您保留默认设置,并且碰巧对环境变量、POST 变量和 COOKIE 变量使用了相同的名称,则在进程结束时,COOKIE 变量将拥有该名称。在现实生活中,这种情况很少发生。
register_globals = Off
此设置允许您决定是否要将 EGPCS 变量注册为全局变量。此设置现已弃用,从 PHP4.2 开始,此标志默认设置为 Off。请改用超全局数组。本书中的所有主要代码清单都使用超全局数组。
magic_quotes_gpc = On
此设置转义传入的 GET/POST/COOKIE 数据中的引号。如果您使用许多可能提交给自己或其他表单并显示表单值的表单,则可能需要将此指令设置为 On 或准备对字符串类型数据使用 addslashes()。
magic_quotes_runtime = Off
此设置转义传入的数据库和文本字符串中的引号。请记住,SQL 在存储字符串时会为单引号和撇号添加反斜杠,并在返回它们时不会将其删除。如果此设置为 Off,则在输出来自 SQL 数据库的任何类型的字符串数据时,需要使用 stripslashes()。如果 magic_quotes_sybase 设置为 On,则此设置必须为 Off。
magic_quotes_sybase = Off
此设置使用 Sybase 样式的单引号而不是反斜杠转义传入的数据库和文本字符串中的单引号。如果 magic_quotes_runtime 设置为 On,则此设置必须为 Off。
auto_prepend_file = [path/to/file]
如果在此处指定路径,则 PHP 必须在每个 PHP 文件的开头自动 include() 它。包括路径限制也适用。
auto_append_file = [path/to/file]
如果在此处指定路径,则 PHP 必须在每个 PHP 文件的结尾自动 include() 它,除非您使用 exit() 函数进行转义。包括路径限制也适用。
include_path = [DIR]
如果设置此值,则只能从这些目录包含或需要文件。include 目录通常位于您的文档根目录下;如果您在安全模式下运行,则这是必需的。将其设置为 . 以包含与脚本所在的目录相同的目录中的文件。多个目录由冒号分隔:.:/usr/local/apache/htdocs:/usr/local/lib。
doc_root = [DIR]
如果您使用的是 Apache,则已在 httpd.conf 中为此服务器或虚拟主机设置了文档根目录。如果您使用的是安全模式,或者只想在网站的一部分(例如,仅在 Web 根目录的一个子目录中)启用 PHP,请在此处设置此值。
file_uploads = [on/off]
如果您将使用 PHP 脚本上传文件,请打开此标志。
upload_tmp_dir = [DIR]
除非您了解 HTTP 上传的含义,否则请勿注释此行!
session.save_handler = files
除极少数情况外,您都不希望更改此设置。所以不要碰它。
ignore_user_abort = [On/Off]
此设置控制网站访问者单击浏览器“停止”按钮时会发生什么。默认值为 On,这意味着脚本将继续运行到完成或超时。如果将设置更改为 Off,脚本将中止。此设置仅在模块模式下有效,在 CGI 模式下无效。
mysql.default_host = hostname
如果未指定其他主机,则连接到数据库服务器时使用的默认服务器主机。
mysql.default_user = username
如果未指定其他名称,则连接到数据库服务器时使用的默认用户名。
mysql.default_password = password
如果未指定其他密码,则连接到数据库服务器时使用的默认密码。
PHP 数组解构
在 PHP 中,“数组解构”是指将数组元素提取到单个变量中的机制。它也可以称为数组解包。PHP 的 list() 结构用于解构给定的数组,并将其项目在一个语句中分配给变量列表。
list($var1, $var2, $var3, . . . ) = array(val1, val2, val3, . . .);
因此,**val1** 赋值给 **$var1**,**val2** 赋值给 **$var2**,依此类推。即使由于括号的存在,您可能认为 list() 是一个函数,但它不是,因为它没有返回值。PHP 将字符串视为数组,但是不能用 list() 解包它。此外,list() 中的括号不能为空。
除了 list() 之外,您还可以使用方括号 [] 作为解构数组的快捷方式。
[$var1, $var2, $var3, . . . ] = array(val1, val2, val3, . . .);
示例
请看以下示例:
<?php $marks = array(50, 56, 70); list($p, $c, $m) = $marks; echo "Physics: $p Chemistry: $c Maths: $m" . PHP_EOL; # shortcut notation [$p, $c, $m] = $marks; echo "Physics: $p Chemistry: $c Maths: $m" . PHP_EOL; ?>
它将产生以下输出:
Physics: 50 Chemistry: 56 Maths: 70 Physics: 50 Chemistry: 56 Maths: 70
解构关联数组
在 PHP 7.1.0 之前,list() 仅适用于从 0 开始的数字索引的数字数组。在 PHP 7.1 中,数组解构也适用于关联数组。
让我们尝试解构(或解包)以下关联数组,一个具有非数字索引的数组。
$marks = array('p'=>50, 'c'=>56, 'm'=>70);
要解构此数组,list() 语句会将每个数组键与一个独立变量关联。
list('p'=>$p, 'c'=>$c, 'm'=>$m) = $marks;
或者,您还可以使用 [] 替代解构表示法。
['p'=>$p, 'c'=>$c, 'm'=>$m] = $marks;
尝试执行以下 PHP 脚本:
<?php $marks = array('p'=>50, 'c'=>56, 'm'=>70); list('p'=>$p, 'c'=>$c, 'm'=>$m) = $marks; echo "Physics: $p Chemistry: $c Maths: $m" . PHP_EOL; # shortcut notation ['p'=>$p, 'c'=>$c, 'm'=>$m] = $marks; echo "Physics: $p Chemistry: $c Maths: $m" . PHP_EOL; ?>
跳过数组元素
对于索引数组,您可以跳过其中一些元素,只将其他元素赋值给所需的变量。
<?php $marks = array(50, 56, 70); list($p, , $m) = $marks; echo "Physics: $p Maths: $m" . PHP_EOL; # shortcut notation [$p, , $m] = $marks; echo "Physics: $p Maths: $m" . PHP_EOL; ?>
对于关联数组,由于索引不是从 0 开始递增的,因此在赋值时不必遵循元素的顺序。
<?php $marks = array('p'=>50, 'c'=>56, 'm'=>70); list('c'=>$c, 'p'=>$p, 'm'=>$m) = $marks; echo "Physics: $p Chemistry: $c Maths: $m" . PHP_EOL; ['c'=>$c, 'm'=>$m, 'p'=>$p] = $marks; # shortcut notation echo "Physics: $p Chemistry: $c Maths: $m" . PHP_EOL; ?>
解构嵌套数组
您还可以将数组解构的概念扩展到嵌套数组。在下面的示例中,嵌套的子数组是一个索引数组。
<?php $marks = ['marks' => [50, 60, 70]]; ['marks' => [$p, $c, $m]] = $marks; echo "Physics: $p Chemistry: $c Maths: $m" . PHP_EOL; ?>
即使嵌套数组也是关联数组,解构也能很好地工作。
<?php $marks = ['marks' => ['p'=>50, 'c'=>60, 'm'=>70]]; ['marks' => ['p'=>$p, 'c'=>$c, 'm'=>$m]] = $marks; echo "Physics: $p Chemistry: $c Maths: $m" . PHP_EOL; ?>
PHP 编码规范
每个公司都根据其最佳实践遵循其自身的编码标准。需要编码标准是因为可能有许多开发人员从事不同的模块,如果他们开始发明自己的标准,那么源代码将变得非常难以管理,并且将来难以维护该源代码。
以下是应该使用编码规范的一些原因:
您的同行程序员必须理解您编写的代码。编码标准充当所有团队破译代码的蓝图。
一致的编码实现的简洁性和清晰性可避免常见的错误。
如果您过一段时间后修改代码,则更容易理解该代码。
遵循统一的编码标准可以提高软件质量。
在 PHP 中编码时,可以遵循一些准则。
缩进和行长
使用 4 个空格缩进,不要使用任何制表符,因为不同的计算机使用不同的制表符设置。建议将行长保持在大约 75-85 个字符,以提高代码可读性。
控制结构
这些包括 if、for、while、switch 等。控制语句在控制关键字和左括号之间应留有一个空格,以便将它们与函数调用区分开来。强烈建议您始终使用花括号,即使在技术上可选的情况下也是如此。
示例
if ((condition1) || (condition2)) { action1; } elseif ((condition3) && (condition4)) { action2; } else { default action; }
您可以按如下方式编写switch语句
switch (condition) { case 1: action1; break; case 2: action2; break; default: defaultaction; break; }
函数调用
函数调用时,函数名称、左括号和第一个参数之间不应有空格;逗号和每个参数之间应有空格;最后一个参数、右括号和分号之间不应有空格。这是一个示例:
$var = foo($bar, $baz, $quux);
函数定义
函数声明遵循“BSD/Allman 样式”:
function fooFunction($arg1, $arg2 = '') { if (condition) { statement; } return $val; }
注释
C 样式注释(/* */)和标准 C++ 注释(//)都可以。允许使用 Perl/shell 样式注释(#),但不鼓励使用。
PHP 代码标签
始终使用<?php ?> 来分隔 PHP 代码,而不是<? ?> 简写。这是 PHP 兼容性所必需的,也是在不同操作系统和设置上包含 PHP 代码最可移植的方式。
变量名
使用所有小写字母
使用 '_' 作为单词分隔符。
全局变量应以 'g' 开头。
全局常量应全部大写,并使用 '_' 分隔符。
静态变量可以以 's' 开头。
使函数可重入
函数不应保留阻止函数可重入的静态变量。
声明块的对齐
声明块应对齐。
每行一个语句
每行应只有一个语句,除非语句非常紧密相关。
简短的方法或函数
方法应限制在单页代码内。
编写 PHP 程序时,还应考虑许多其他要点。总体目标是在整个代码编程过程中保持一致,只有遵循任何编码标准才能做到这一点。如果您喜欢不同的内容,可以设计自己的标准。
PHP - 正则表达式
正则表达式只不过是字符本身的序列或模式。它们为模式匹配功能奠定了基础。
使用正则表达式,您可以在另一个字符串中搜索特定字符串,您可以用另一个字符串替换一个字符串,并且您可以将一个字符串拆分为许多块。
PHP 提供了特定于两组正则表达式函数的函数,每组函数对应于某种类型的正则表达式。您可以根据自己的喜好使用任何一种。
- POSIX 正则表达式
- PERL 风格正则表达式
POSIX 正则表达式
POSIX 正则表达式的结构与典型的算术表达式并不相似:各种元素(运算符)组合在一起形成更复杂的表达式。
最简单的正则表达式是匹配单个字符的表达式,例如字符串 g、haggle 或 bag 中的 g。
让我们解释一下 POSIX 正则表达式中使用的几个概念。之后,我们将向您介绍与正则表达式相关的函数。
方括号
方括号 ([]) 在正则表达式上下文中具有特殊含义。它们用于查找一系列字符。
序号 | 表达式和描述 |
---|---|
1 | [0-9] 它匹配从 0 到 9 的任何十进制数字。 |
2 | [a-z] 它匹配从 a 到 z 的任何小写字符。 |
3 | [A-Z] 它匹配从 A 到 Z 的任何大写字符。 |
4 | [a-Z] 它匹配从小写 a 到大写 Z 的任何字符。 |
上面显示的范围是通用的;您也可以使用范围 [0-3] 来匹配从 0 到 3 的任何十进制数字,或使用范围 [b-v] 来匹配从小写 b 到 v 的任何小写字符。
量词
括号字符序列和单个字符的频率或位置可以用特殊字符表示。每个特殊字符都有其特定的含义。+、*、?、{int. range} 和 $ 标志都跟在一个字符序列之后。
序号 | 表达式和描述 |
---|---|
1 | p+ 它匹配任何包含至少一个 p 的字符串。 |
2 | p* 它匹配任何包含零个或多个 p 的字符串。 |
3 | p? 它匹配任何包含零个或一个 p 的字符串。 |
4 | p{N} 它匹配任何包含N个 p 序列的字符串 |
5 | p{2,3} 它匹配任何包含两个或三个 p 序列的字符串。 |
6 | p{2, } 它匹配任何包含至少两个 p 序列的字符串。 |
7 | p$ 它匹配任何在结尾处有 p 的字符串。 |
8 | ^p 它匹配任何在开头处有 p 的字符串。 |
示例
以下示例将阐明您关于匹配字符的概念。
序号 | 表达式和描述 |
---|---|
1 | [^a-zA-Z] 它匹配任何不包含从 a 到 z 和从 A 到 Z 的任何字符的字符串。 |
2 | p.p 它匹配任何包含 p、后跟任何字符,然后后跟另一个 p 的字符串。 |
3 | ^.{2}$ 它匹配任何包含恰好两个字符的字符串。 |
4 | <b>(.*)</b> 它匹配任何包含在<b>和</b>之间的字符串。 |
5 | p(hp)* 它匹配任何包含 p 后跟零个或多个 php 序列的字符串。 |
预定义字符范围
为了方便您的编程,可以使用多个预定义字符范围,也称为字符类。字符类指定整个字符范围,例如字母或整数集:
序号 | 表达式和描述 |
---|---|
1 | [[:alpha:]] 它匹配任何包含字母字符 aA 到 zZ 的字符串。 |
2 | [[:digit:]] 它匹配任何包含数字 0 到 9 的字符串。 |
3 | [[:alnum:]] 它匹配任何包含字母数字字符 aA 到 zZ 和 0 到 9 的字符串。 |
4 | [[:space:]] 它匹配任何包含空格的字符串。 |
PHP 的 Regexp POSIX 函数
PHP 目前提供七个函数,用于使用 POSIX 风格正则表达式搜索字符串:
序号 | 函数及描述 |
---|---|
1 | ereg()
ereg() 函数在 string 指定的字符串中搜索 pattern 指定的字符串,如果找到该模式,则返回 true,否则返回 false。 |
2 | ereg_replace()
ereg_replace() 函数搜索 pattern 指定的字符串,如果找到,则用 replacement 替换 pattern。 |
3 | eregi()
eregi() 函数在 pattern 指定的字符串中搜索 string 指定的字符串。搜索不区分大小写。 |
4 | eregi_replace()
eregi_replace() 函数的工作方式与 ereg_replace() 完全相同,只是它对 string 中 pattern 的搜索不区分大小写。 |
5 | split()
split() 函数会将字符串分成多个元素,每个元素的边界基于 string 中 pattern 的出现。 |
6 | spliti()
spliti() 函数的工作方式与其同级 split() 完全相同,只是它不区分大小写。 |
7 | sql_regcase()
sql_regcase() 函数可以被认为是一个实用程序函数,它将输入参数字符串中的每个字符转换为包含两个字符的括号表达式。 |
PERL 风格正则表达式
Perl 风格正则表达式与其 POSIX 对应项类似。POSIX 语法几乎可以与 Perl 风格正则表达式函数互换使用。实际上,您可以使用上一节 POSIX 中介绍的任何量词。
让我们解释一下 PERL 正则表达式中使用的几个概念。之后,我们将向您介绍与正则表达式相关的函数。
元字符
元字符只是一个以反斜杠开头的字母字符,它赋予组合特殊的含义。
例如,您可以使用 '\d' 元字符搜索大量金额:/([\d]+)000/,这里\d将搜索任何数字字符的字符串。
以下是 PERL 风格正则表达式中可使用的元字符列表。
Character Description . a single character \s a whitespace character (space, tab, newline) \S non-whitespace character \d a digit (0-9) \D a non-digit \w a word character (a-z, A-Z, 0-9, _) \W a non-word character [aeiou] matches a single character in the given set [^aeiou] matches a single character outside the given set (foo|bar|baz) matches any of the alternatives specified
修饰符
有几个修饰符可以使您使用正则表达式的操作更容易,例如区分大小写、多行搜索等。
Modifier Description i Makes the match case insensitive m Specifies that if the string has newline or carriage return characters, the ^ and $ operators will now match against a newline boundary, instead of a string boundary o Evaluates the expression only once s Allows use of . to match a newline character x Allows you to use white space in the expression for clarity g Globally finds all matches cg Allows a search to continue even after a global match fails
PHP 的 Regexp PERL 兼容函数
PHP 提供以下函数,用于使用 Perl 兼容的正则表达式搜索字符串:
序号 | 函数及描述 |
---|---|
1 | preg_match()
preg_match() 函数在 string 中搜索 pattern,如果存在 pattern,则返回 true,否则返回 false。 |
2 | preg_match_all()
preg_match_all() 函数匹配 string 中 pattern 的所有出现。 |
3 | preg_replace()
preg_replace() 函数的工作方式与 ereg_replace() 完全相同,只是可以在 pattern 和 replacement 输入参数中使用正则表达式。 |
4 | preg_split()
preg_split() 函数的工作方式与 split() 完全相同,只是它接受正则表达式作为 pattern 的输入参数。 |
5 | preg_grep()
preg_grep() 函数搜索 input_array 的所有元素,返回与正则表达式 pattern 匹配的所有元素。 |
6 | preg_quote()
引用正则表达式字符 |
PHP 错误处理
PHP 中的错误处理是指在 PHP 代码中设置规定,以有效识别和恢复程序可能遇到的运行时错误。在 PHP 中,错误的处理借助于:
die() 函数
错误处理程序函数
die() 函数
die() 函数是 PHP 中 exit() 的别名。两者都会在遇到时终止当前 PHP 脚本。如果在括号中指定可选字符串,则会在程序终止之前输出该字符串。
die("message");
示例
以下代码是 die() 在 PHP 脚本中的典型用法。如果 PHP 找不到文件,它会显示“文件未找到”消息,否则会继续打开它以进行后续处理。
<?php if(!file_exists("nosuchfile.txt")) { die("File not found"); } else { $file = fopen("nosuchfile","r"); print "Opend file sucessfully"; // Rest of the code here. fclose($file); } ?>
它将产生以下输出:
File not found
使用上述技术,您可以随时停止程序出错并显示更有意义且用户友好的消息,而不是让 PHP 生成致命错误消息。
错误处理程序函数
使用 die() 进行错误处理被认为是一种笨拙且程序设计不良的做法,因为它会导致网站用户体验不佳。PHP 提供了一个更优雅的替代方案,您可以使用它来定义自定义函数并将其指定为错误处理程序。
set_error_handler() 函数具有以下参数:
set_error_handler(?callable $callback, int $error_levels = E_ALL): ?callable
第一个参数是一个用户定义的函数,每当遇到错误时都会自动调用该函数。
自定义错误处理程序回调函数应具有以下参数:
handler( int $errno, string $errstr, string $errfile = ?, int $errline = ?, array $errcontext = ? ): bool
参数
参数 | 重要性 | 描述 |
---|---|---|
errno | 必需 | 它指定用户定义错误的错误级别。它必须是数值。 |
errstr | 必需 | 它指定用户定义错误的错误消息。 |
errfile | 可选 | 它指定发生错误的文件名。 |
errline | 可选 | 它指定发生错误的行号。 |
errcontext | 可选 | 它指定一个数组,其中包含发生错误时正在使用的变量及其值。 |
如果回调函数返回 false,则将调用默认错误。
$errno 是与预定义错误级别对应的整数。
序号 | 常量 & 说明 | 值 |
---|---|---|
1 | E_ERROR (int) 无法恢复的致命运行时错误。脚本执行将停止。 |
1 |
2 | E_WARNING (int) 运行时警告(非致命错误)。脚本执行不会停止。 |
2 |
3 | E_PARSE (int) 编译时解析错误。解析错误应该只由解析器生成。 |
4 |
4 | E_NOTICE (int) 运行时提示。某些内容可能表示错误,但也可能在脚本正常运行过程中发生。 |
8 |
5 | E_CORE_ERROR (int) PHP 初始启动期间发生的致命错误。这类似于E_ERROR。 |
16 |
6 | E_CORE_WARNING (int) PHP 初始启动期间发生的警告(非致命错误)。这类似于E_WARNING。 |
32 |
7 | E_COMPILE_ERROR (int) 致命的编译时错误。这类似于E_ERROR。 |
64 |
8 | E_COMPILE_WARNING (int) 编译时警告(非致命错误)。这类似于E_WARNING。 |
128 |
9 | E_USER_ERROR (int) 用户生成的错误消息。这类似于E_ERROR,通过使用PHP函数trigger_error()在PHP代码中生成。 |
256 |
10 | E_USER_WARNING (int) 用户生成的警告消息。这类似于E_WARNING,通过使用函数trigger_error()在PHP代码中生成。 |
512 |
11 | E_USER_NOTICE (int) 用户生成的提示消息。这类似于E_NOTICE,通过使用函数trigger_error()在PHP代码中生成。 |
1024 |
12 | E_STRICT (int) 启用此选项可以使PHP建议对代码进行更改,以确保代码的最佳互操作性和向前兼容性。 |
2048 |
13 | E_RECOVERABLE_ERROR (int) 可捕获的致命错误。如果错误没有被用户定义的处理程序捕获,则应用程序将中止,如同E_ERROR一样。 |
4096 |
14 | E_DEPRECATED (int) 运行时提示。启用此选项可接收有关将来版本中无法运行的代码的警告。 |
8192 |
15 | E_USER_DEPRECATED (int) 用户生成的警告消息。这类似于E_DEPRECATED,通过使用函数trigger_error()在PHP代码中生成。 |
16384 |
16 | E_ALL (int) 所有错误、警告和提示。 |
32767 |
示例
请看以下示例:
<?php error_reporting(E_ERROR); function myerrorhandler($errno, $errstr) { echo "error No: $errno Error message: $errstr" . PHP_EOL; echo "Terminating PHP script"; die(); } set_error_handler("myerrorhandler"); $f = fopen("nosuchfile.txt", "r"); echo "file opened successfully"; // rest of the code fclose($f); ?>
它将产生以下输出:
error No: 2 Error message: fopen(nosuchfile.txt): Failed to open stream: No such file or directory Terminating PHP script
PHP 的错误类层次结构从 throwable 接口开始。PHP 中所有预定义的 Error 类都继承自 Error 类。
ArithmeticError 类
ArithmeticError 类继承自Error 类。此类错误可能在执行某些数学运算时发生,例如执行负数位的按位移位运算。
示例
请看以下示例:
<?php try { $a = 10; $b = -3; $result = $a << $b; } catch (ArithmeticError $e) { echo $e->getMessage(); } ?>
它将产生以下输出:
Bit shift by negative number
当调用 intdiv() 函数的结果值超出整数的合法范围时,也会抛出此错误。
示例
请看以下示例:
<?php try { $a = PHP_INT_MIN; $b = -1; $result = intdiv($a, $b); echo $result; } catch (ArithmeticError $e) { echo $e->getMessage(); } ?>
它将产生以下输出:
Division of PHP_INT_MIN by -1 is not an integer
DivisionByZeroError
DivisionByZeroError 类是 ArithmeticError 类的子类。当除法运算中分母的值为零时,就会发生此类错误。
示例:模零
请查看以下示例
<?php try { $a = 10; $b = 0; $result = $a%$b; echo $result; } catch (DivisionByZeroError $e) { echo $e->getMessage(); } ?>
它将产生以下输出:
Modulo by zero
当模运算符 (%) 的第二个运算数为 0,以及 intdiv() 函数的第二个参数为 0 时,也会发生这种情况。
示例:除以零
请看以下示例:
<?php try { $a = 10; $b = 0; $result = $a/$b; echo $result; } catch (DivisionByZeroError $e) { echo $e->getMessage(); } ?>
它将产生以下输出:
Division by zero
ArgumentCountError
当传递给用户定义函数或方法的参数少于其定义中的参数时,PHP 解析器将抛出 ArgumentCountError。
示例
请看以下示例:
<?php function add($x, $y) { return $x+$y; } try { echo add(10); } catch (ArgumentCountError $e) { echo $e->getMessage(); } ?>
它将产生以下输出:
Too few arguments to function add(), 1 passed in C:\xampp\php\test.php on line 9 and exactly 2 expected
TypeError
当实际参数类型和形式参数类型不匹配时,会引发此错误;返回值类型与声明的返回值类型不匹配。
示例
请看以下示例:
<?php function add(int $first, int $second) { echo "addition: " . $first + second; } try { add('first', 'second'); } catch (TypeError $e) { echo $e->getMessage(), ""; } ?>
它将产生以下输出:
add(): Argument #1 ($first) must be of type int, string given, called in /home/cg/root/63814/main.php on line 7
当向 PHP 的内置函数传递不正确的参数数量时,也会抛出 TypeError。但是,必须在开头设置“strict_types=1”指令。
示例
请看以下示例:
<?php declare(strict_types=1); try { echo pow(100,2,3); } catch (TypeError $e) { echo $e->getMessage(), ""; } ?>
它将产生以下输出:
pow() expects exactly 2 parameters, 3 given
PHP 中的异常处理
PHP 具有类似于其他编程语言的异常模型。异常很重要,并提供对错误处理的更好控制。
让我们解释一下与异常相关的新的关键字。
Try − 使用异常的函数应位于“try”块中。如果异常未触发,则代码将照常继续执行。但是,如果异常触发,则会“抛出”异常。
Throw − 这是触发异常的方式。“throw”必须至少有一个“catch”。
Catch − “catch”块检索异常并创建一个包含异常信息的 对象。
当抛出异常时,语句后面的代码将不会执行,PHP 将尝试查找第一个匹配的 catch 块。如果未捕获异常,则将发出 PHP 致命错误,并显示“未捕获的异常...”。
可以在 PHP 中抛出并捕获(“捕获”)异常。代码可以用 try 块包围。
每个 try 必须至少有一个相应的 catch 块。可以使用多个 catch 块来捕获不同类别的异常。
可以在 catch 块中抛出(或重新抛出)异常。
示例
以下是代码片段,请将此代码复制粘贴到文件中并验证结果。
<?php try { $error = 'Always throw this error'; throw new Exception($error); // Code following an exception is not executed. echo 'Never executed'; }catch (Exception $e) { echo 'Caught exception: ', $e->getMessage(), ""; } // Continue execution echo 'Hello World'; ?>
在上面的示例中,$e->getMessage 函数用于获取错误消息。以下函数可从Exception类中使用。
getMessage() − 异常消息
getCode() − 异常代码
getFile() − 源文件名
getLine() − 源代码行号
getTrace() − backtrace() 的数组
getTraceAsString() − 格式化的跟踪字符串
创建自定义异常处理程序
您可以定义自己的自定义异常处理程序。使用以下函数设置用户定义的异常处理程序函数。
string set_exception_handler ( callback $exception_handler )
这里exception_handler是当发生未捕获异常时要调用的函数的名称。此函数必须在调用 set_exception_handler() 之前定义。
示例
请看以下示例:
<?php function exception_handler($exception) { echo "Uncaught exception: " , $exception->getMessage(), "\n"; } set_exception_handler('exception_handler'); throw new Exception('Uncaught Exception'); echo "Not Executed"; ?>
查看完整的错误处理函数集,请访问 PHP 错误处理函数
PHP Try…Catch
在 PHP 中,提供try、catch、throw和finally关键字来处理异常。错误是意外的程序结果,程序本身无法处理,程序必须使用 die() 或设置自定义错误处理程序终止。
另一方面,异常是指可以以某种方式处理的意外情况,这样程序可以在将异常抛出其正常流程后继续运行。
可以在 PHP 代码中使用 catch 关键字抛出和捕获异常。可能容易发生异常的代码块用try块包围。每个try必须至少有一个对应的catch或finally块。
Try、Throw、Catch 和 Finally
这四个与异常相关的关键字具有以下作用:
Try − 可能发生某些异常的代码块放在“try”块中。如果异常未触发,则代码继续执行。但是,如果发生异常,则会“抛出”异常。执行将停止,PHP 将查找匹配的“catch”块。如果未捕获异常,PHP 将发出致命错误。
Throw − 这是触发异常的方式。“throw”必须至少有一个“catch”或“finally”块。
Catch − 一个检索异常并创建包含异常信息的 对象的块。可以使用多个 catch 块来捕获不同的异常。
Finally − finally 块中的代码总是在 throw 或 catch 块之后执行。
示例
这是一个异常处理技术的示例。代码在浏览器上呈现两个文本字段,并要求用户输入两个数字以执行它们的除法。如果第二个数字(分母)为 0,则会抛出异常,程序进入 catch 块并打印异常消息。否则,将显示除法的结果。
<html> <body> <form action="<?php echo $_SERVER['PHP_SELF'];?>" method="post"> <h3>First No: <input type="text" name="first"/></h3> <h3>Second No: <input type="text" name="second"/></h3> <input type="submit" value="Submit" /> </form> <?php if ($_SERVER["REQUEST_METHOD"] == "POST") { $x = $_POST['first']; $y = $_POST['second']; echo "$x $y"; try { if ($y == 0) { throw new Exception("Division by Zero"); } $z = $x/$y; echo "<h3>x = $x y = $y Division = $z<br>"; } catch (Exception $e) { echo "<h3> Exception: " . $e->getMessage(); } } ?> </body> </html>
它将产生以下输出:
Case 1: x = 10 y = 5 Division = 2 Case 2: x = 10 y = 0 Exception: Division by Zero
Exception 类
PHP 抛出Exception 类的对象。在 PHP 中,Exception 类是用户异常的基础。它实现了 throwable 接口。
此类定义了以下方法:
getMessage()
此函数将异常消息作为字符串返回:
final public Exception::getMessage(): string
getCode()
此函数返回 Exception 中的异常代码作为int:
final public Exception::getCode(): int
来看下面的示例:
try { throw new Exception("Some error message", 30); } catch(Exception $e) { echo "The exception code is: " . $e->getCode(); }
getFile()
此函数返回创建异常的文件名:
final public Exception::getFile(): string
来看下面的示例:
try { if ($y == 0) { throw new Exception("Division by Zero"); } $z = $x/$y; echo "<h3>x = $x y = $y Division = $z<br>"; } catch (Exception $e) { echo "<h3> Exception: " . $e->getMessage(). " in " . $e->getFile(); }
它将产生以下输出:
Exception: Division by Zero in C:\xampp\htdocs\hello.php
getLine()
此函数返回创建异常的行号:
final public Exception::getLine(): int
示例
请看以下示例:
<?php if ($_SERVER["REQUEST_METHOD"] == "POST") { $x = $_POST['first']; $y = $_POST['second']; echo "$x $y"; try { if ($y == 0) { throw new Exception("Division by Zero"); } $z = $x/$y; echo "<h3>x = $x y = $y Division = $z<br>"; } catch (Exception $e) { echo "<h3> Exception: " . $e->getMessage(). " in " . $e->getLine() . " of " . $e->getFile(); } } ?>
它将产生以下输出:
Exception: Division by Zero in 21 of C:\xampp\htdocs\hello.php
多个 Catch 块
PHP 允许在 try 块之后使用一系列 catch 块来处理不同的异常情况。可以使用多个catch块来处理预定义的异常和错误以及用户定义的异常。
示例
以下示例使用catch块来处理 DivisioByZeroError、TypeError、ArgumentCountError 和 InvalidArgumentException 条件。还有一个catch块用于处理常规 Exception。
<?php declare(strict_types=1); function divide(int $a, int $b) : int { return $a / $b; } $a=10; $b=0; try { if (!$b) { throw new DivisionByZeroError('Division by zero.'); if (is_int($a)==FALSE || is_int($b)==FALSE) throw new InvalidArgumentException("Invalid type of arguments"); $result=divide($a, $b); echo $result; } // if argument types not matching catch (TypeError $x) { echo $x->getMessage(); } // if denominator is 0 catch (DivisionByZeroError $y) { echo $y->getMessage(); } // if number of arguments not equal to 2 catch (ArgumentCountError $z) { echo $z->getMessage(); } // if argument types not matching catch (InvalidArgumentException $i) { echo $i->getMessage(); } // any uncaught exception catch (Exception $ex) { echo $ex->getMessage(); } ?>
首先,由于分母为 0,将显示“除以 0”错误:
Division by 0
设置$b=3将导致 TypeError,因为 divide 函数预期返回整数,但除法结果为float。
divide(): Return value must be of type int, float returned
如果仅将一个变量传递给 divide 函数,通过更改$res=divide($a);这将导致ArgumentCountError:
Too few arguments to function divide(), 1 passed in C:\xampp\htdocs\hello.php on line 16 and exactly 2 expected
如果其中一个参数不是整数,则为InvalidArgumentException的情况。将$b更改为字符串:
Invalid type of arguments
Finally 块
也可以在catch块之后或代替catch块指定finally块。finally块中的代码将在try和catch块之后始终执行,无论是否已抛出异常,以及在正常执行恢复之前。
try { if ($y == 0) { throw new Exception("Division by Zero"); } $z = $x/$y; echo "<h3>x = $x y = $y Division = $z </h3><br>"; } catch (Exception $e) { echo "<h3> Exception: " . $e->getMessage(). "</h3>"; } finally { echo "<h3>End of try - catch - finally</h3>"; }
它将产生以下输出:
情况 1:
x = 10 y = 5 Division = 2 End of try - catch – finally
情况 2:
X=10 y=0 Exception: Division by Zero End of try - catch – finally
带有 Return 的 Finally
当try块或catch块(或两者)包含return语句时,finally 块有一个特殊的行为。通常,return语句会导致程序的控制返回到调用位置。但是,对于具有带有return的 try/catch 块的函数,finally块中的语句将在返回之前先执行。
示例
在下面的示例中,div() 函数具有“try-catch-finally”结构。try块在没有异常的情况下返回除法的结果。如果发生异常,则catch块返回错误消息。但是,无论哪种情况,finally块中的语句都将首先执行。
<?php function div($x, $y) { try { if ($y==0) throw new Exception("Division by 0"); else $res=$x/$y;; return $res; } catch (Exception $e) { return $e->getMessage(); } finally { echo "This block is always executed\n"; } } $x=10; $y=0; echo div($x,$y); ?>
它将产生以下输出:
This block is always executed Division by 0
PHP 调试Bug
PHP 代码中的错误是指程序中的错误,会导致意外结果或崩溃。在用户发现错误之前找到错误的系统方法称为调试。本章介绍了一些在 PHP 代码中跟踪错误的重要技巧。
程序很少第一次就能正常工作。程序中可能会出现许多问题,这些问题会导致 PHP 解释器生成错误消息。您可以选择这些错误消息的去向。这些消息可以与其他程序输出一起发送到 Web 浏览器。它们也可以包含在“Web 服务器错误日志”中。
要在浏览器中显示错误消息,请将“display_errors”配置指令设置为 ON。确保在“php.ini”文件中启用了以下设置。
display_errors=On display_startup_errors=On
您还可以使用ini_set() 函数覆盖“pnp.ini”配置:
ini_set('display_errors', 1) ini_set('display_startup_errors', 1)
要将错误发送到 Web 服务器错误日志,请将“log_errors”设置为 ON。如果您希望错误消息同时出现在两个位置,则可以将它们都设置为 On。
PHP 定义了一些常量,您可以使用这些常量来设置error_reporting的值,以便仅报告特定类型的错误:
E_ALL(所有错误,除了严格提示)
E_PARSE(解析错误)
E_ERROR(致命错误)
E_WARNING(警告)
E_NOTICE(提示)
E_STRICT(严格提示)
编写PHP程序时,最好使用支持PHP的编辑器,例如BBEdit或Emacs。这些编辑器的特殊功能之一是语法高亮显示。它会根据程序不同部分的内容更改其颜色。例如,字符串为粉色,if和while等关键字为蓝色,注释为灰色,变量为黑色。
微软的VS Code也是编辑PHP代码的好选择。如果安装VS Code扩展Intelephense,您将在编辑器窗口输入PHP语句时获得类型提示和错误消息。
另一个功能是引号和括号匹配,这有助于确保引号和括号平衡。当您输入一个闭合分隔符,例如"}"时,编辑器会突出显示与其匹配的打开"{"。
调试代码时需检查的要点
调试程序代码时,需要验证以下几点:
缺少分号
每个PHP语句都以分号 (;) 结尾。PHP不会停止读取语句,直到它到达分号。如果您省略一行末尾的分号,PHP将继续读取下一行的语句。
等号不足
在比较语句中询问两个值是否相等时,需要使用两个等号 (==)。使用一个等号是一个常见的错误。
变量名拼写错误
如果拼写错误变量名,PHP会将其理解为一个新变量。记住:对PHP来说,$test与$Test不是同一个变量。
缺少美元符号
变量名中缺少美元符号很难发现,但至少通常会导致错误消息,以便您知道在哪里查找问题。
令人困扰的引号
引号可能过多、过少或类型错误。因此,请检查引号数量是否平衡。
缺少括号和花括号
它们应该总是成对出现。
数组索引
PHP中的数组是项目的集合,每个项目都分配一个从0开始递增的索引。
此外,请正确处理所有错误并将所有跟踪消息定向到系统日志文件,以便如果发生任何问题,它将被记录到系统日志文件中,并且您可以调试该问题。
面向C开发人员的PHP
如果您具备C编程的先验知识,学习PHP就会容易得多,尤其是基础知识。尽管PHP与C非常相似,但它包含了许多特定于Web的库,所有这些库都直接连接到您最喜欢的Web服务器。
理解PHP最简单的方法是将其视为可以嵌入HTML文档中的解释型C。PHP脚本也可以像C程序一样从命令行执行。
语句和函数定义的语法应该很熟悉,只是变量前面总是带有$,并且函数不需要单独的原型。
让我们来看看PHP和C的一些异同:
C和PHP之间的相似之处
语法 - 广义地说,PHP语法与C相同,如果您已经熟悉C,这使得学习PHP更容易。与C类似,PHP代码不区分空格,语句以分号结尾。
函数调用具有相同的结构
my_function(expression1, expression2) { Statements; }
花括号用于将多个语句放入块中。
PHP支持C和C++风格的注释(/* */以及//),以及Perl和shell脚本风格(#)。
运算符 - 赋值运算符(=, +=, *=, 等等),布尔运算符(&&, ||, !),比较运算符(<,>, <=, >=, ==, !=),以及基本算术运算符(+, -, *, /, %)在PHP中的行为与在C中相同。
控制结构 - 基本控制结构(if, switch, while, for)的行为与在C中相同,包括支持break和continue。一个显著的区别是PHP中的switch可以接受字符串作为case标识符。
PHP还具有foreach循环结构,该结构遍历集合,例如数组。
函数名 - 当您仔细阅读文档时,您会看到许多函数名似乎与C函数相同。
C和PHP之间的区别
美元符号 - 所有变量名都以一个前导$为前缀。变量不需要在赋值之前声明,并且它们没有内在类型。PHP是一种动态类型语言,而C是一种静态类型语言。
类型 - PHP只有两种数值类型:整数(对应于C中的long)和双精度浮点数(对应于C中的double)。在PHP中,float与double同义。字符串的长度是任意的。PHP中没有单独的char类型,就像C中那样。
类型转换 - C是一种强类型语言,因为变量的类型必须在使用之前声明,并且类型在编译时进行检查。另一方面,PHP是一种弱类型语言,类型在编译时不进行检查,并且类型错误通常也不会在运行时发生。相反,变量和值会根据需要自动在类型之间转换。
数组 - 数组的语法表面上与C的数组语法类似,但它们的实现完全不同。在C中,数组是相似数据类型的集合。在PHP数组中,项目可以是不同类型的。PHP数组实际上是关联数组或哈希表,索引可以是数字或字符串。它们不需要预先声明或分配。
没有结构体类型 - C中的struct关键字用于定义新的数据类型。PHP中没有struct关键字或其等价物,部分原因是数组和对象类型一起使其变得不必要。PHP数组的元素不必具有一致的类型。
没有指针 - 指针是C中的一个重要概念。PHP中没有指针,尽管无类型的变量扮演着类似的角色。与C不同,PHP支持变量引用。您还可以模拟函数指针到某种程度,因为函数名可以存储在变量中,并通过使用变量而不是文字名称来调用。
没有原型 - 函数不需要在其实现定义之前声明,只要定义可以在当前代码文件或包含文件中找到即可。相反,C函数必须在使用之前定义。
没有main() - 在C程序中,main()函数是入口点,无论它在代码中的哪个位置。另一方面,PHP程序从脚本中的第一条语句开始执行。
内存管理 - PHP引擎实际上是一个垃圾收集环境(引用计数),在小型脚本中无需进行任何释放。您可以随意分配新的结构——例如新的字符串和对象实例。在PHP5中,可以为对象定义析构函数,但是没有像C/C++中的free或delete关键字。当最后一个对对象的引用消失之前,在内存被回收之前,会调用析构函数。
编译和链接 - PHP是一种解释型语言。因此,不会创建PHP脚本的编译版本。C程序首先编译以获得目标代码,然后将其链接到所需的库以构建可执行文件。PHP脚本没有单独的编译步骤。PHP脚本不能转换为自执行文件。
宽容性 - 一般来说,PHP比C(尤其是在其类型系统中)更宽容,因此它会让您摆脱新型错误。意外结果比错误更常见。
面向Perl开发人员的PHP
Perl是一种动态类型、高级和通用的编程语言。通常认为Perl是Practical Extraction and Reporting Language的首字母缩写。另一方面,PHP也是一种通用的脚本语言。最初PHP是Personal Home Page的缩写,但如今它已被认为是递归缩写“PHP: Hypertext Preprocessor”。
本章列出了PHP和Perl之间的一些主要异同。这将帮助Perl开发人员快速理解PHP并避免常见错误。
Perl和PHP之间的相似之处
Perl和PHP都是脚本语言。它们不用于在执行之前构建本机独立可执行文件。
早期的PHP版本受到Perl的启发。PHP的基本语法与Perl非常相似。两者都与C共享许多语法特性。它们的代码不区分空格,每个语句都以分号结尾。
PHP和Perl都使用花括号将多个语句组织成单个块。在两种情况下,函数调用都以函数名称开头,后跟括在括号中并用逗号分隔的实际参数。
PHP中的所有变量都像Perl中的标量变量:前面带美元符号 ($) 的名称。
由于这两种语言都是动态类型的,因此您不需要在使用PHP和Perl变量之前声明其类型。
在PHP中,与Perl一样,变量除了它们当前持有的值之外没有内在类型。您可以将数字或字符串存储在相同类型的变量中。
PHP和Perl都比单引号字符串('string')对双引号字符串("string")进行更多的解释。
Perl和PHP之间的区别
PHP可以嵌入HTML中。尽管可以从命令行运行PHP脚本,但它更常用作Web服务器上的服务器端脚本语言,并用于生成网页。
如果您习惯于使用Perl编写CGI脚本,PHP中的主要区别在于您不再需要使用print或heredoc语句显式打印大块静态HTML,而可以直接在PHP代码块之外编写HTML本身。
没有@或%变量 - PHP只有一种变量,它以美元符号 ($) 开头。语言中的任何数据类型都可以存储在这些变量中,无论是标量还是复合类型。在Perl中,数组变量以@符号为前缀。此外,哈希变量以%符号为前缀。
与Perl不同,PHP有一种名为数组的单一数据类型,它可以是索引数组或关联数组,这类似于Perl中的哈希。
PHP 中的函数调用看起来非常类似于PERL 中的子程序调用。另一方面,PHP 中的函数定义通常需要某种形式参数列表,就像 C 或 Java 中那样,而 PERL 中则不是这样。
PERL 中变量的作用域默认情况下是全局的。这意味着顶级变量在子程序内是可见的。通常,这会导致在函数之间滥用全局变量。在 PHP 中,函数定义内变量的作用域默认情况下是局部的。
PHP 本身没有模块系统。在 PHP 中,普通代码文件和用作导入库的代码文件之间没有真正的区别。
Break 和 continue 而不是 next 和 last —— PHP 更像 C 语言,使用 break 和 continue,而不是像 PERL 中那样使用 next 和 last 语句。
没有 elsif —— 一个小的拼写差异:Perl 的 elsif 是 PHP 的 elseif。
除了 Perl 风格的 (#)单行注释之外,PHP 还提供 C 风格的多行注释 (/* comment */) 和 Java 风格的单行注释 (// comment)。
正则表达式——PHP 本身没有针对正则表达式的特定语法,但在其“Perl 兼容”的正则表达式函数中具有大部分相同的功能。
PHP – 框架
PHP 生态系统有很多 Web 框架。一些流行的 PHP Web 框架包括 Laravel、Yii、CakePHP 等。虽然可以使用核心 PHP 来构建 Web 应用程序,但开发人员越来越倾向于使用 Web 框架来进行快速应用程序开发。
什么是软件框架?
在计算机编程中,软件框架是一组库和类,它们提供通用功能,允许开发人员更多地关注应用程序逻辑,而不是编写例行但繁琐的低级过程的代码。
框架提供了一个可重用的软件环境,可以快速构建一个最小的可运行模板应用程序。开发人员可以修改这些模块以实现其他功能。
每个框架都是为了帮助开发人员构建特定类型的应用程序而构建的。例如,Web 框架(有时也称为“Web 应用程序框架”)用于开发 Web 应用程序,包括 Web 服务、Web 资源和 Web API。
在本章中,让我们简要概述一些流行的 PHP 框架。
FuelPHP
FuelPHP (https://fuelphp.com/) 基于模型-视图-控制器 (MVC) 并具有创新的插件。FuelPHP 支持基于路由的理论,您可以在其中直接路由到更接近输入 URI 的位置,使闭包成为控制器并赋予其进一步执行的控制权。
CakePHP
CakePHP (https://cakephp.com.cn/) 是一个构建简单而强大的 Web 应用程序的绝佳资源。PHP 中的一些内置强大功能包括输入验证和 SQL 注入防护,可确保您的应用程序安全可靠。
FlightPHP
FlightPHP (https://flightphp.com/) 对创建 RESTful Web 服务非常有帮助,并且它是 MIT 许可的。
Symfony
Symfony 适用于高级专业开发人员,用于使用 PHP 组件(例如 Drupal、PHPBB、Laravel、eX、OROCRM 和 Piwik)构建网站。
Yii Framework
Yii Framework (https://yiiframework.cn/) 基于 Web 2.0,具有高端安全性。它包括输入验证、输出过滤和 SQL 注入防护。
Laravel
Laravel (https://laravel.net.cn/) 最适用于 RESTful 路由和轻量级刀片模板引擎。Laravel 集成了经过良好测试和可靠代码的一些强大组件。
Zend
Zend (https://framework.zend.com/) 是一个用于执行高端 Web 应用程序的现代框架。它基于加密和安全的编码工具。Zend Framework 是一个包含 5.7 亿多次安装的专业 PHP 包集合。
它可以用于使用 PHP 5.6+ 开发 Web 应用程序和服务,并使用广泛的语言特性提供 100% 面向对象的代码。
CodeIgniter
CodeIgniter 对于需要简单优雅的工具包来创建创新型 Web 应用程序的开发人员来说,易于开发小型应用程序。
Phalcon PHP
Phalcon (https://phalcon.io/en-us) 是一个基于 MVC 并集成了创新架构以实现更快性能的 PHP 框架。
PHPixie
PHPixie (https://phpixie.com/) 基于 MVC,旨在快速可靠地开发网站。
Agavi
Agavi 是一个功能强大且可扩展的 PHP5 应用程序框架,它遵循 MVC 模型。Agavi 可以帮助 PHP 开发人员编写简洁易维护的代码。
核心 PHP 与框架
PHP 是迄今为止最流行的用于 Web 应用程序开发的服务器端编程语言,几乎 75% 的网站使用 PHP 的核心形式或可用的 PHP 框架之一。为了在使用“核心 PHP”还是框架进行 Web 开发之间做出选择,我们需要了解两者的优缺点。
简单来说,仅使用核心 PHP 开发 Web 应用程序就像手动解决数学问题一样,需要在纸上写下每一个步骤。另一方面,使用框架类似于使用计算器等工具来解决问题。正如计算器一样,框架是快速应用程序开发的有用工具。
核心 PHP 与框架——优缺点
Web 框架,尤其是 PHP 框架,是一个或多个 PHP 库和类的集合。它提供通用功能,允许开发人员更多地关注应用程序逻辑,而不是从头编写代码。它提供可重用的软件环境,可以快速构建最小的可运行模板应用程序。
仅用核心 PHP 开发 Web 应用程序有其自身的优点和缺点——
它使开发人员能够更好地控制和灵活操作。
同时,对于仅使用核心 PHP 开发的大型应用程序而言,可能会变得笨拙、难以管理和维护。
现在,让我们来看一下使用 PHP 框架的优缺点——
像 Symfony、Laravel 或 Yii 这样的 PHP 框架为 Web 应用程序开发提供了一种更标准化的方法。通过框架处理大部分例行和重复的部分,开发人员可以更多地关注应用程序逻辑。因此,在调试上浪费的时间更少。
另一方面,与核心 PHP 相比,框架的灵活性较差。框架可以随时提供应用程序的骨架模板,开发人员只需在框架定义的范围内自定义功能即可。
MVC 架构
大多数 Web 应用程序框架都采用MVC(模型、视图和控制器)架构,通过将逻辑与样式分离,使编写高质量、健壮的代码变得容易得多。
如果您希望将核心 PHP 功能用于应用程序开发,您可以自由地采用面向对象方法或模块化方法,无论哪种方法适合您。
内置安全措施
PHP 框架提供内置的安全措施,可以将其整合到 Web 应用程序中。
如果您选择使用核心 PHP 开发应用程序,则必须明确提供安全措施。
但是,大多数框架都有一些外部依赖项,这可能会使应用程序比自包含的核心 PHP 应用程序更容易受到攻击。
与核心 PHP 应用程序相比,基于框架的应用程序在性能方面可能会稍慢一些,特别是对于较小的应用程序。
比较:核心 PHP 与框架
两者之间的比较可以总结如下——
对于小型应用程序,核心 PHP 比框架更可取。
框架提供快速开发和代码重用。
框架的灵活性较差。
使用核心 PHP 功能,开发人员可以完全控制。
对于大型应用程序,MVC 架构很有帮助。
框架提供集成的授权和身份验证支持。在核心 PHP 应用程序中,需要明确定义安全规则。
PHP – 设计模式
在软件工程理论中,“设计模式”一词通常是指可重用的解决方案,可以用作开发应用程序的模板,以解决常见问题。您可以将软件设计模式视为开发软件解决方案时的正式最佳实践。
大多数标准设计模式都可以非常有效地应用于 PHP 应用程序的开发中。在本章中,我们将学习如何在开发 PHP 应用程序中应用一些流行的设计模式。
单例模式
当您希望将某个类的对象的实例化限制为只有一个实例时,单例设计模式非常有用。“单例模式”这个名称来自数学中的单例概念。单例模式确保只有一个实例,并在整个应用程序中对其进行全局访问。
单例模式的典型应用是创建数据库连接对象,该对象必须在应用程序的生命周期中创建一次。
示例
在以下代码中,DataBaseConnector 类只能实例化一次,否则将发出禁止重复对象的提示。
<?php class DataBaseConnector { private static $obj; private final function __construct() { echo __CLASS__ . " object created for first time ". PHP_EOL; } public static function getConnect() { if (!isset(self::$obj)) { self::$obj = new DataBaseConnector(); return self::$obj; } else { echo "connection object could not be created again" . PHP_EOL; } } } $obj1 = DataBaseConnector::getConnect(); $obj2 = DataBaseConnector::getConnect(); var_dump($obj1 == $obj2); ?>
它将产生以下输出:
DataBaseConnector object created for first time connection object could not be created again bool(false)
工厂模式
这是最常用的设计模式之一。在此模式中,您不会直接声明所需类的对象,而是提供另一个类的静态方法来创建所需的对象。
示例
以下示例演示了工厂设计模式的工作原理——
<?php class Automobile { private $bikeMake; private $bikeModel; public function __construct($make, $model) { $this->bikeMake = $make; $this->bikeModel = $model; } public function getMakeAndModel() { return $this->bikeMake . ' ' . $this->bikeModel; } } class AutomobileFactory { public static function create($make, $model) { return new Automobile($make, $model); } } $pulsar = AutomobileFactory::create('ktm', 'Pulsar'); print_r($pulsar->getMakeAndModel()); ?>
它将产生以下输出:
ktm Pulsar
策略模式
策略模式建议一种方法,在该方法中,您可以封装特定系列的算法,从而允许负责实例化特定算法的客户端类。实现该模式的类不知道实际的实现。
示例
这是一段演示策略模式用法的代码。我们有一个接口,其 case() 方法由两个不同的类以不同的方式实现。testdata 类的对象通过其自身的 process() 方法间接调用相应的 case() 方法。
<?php interface example { public function case($str); } class ucase implements example { public function case($str) { return strtoupper($str); } } class lcase implements example { public function case($str) { return strtolower($str); } } class testdata { private $data; public function __construct($input) { $this->data = $input; } public function process(example $type) { return $this->data = $type->case($this->data); } } $str = "hello"; $obj = new testdata($str); echo $obj->process(new ucase) . PHP_EOL; $str = "HELLO"; echo $obj->process(new lcase); ?>
它将产生以下输出:
HELLO Hello
MVC 设计模式
MVC(代表模型、视图和控制器)是一种非常流行的软件架构模式。大多数 PHP 网络(例如 Laravel、Symfony 等)都实现了 MVC 架构。
应用程序中每一层角色的分离如下——
模型——指的是数据结构。在这种情况下,指的是数据库。
视图——指的是用户界面。HTML 和 CSS。
控制器——进行处理的“中间人”。接受来自视图的输入,并与模型一起工作。不言而喻,PHP 脚本和库本身。
视图充当 GUI,模型充当后端,控制器充当适配器。在这里,三个部分相互连接。它将在彼此之间传递数据和访问数据。
示例
让我们在下面的示例中使用纯PHP、JavaScript和HTML实现MVC设计模式。
应用程序的表示层是view.php,它渲染一个HTML表单。用户将数据提交给控制器脚本。控制器返回的结果通过一些JavaScript在网页上呈现。
view.php
<!DOCTYPE html> <html> <head> <title>View (User Interface)</title> <link rel="stylesheet" href="style.css"> </head> <body> <form id="mysearch" action="controller.php" method="POST"> <input type="text" id = "nm" name="search" required> <input type="submit" value="Search"> </form> <div id="results"></div> <script> let results = document.getElementById("results"); results.innerHTML = ""; </script> <?php session_start(); if (isset($_SESSION['result'])) { $arr=$_SESSION['result']; foreach ($arr as $obj) {?> <script> results.innerHTML += "<div><?php echo $obj['id'] . "-" . $obj['name'] . "</div>"; ?>"; </script> <?php } } ?> </body> </html>
控制器脚本需要model.php,并使用数据库对象,调用select方法从数据库中提取数据。结果存储在当前会话中,以便可以在视图页面访问它。
controller.php
<?php session_start(); require "model.php"; $results = $_DB->select( "SELECT * FROM `users` WHERE `name` LIKE ?", ["%{$_POST["search"]}%"] ); $_SESSION['search'] = $_POST['search']; $_SESSION['result'] = $results; Header("Location: view.php", true); ?>
应用程序的模型层在“model.php”中编码。它使用PDO扩展连接名为mydb的mysql数据库。
model.php
<?php class DB { public $error = ""; private $pdo = null; private $stmt = null; var $dsn="localhost"; var $dbName="myDB"; var $username="root"; var $password=""; function __construct () { $this->pdo = new PDO("mysql:host=$this->dsn;dbname=$this-> dbName",$this->username,$this->password); } function __destruct () { if ($this->stmt!==null) { $this->stmt = null; } if ($this->pdo!==null) { $this->pdo = null; } } function select ($sql, $data=null) { $this->stmt = $this->pdo->prepare($sql); $this->stmt->execute($data); return $this->stmt->fetchAll(); } } $_DB = new DB(); ?>
后端mydb数据库必须有一个包含ID和NAME字段的用户表。
-- Table structure for table `users` -- CREATE TABLE `users` ( `id` bigint(20) NOT NULL, `name` varchar(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; -- -- Dumping data for table `users` -- INSERT INTO `users` (`id`, `name`) VALUES (21, 'Ahmad Shaikh'), (24, 'Akshay Wadkar'), (26, 'Bridget Wooten'), (10, 'Coby Kelleigh'), (20, 'Dashan Shah'), (12, 'Elizabeth Taylor'), (41, 'Issac Newton'), (34, 'Julia Roberts'), (31, 'Junior Mahmood'), (32, 'Kailas Bende'), (47, 'Karan Sharma'), (16, 'Kenneth Sanders'), (28, 'Kirstie Thomas'), (33, 'Lawrence Murphy'), (14, 'Leah Shan'), (51, 'Marcus Best'), (29, 'Maya Pande'), (50, 'Nathaniel Khan'), (6, 'Richard Breann'), (54, 'Rowan Avalos'), (3, 'Rusty Terry'), (37, 'Sacha Gross'), (27, 'Sally Castillo'), (11, 'Sarah Sanders'), (18, 'Seth Sonnel'), (38, 'Shannon Peterson'), (25, 'Shayan Clements'), (49, 'Shoaib Vickers'), (43, 'Simran Kaur'), (35, 'Sulaiman Gilmour'), (44, 'Taran Morin'), (48, 'Taran Morin'), (22, 'Thelma Kim'), (8, 'Tillie Sharalyn'), (36, 'Virgil Collier');
在浏览器中访问“https://127.0.0.1/view.php”启动应用程序。输入与具有所需字母的名称相对应的搜索词。
PHP – 过滤器
在PHP应用程序中处理客户端请求形式接收到的输入数据之前,验证输入数据非常重要。为了执行输入验证,PHP中的过滤器扩展提供了许多过滤器函数,由预定义的过滤器常量和标志支持。PHP库的过滤器扩展还有助于清理通过GET或POST方法接收到的输入。
过滤器扩展是一个强大的功能,有助于防止安全漏洞,例如SQL注入和跨站点脚本。扩展有两种类型的过滤器:
验证过滤器
验证过滤器检查数据是否符合特定条件。例如,您希望确保用户已在HTML表单中正确输入电子邮件字段。FILTER_VALIDATE_EMAIL将确定数据是否为有效的电子邮件地址。但是,验证过滤器不会更改数据本身。
清理过滤器
清理是指从输入中删除不需要的字符的过程。因此,它可能会通过删除不需要的字符来更改数据。例如,传入FILTER_SANITIZE_EMAIL将删除电子邮件地址中不应包含的不合适的字符,而无需执行验证。
过滤器标志
PHP中的过滤器扩展定义了许多过滤器标志,如下所示:
序号 | ID & 描述 |
---|---|
1 | FILTER_FLAG_STRIP_LOW 删除数值<32的字符。 |
2 | FILTER_FLAG_STRIP_HIGH 删除数值>127的字符。 |
3 | FILTER_FLAG_STRIP_BACKTICK 删除反引号字符。 |
4 | FILTER_FLAG_ALLOW_FRACTION 允许使用句点(.)作为数字的小数分隔符。 |
5 | FILTER_FLAG_ALLOW_THOUSAND 允许使用逗号(,)作为数字的千位分隔符。 |
6 | FILTER_FLAG_ALLOW_SCIENTIFIC 允许使用e或E表示数字的科学计数法。 |
7 | FILTER_FLAG_NO_ENCODE_QUOTES 如果存在此标志,则不会编码单引号(')和双引号(")。 |
8 | FILTER_FLAG_ENCODE_LOW 编码所有数值<32的字符。 |
9 | FILTER_FLAG_ENCODE_HIGH 编码所有数值>127的字符。 |
10 | FILTER_FLAG_ENCODE_AMP 编码与符号(&)。 |
11 | FILTER_NULL_ON_FAILURE 对于无法识别的值,返回null。 |
12 | FILTER_FLAG_ALLOW_OCTAL 将以零(0)开头的输入视为八进制数。 |
13 | FILTER_FLAG_ALLOW_HEX 将以0x或0X开头的输入视为十六进制数。 |
14 | FILTER_FLAG_EMAIL_UNICODE 允许电子邮件地址的本地部分包含Unicode字符。 |
15 | FILTER_FLAG_IPV4 允许IP地址为IPv4格式。 |
16 | FILTER_FLAG_IPV6 允许IP地址为IPv6格式。 |
17 | FILTER_FLAG_NO_PRIV_RANGE 对于以下专用IPv4范围,验证失败:10.0.0.0/8、172.16.0.0/12和192.168.0.0/16。 |
18 | FILTER_FLAG_NO_RES_RANGE 对于以下保留的IPv4范围,验证失败:0.0.0.0/8、169.254.0.0/16、127.0.0.0/8和240.0.0.0/4。 对于以下保留的IPv6范围,验证失败:::1/128、::/128、::ffff:0:0/96和fe80::/10。 |
19 | FILTER_FLAG_GLOBAL_RANGE 对于非全局IPv4/IPv6范围,验证失败。 |
20 | FILTER_FLAG_SCHEME_REQUIRED 要求URL包含方案部分。 |
21 | FILTER_FLAG_HOST_REQUIRED 要求URL包含主机部分。 |
22 | FILTER_FLAG_PATH_REQUIRED 要求URL包含路径部分。 |
23 | FILTER_FLAG_QUERY_REQUIRED 要求URL包含查询字符串。 |
24 | FILTER_REQUIRE_SCALAR 要求值为标量。 |
25 | FILTER_REQUIRE_ARRAY 要求值为数组。 |
26 | FILTER_FORCE_ARRAY 如果值为标量,则将其视为只有一个标量值作为元素的数组。 |
过滤器函数
过滤器扩展包含以下过滤器函数:
序号 | ID & 描述 |
---|---|
1 | filter_has_var() 检查指定类型的变量是否存在 |
2 | filter_id() 返回属于命名过滤器的过滤器ID |
3 | filter_input_array() 获取外部变量并对其进行可选过滤 |
4 | filter_input () 按名称获取特定的外部变量并对其进行过滤 |
5 | filter_list() 返回所有支持的过滤器的列表 |
6 | filter_var_array() 获取多个变量并对其进行可选过滤 |
7 | filter_var() 使用指定的过滤器过滤变量 |
预定义常量
上述函数使用一个名为input_type的参数,它是预定义的枚举常量之一,表示输入是如何为过滤目的提供给PHP脚本的。
常量 | 类型 |
---|---|
INPUT_POST (int) | POST变量 |
INPUT_GET (int) | GET变量 |
INPUT_COOKIE (int) | COOKIE变量 |
INPUT_ENV (int) | ENV变量 |
INPUT_SERVER (int) | SERVER变量 |
INPUT_SESSION (int) | SESSION变量 |
INPUT_REQUEST (int) | REQUEST变量 |
filter_has_var()函数
filter_has_var()函数检查指定类型的变量是否存在。
filter_has_var(int $input_type, string $var_name): bool
input_type是预定义常量INPUT_GET、INPUT_POST、INPUT_COOKIE、INPUT_SERVER或INPUT_ENV之一;而var_name参数是要检查的变量的名称。函数在成功时返回true,失败时返回false。
示例
访问XAMPP服务器上的以下PHP脚本。
<?php if (!filter_has_var(INPUT_GET, "email")) { echo("Email not found"); } else { echo("Email found"); } ?>
它将产生以下输出:
访问https://127.0.0.1/[email protected]
Email found
filter_input()函数
filter_input()函数获取特定外部变量的名称并根据应用的过滤器常量对其进行过滤。
filter_input( int $type, string $var_name, int $filter = FILTER_DEFAULT, array|int $options = 0 ): mixed
type参数是常量INPUT_GET、INPUT_POST、INPUT_COOKIE、INPUT_SERVER或INPUT_ENV之一。第二个参数是var_name,要获取的变量的名称。您可以使用要应用的过滤器。使用任何预定义的过滤器标志。如果省略,将使用FILTER_DEFAULT。
函数在成功时返回请求变量的值,如果过滤器失败则返回false,如果var_name变量未设置则返回null。
示例
请看以下示例:
<?php if (!filter_input(INPUT_GET, "email", FILTER_VALIDATE_EMAIL)) { echo("Email is not valid"); } else { echo("Email is valid"); } ?>
它将产生以下输出:
如果您使用URLhttps://127.0.0.1/[email protected],
Email is valid
如果URL是https://127.0.0.1/hello.php?email=a b [email protected],
Email is not valid
您还可以使用INPUT_POST类型来验证通过POST方法接收到的输入:
<?php if (!filter_input(INPUT_POST, "email", FILTER_VALIDATE_EMAIL)) { echo("Email is not valid"); } else { echo("Email is valid"); } ?>
要使用POST请求传递数据,请打开命令提示符,并使用以下CURL命令
curl -X POST -d "{\"email\": \"[email protected]\"}" https://127.0.0.1/hello.php
filter_list()函数
filter_list()函数返回所有支持的过滤器的列表。
filter_list(): array
示例
该函数返回所有支持的过滤器的名称数组,如果没有此类过滤器,则返回空数组。
<?php print_r(filter_list()); ?>
它将产生以下输出:
Array ( [0] => int [1] => boolean [2] => float [3] => validate_regexp [4] => validate_domain [5] => validate_url [6] => validate_email [7] => validate_ip [8] => validate_mac [9] => string [10] => stripped [11] => encoded [12] => special_chars [13] => full_special_chars [14] => unsafe_raw [15] => email [16] => url [17] => number_int [18] => number_float [19] => add_slashes [20] => callback )
filter_input_array()函数
filter_input_array()获取外部变量并对其进行可选过滤。
filter_input_array(int $type, array|int $options = FILTER_DEFAULT, bool $add_empty = true): array|false|null
此函数可用于检索许多值,而无需重复调用filter_input()。
type参数是INPUT_GET、INPUT_POST、INPUT_COOKIE、INPUT_SERVER或INPUT_ENV之一。
options参数是一个定义参数的数组。有效的键是包含变量名的字符串,有效的值是过滤器类型,或者是一个可选地指定过滤器、标志和选项的数组。此参数也可以是一个包含过滤器常量的整数。然后,输入数组中的所有值都将通过此过滤器进行过滤。
该函数在成功时返回一个包含请求变量值的数组。如果type指定的输入数组未填充,则如果未给出FILTER_NULL_ON_FAILURE标志,则函数返回null,否则返回false。对于其他错误,返回false。
示例
要在HTTP请求中包含数组,我们在“hello.html”中使用以下HTML表单,并通过POST方法发送。
<!DOCTYPE html> <html> <body> <h1>Filter Input Array</h1> <form action="hello.php" method="POST"> <p><label for="email">Enter your email:</label> <input type="text" id="email" name="email"></p> <p><label for="age">Enter your age<label> <input type = "text" id="age" name="age"></p> <input type="submit"> </form> </body> </html>
验证输入数组的PHP脚本如下:
<?php $filters = array ( "age" => array ("filter"=>FILTER_VALIDATE_INT, "options"=>array("min_range"=>20,"max_range"=>40) ), "email" => FILTER_VALIDATE_EMAIL ); print_r(filter_input_array(INPUT_POST, $filters)); ?>
打开HTML表单并输入30作为年龄,[email protected]作为电子邮件,结果将是一个数组,验证这两个输入:
Array ( [age] => 30 [email] => [email protected] )
尝试输入无效的输入,例如“age=15”。输出数组将显示age键的空值。
Array ( [age] => [email] => [email protected] )
PHP – JSON
PHP的标准发行版默认情况下启用了JSON支持。PHP扩展实现了JavaScript对象表示法(JSON)数据交换格式。PHP解析器中的JSON扩展处理JSON数据。
JSON(JavaScript对象表示法)是一种轻量级、基于文本的、与语言无关的数据交换格式。JSON定义了一小组用于结构化数据的可移植表示的格式规则。它是一种基于文本的数据格式,易于人和机器读取。
PHP 5.2及更高版本中的JSON扩展提供了一些预定义常量、JSON相关函数以及JsonException类。
PHP JSON函数
PHP具有以下JSON函数:
json_encode()
此函数返回一个包含提供的值的JSON表示的字符串。如果参数是数组或对象,它将被递归地序列化。
json_encode(mixed $value, int $flags = 0, int $depth = 512): string|false
json_decode()
此函数获取JSON编码的字符串并将其转换为PHP值。
json_decode( string $json, ?bool $associative = null, int $depth = 512, int $flags = 0 ): mixed
当此函数的关联参数为true时,JSON对象将作为关联数组返回;当为false时,JSON对象将作为对象返回。
编码/解码操作受提供的标志影响。预定义常量及其整数值如下:
预定义常量 | 值 |
---|---|
JSON_HEX_TAG | 1 |
JSON_HEX_AMP | 2 |
JSON_HEX_APOS | 4 |
JSON_HEX_QUOT | 8 |
JSON_FORCE_OBJECT | 16 |
JSON_NUMERIC_CHECK | 32 |
JSON_UNESCAPED_SLASHES | 64 |
JSON_PRETTY_PRINT | 128 |
JSON_UNESCAPED_UNICODE | 256 |
json_last_error_msg()
此函数返回上次json_encode()或json_decode()调用的错误字符串。
json_last_error_msg(): string
如果没有发生错误,则返回“无错误”消息。
json_last_error()
此函数返回一个整数。
json_last_error(): int
该函数返回一个整数,对应于以下常量之一:
序号 | 常量与含义 |
---|---|
1 | JSON_ERROR_NONE 未发生错误 |
2 | JSON_ERROR_DEPTH 已超出最大堆栈深度 |
3 | JSON_ERROR_STATE_MISMATCH 无效或格式错误的JSON |
4 | JSON_ERROR_CTRL_CHAR 控制字符错误,可能编码不正确 |
5 | JSON_ERROR_SYNTAX 语法错误 |
6 | JSON_ERROR_UTF8 格式错误的UTF-8字符,可能编码不正确 |
7 | JSON_ERROR_RECURSION 待编码值中存在一个或多个递归引用 |
8 | JSON_ERROR_INF_OR_NAN 待编码值中存在一个或多个NAN或INF值 |
9 | JSON_ERROR_UNSUPPORTED_TYPE
给定了一个无法编码的类型的值 |
10 | JSON_ERROR_INVALID_PROPERTY_NAME 给定了一个无法编码的属性名 |
11 | JSON_ERROR_UTF16 UTF-16 字符格式错误,可能编码错误 |
示例
下面的 PHP 代码将给定的数组编码为 JSON 表示形式,并将 JSON 字符串解码回 PHP 数组。
<?php $arr = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5); $encoded = json_encode($arr); echo "The initial array: " . PHP_EOL; var_dump($arr); echo "Encoded JSON: $encoded" . PHP_EOL; $decoded = json_decode($encoded); echo "Array obtained after decoding: " . PHP_EOL; var_dump($decoded); ?>
它将产生以下输出:
The initial array: array(5) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) ["d"]=> int(4) ["e"]=> int(5) } Encoded JSON: {"a":1,"b":2,"c":3,"d":4,"e":5} Array obtained after decoding: object(stdClass)#1 (5) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) ["d"]=> int(4) ["e"]=> int(5) }
PHP – 异常
在 PHP 7 之前,PHP 解析器用于响应各种条件报告错误。每个错误都属于某种预定义类型。PHP 7 改变了错误报告机制。大多数错误不再通过传统的错误报告方式报告,而是通过抛出异常来报告。
PHP 中的异常处理机制与许多其他语言类似,并使用try、catch、throw和finally关键字实现。
Throwable 接口
PHP 中的异常实现了Throwable 接口。Throwable 接口作为任何可以通过 throw 语句抛出的对象的基类,包括 Error 和 Exception 对象。
用户定义的类不能直接实现 Throwable 接口。相反,要声明用户定义的异常类,必须扩展Exception 类。
包含潜在异常的 PHP 代码被包围在一个try块中。如果发现异常,则会抛出一个异常对象,以便捕获潜在的异常。每个try块必须至少对应一个catch或finally块。此外,可能有多个 catch/finally 块对应于一个try块。
try { // throw errors in the try-block // if an error occurs we can throw an exception throw new Exception('this is an error.'); } catch(Exception $e) { // catch the throws in the catch-block // do something with the exception object, eg. // display its message echo 'Error message: ' .$e->getMessage(); }
如果抛出异常且没有catch块,则异常将“冒泡”直到找到匹配的catch块。如果调用堆栈一直展开到全局范围而没有遇到匹配的 catch 块,则将调用全局异常处理程序(如果已设置),否则程序将以致命错误终止。
set_exception_handler
如果异常未在 try/catch 块中捕获,此函数将设置默认的异常处理程序。回调执行后,程序执行将停止。
set_exception_handler(?callable $callback): ?callable
$callback 参数是要在发生未捕获异常时调用的函数的名称。必须在调用 set_exception_handler() 之前定义此函数。此处理程序函数需要接受一个参数,该参数将是抛出的异常对象。
该函数返回先前定义的异常处理程序的名称,或错误时返回 NULL。如果未定义先前的处理程序,则也返回 NULL。
示例
请看以下示例:
<?php function handler($ex) { echo "Uncaught exception is : " , $ex->getMessage(), "\n"; } set_exception_handler('handler'); throw new Exception('Not Found Exception'); echo "not included Executed\n"; ?>
它将产生以下输出:
Uncaught exception is : Not Found Exception
SPL 异常
标准 PHP 库包含预定义的异常:
序号 | 预定义异常 |
---|---|
1 | LogicException 表示程序逻辑错误的异常。 |
2 | BadFunctionCallException 如果回调引用未定义的函数或缺少某些参数,则抛出此异常。 |
3 | BadMethodCallException 如果回调引用未定义的方法或缺少某些参数,则抛出此异常。 |
4 | DomainException 如果值不符合定义的有效数据域,则抛出此异常。 |
5 | InvalidArgumentException 如果参数不是预期类型,则抛出此异常。 |
6 | LengthException 如果长度无效,则抛出此异常。 |
7 | OutOfRangeException 请求非法索引时抛出此异常。 |
8 | RuntimeException 如果发生只能在运行时发现的错误,则抛出此异常。 |
9 | OutOfBoundsException 如果值不是有效的键,则抛出此异常。 |
10 | OverflowException 向已满容器添加元素时抛出此异常。 |
11 | RangeException 抛出此异常以指示程序执行期间的范围错误。除下溢/上溢之外的算术错误。 |
12 | UnderflowException 对空容器执行无效操作(例如删除元素)时抛出此异常。 |
13 | UnexpectedValueException 如果值与一组值不匹配,则抛出此异常。 |
用户定义的异常
您可以定义一个扩展基 Exception 类的自定义异常类。以下脚本定义了一个名为 myException 的自定义异常类。如果 $num 的值小于 0 或大于 100,则会抛出此类型的异常。
示例
Exception 类的 getMessage() 方法返回错误消息,getLine() 方法返回出现异常的代码行。
<?php class myException extends Exception { function message() { return "error : ". $this->getMessage(). "in line no". $this->getLine(); } } $num=125; try { if ($num>100 || $num<0) throw new myException("$num is invalid number"); else echo "$num is a valid number"; } catch (myException $m) { echo $m->message(); } ?>
使用$num=125和$num=90运行上述代码以获取错误消息和有效数字的消息:
error : 125 is invalid number in line no 10
PHP – 特殊类型
PHP 的两种数据类型——resource和NULL——被归类为特殊类型。resource 类型对象引用外部资源,例如数据库连接、文件流等。另一方面,NULL 数据类型是一个没有任何数据分配给它的变量。本章,我们将学习更多关于这些类型的知识。
资源类型
PHP 程序通常需要与外部环境(例如数据库或磁盘文件等)交互。这些在 PHP 中被视为资源。资源是一种特殊的数据类型,它引用任何此类外部资源。PHP 使用相关函数创建这些资源。例如,fopen() 函数打开一个磁盘文件,其引用存储在一个资源变量中。
PHP 的 Zend 引擎使用引用计数系统。因此,引用计数为零的资源将由垃圾收集器自动销毁,并且不需要手动释放资源数据类型使用的内存。
不同的内置 PHP 函数返回各自的资源变量。随后,PHP 使用它们与相应的外部环境交互。例如,fopen() 函数返回一个文件资源,它充当文件句柄,并且通过此资源变量来促进文件的读/写操作。
下表总结了返回资源变量的不同函数:
资源类型 | 内置函数 | 定义 | |
---|---|---|---|
已生成 | 已售出 | ||
bzip2 | bzopen() | bzclose() | Bzip2 文件 |
curl | curl_init() | curl_close() | Curl 会话 |
ftp | ftp_connect(), | ftp_close() | FTP 流 |
mssql 连接 | mssql_connect() | mssql_close() | 到 Microsoft SQL Server 数据库的连接 |
mysql 连接 | mysql_connect() | mysql_close() | 到 MySQL 数据库的连接 |
mysql 结果 | mysql_db_query(), | mysql_free_result() | MySQL 结果 |
oci8 连接 | oci_connect() | oci_close() | 到 Oracle 数据库的连接 |
ODBC 连接 | odbc_connect() | odbc_close() | 到 ODBC 数据库的连接 |
pdf 文档 | pdf_new() | pdf_close() | PDF 文档 |
流 | opendir() | closedir() | 目录句柄 |
流 | fopen(), tmpfile() | fclose() | 文件句柄 |
套接字 | socket_create() | Socket_close() | 套接字句柄 |
xml | xml_parser_create() | xml_parser_free() | XML 解析器 |
zlib | gzopen() | gzclose() | gz 压缩文件 |
zlib.deflate | deflate_init() | None() | 增量解压缩上下文 |
zlib.inflate | inflate_init() | None() | 增量压缩上下文 |
PHP 有 get_resource_type() 函数,它返回变量的资源类型。
get_resource_type ( resource $handle ) : string
其中 $handle 是要获取其类型的资源变量。此函数返回与资源类型对应的字符串。
还有一个 get_resource_id() 函数,它为给定的资源提供一个整数标识符。
get_resource_id(resource $resource): int
示例
此函数提供了一种类型安全的方式来为给定的资源生成整数标识符。
<?php $fp = fopen("hello.php", "r"); $resource = get_resource_type($fp); $id = get_resource_id($fp); echo "The resource type is : $resource The resource ID is : $id"; ?>
它将产生以下输出:
The resource type is : stream The resource ID is : 5
NULL 类型
在 PHP 中,没有值的变量被称为 null 数据类型。此类变量的值定义为 NULL。可以使用 unset() 函数将变量显式赋值为 NULL 或将其值设置为 null。
$var=NULL;
可以将其他类型的变量转换为 null,尽管从 PHP 7.2 开始已弃用将 null 转换为其他类型。在早期版本中,转换是使用 (unset)$var 语法完成的。
示例
以下示例显示如何将 NULL 分配给变量
<?php $var=NULL; var_dump($var); ?>
它将产生以下输出:
NULL
示例
以下示例将 null 变量转换为其他主要变量:
<?php $var = NULL; var_dump( (int) $var); var_dump((float)$var); var_dump((bool) $var) ; var_dump( (boolean) $var); ?>
它将产生以下输出:
int(0) float(0) bool(false) bool(false)
PHP – 哈希
术语“哈希”表示加密数据(特别是文本)以获得固定长度值的技术。PHP 库包含许多函数,这些函数可以通过应用不同的哈希算法(例如 md5、SHA2、HMAC 等)对数据执行哈希运算。获得的加密值称为原始密钥的哈希值。
哈希处理是一个单向过程,这意味着不可能反转哈希以获得原始密钥。
哈希的应用
哈希技术有效地用于以下目的:
密码认证
我们经常注册各种在线应用程序,例如 gmail、Facebook 等。您需要填写一个表单,在其中为在线帐户创建密码。服务器会对您的密码进行哈希处理,并将哈希值存储在数据库中。登录时,提交的密码将被哈希处理并与数据库中的密码进行比较。这可以保护您的密码不被盗。
数据完整性
哈希的一个重要用途是验证数据是否未被篡改。当从互联网下载文件时,会显示其哈希值,您可以将其与下载的文件进行比较,以确保文件未损坏。
哈希过程
哈希过程可以用下图表示:
PHP 中的哈希算法
PHP 支持多种哈希算法:
MD5 – MD5 是一种 128 位哈希函数,广泛用于软件中以验证传输文件的完整性。128 位哈希值通常表示为 32 位十六进制数字。例如,单词“frog”始终生成哈希“8b1a9953c4611296a827abf8c47804d7”
SHA – SHA 代表安全哈希算法。它是美国国家标准与技术研究院 (NIST) 制定的标准系列。SHA 是 MD5 的修改版本,用于对数据和证书进行哈希处理。SHA-1 和 SHA-2 是该算法的两个不同版本。SHA-1 是一个 160 位哈希值。SHA-2 实际上是一个“系列”哈希值,并且具有各种长度,最常用的是 256 位。
HMAC – HMAC(基于哈希的消息验证码)是一种加密身份验证技术,它使用哈希函数和密钥。
HKDF – HKDF 是一种基于 HMAC 消息验证码的简单密钥派生函数 (KDF)。
PBKDF2 – PBKDF2(基于密码的密钥派生函数 2)是一种哈希算法,它从密码创建加密密钥。
PHP 中的哈希函数
PHP 库包含多个哈希函数:
hash_algos 函数
此函数返回一个数值索引数组,其中包含受支持的哈希算法列表。
hash_algos(): array
hash_file 函数
该函数返回一个字符串,其中包含计算出的消息摘要(小写十六进制)。
hash_file( string $algo, string $filename, bool $binary = false, array $options = [] ): string|false
algo 参数是所选哈希算法的类型(例如,“md5”、“sha256”、“haval160,4”等)。filename 是描述要哈希文件的 URL;支持 fopen 包装器。
示例
请看以下示例:
<?php /* Create a file to calculate hash of */ $fp=fopen("Hello.txt", "w"); $bytes = fputs($fp, "The quick brown fox jumped over the lazy dog."); fclose($fp); echo hash_file('md5', "Hello.txt"); ?>
它将产生以下输出:
5c6ffbdd40d9556b73a21e63c3e0e904
hash() 函数
hash() 函数生成哈希值(消息摘要)−
hash( string $algo, string $data, bool $binary = false, array $options = [] ): string
algo 参数是所选哈希算法的类型(例如,“md5”、“sha256”、“haval160,4”等)。data 参数是要哈希的消息。如果 binary 参数为“true”,则输出原始二进制数据;“false”输出小写十六进制。
示例
该函数返回一个字符串,其中包含计算出的消息摘要(小写十六进制)。
<?php echo "Using SHA256 algorithm:" . hash('sha256', 'The quick brown fox jumped over the lazy dog.'). PHP_EOL; echo "Using MD5 algorithm:",hash('md5', 'The quick brown fox jumped over the lazy dog.'), PHP_EOL; echo "Using SHA1 algorithm:" . hash('sha1', 'The quick brown fox jumped over the lazy dog.'); ?>
它将产生以下输出:
Using SHA256 algorithm:68b1282b91de2c054c36629cb8dd447f12f096d3e3c587978dc2248444633483 Using MD5 algorithm:5c6ffbdd40d9556b73a21e63c3e0e904 Using SHA1 algorithm:c0854fb9fb03c41cce3802cb0d220529e6eef94e
PHP – 加密
早期版本的 PHP 包含 mcrypt 扩展,该扩展提供加密/解密功能。由于缺乏维护,mcrypt 扩展已弃用,并从 PHP 7.2 版本开始移除。PHP 现在包含 OpenSSL 库,该库具有广泛的功能来支持加密和解密功能。
OpenSSL 支持各种加密算法,例如 AES(高级加密标准)。所有受支持的算法都可以通过调用 openssl_get_cipher_methods() 函数获得。
OpenSSL 扩展中的两个重要函数是 −
openssl_encrypt() − 加密数据
openssl_decrypt() − 解密数据
openssl_encrypt() 函数
此函数使用给定的方法和密钥加密给定的数据,并返回原始或 base64 编码的字符串 −
openssl_encrypt( string $data, string $cipher_algo, string $passphrase, int $options = 0, string $iv = "", string &$tag = null, string $aad = "", int $tag_length = 16 ): string|false
该函数具有以下参数 −
序号 | 参数 & 说明 |
---|---|
1 | data 要加密的明文消息数据。 |
2 | cipher_algo 密码方法。 |
3 | passphrase 密码短语。如果密码短语短于预期,则用 NULL 字符填充;如果密码短语长于预期,则将其截断。 |
4 | options options 是标志 OPENSSL_RAW_DATA 和 OPENSSL_ZERO_PADDING 的按位析取。 |
5 | iv 非 NULL 初始化向量。 |
6 | tag 使用 AEAD 密码模式(GCM 或 CCM)时按引用传递的身份验证标记。 |
7 | aad 附加身份验证数据。 |
8 | tag_length 身份验证标记的长度。对于 GCM 模式,其值可以在 4 到 16 之间。 |
函数在成功时返回加密的字符串,在失败时返回false。
openssl_decrypt() 函数
此函数获取原始或 base64 编码的字符串,并使用给定的方法和密钥对其进行解密。
openssl_decrypt( string $data, string $cipher_algo, string $passphrase, int $options = 0, string $iv = "", ?string $tag = null, string $aad = "" ): string|false
openssl_decrypt() 函数使用与openssl_encrypt 函数相同的参数。
此函数在成功时返回解密的字符串,在失败时返回 false。
示例
请看以下示例:
<?php function sslencrypt($source, $algo, $key, $opt, $iv) { $encstring = openssl_encrypt($source, $algo, $key, $opt, $iv); return $encstring; } function ssldecrypt($encstring, $algo, $key, $opt, $iv) { $decrstring = openssl_decrypt($encstring, $algo, $key, $opt, $iv); return $decrstring; } // string to be encrypted $source = "PHP: Hypertext Preprocessor"; // Display the original string echo "Before encryption: " . $source . "\n"; $algo = "BF-CBC"; $opt=0; $ivlength = openssl_cipher_iv_length($algo); $iv = random_bytes($ivlength); $key = "abcABC123!@#"; // Encryption process $encstring = sslencrypt($source, $algo, $key, $opt, $iv); // Display the encrypted string echo "Encrypted String: " . $encstring . "\n"; // Decryption process $decrstring = ssldecrypt($encstring, $algo, $key, $opt, $iv); // Display the decrypted string echo "Decrypted String: " . $decrstring; ?>
它将产生以下输出:
Before encryption: PHP: Hypertext Preprocessor Encrypted String: Decrypted String:
PHP is_null() 函数
PHP 将 NULL 定义为其特殊数据类型之一。它表示某个变量尚未分配任何特定数据类型的值。它是 PHP 中的内置常量,用于指示故意缺少任何对象或值。可以使用unset() 函数将变量显式分配为 NULL 或将其值设置为 null。
is_null() 函数
PHP 提供了一个布尔函数is_null() 来检查变量是否确实是 NULL 类型。
is_null(mixed $value): bool
示例 1
如果任何变量都显式分配了 NULL,则is_null() 函数显然返回true。
<?php $x = NULL; echo "Variable \$x is null? "; var_dump(is_null($x)); ?>
它将产生以下输出:
Variable $x is null? bool(true)
示例 2
如果取消设置具有某个值的变量,则 is_null() 函数也会返回 true,但会发出警告
<?php $x = "Hello"; unset($x); echo "Variable \$x is null?\n"; var_dump(is_null($x)); ?>
它将产生以下输出:
Variable $x is null? bool(true) PHP Warning: Undefined variable $x in /home/cg/root/89262/main.php on line 5
示例 3
同样,如果您只是声明一个变量,而没有为其赋值,则 is_null() 函数会返回true 并发出警告 −
<?php $y; echo "Variable \$y is null?\n"; var_dump(is_null($y)); ?>
它将产生以下输出:
Variable $y is null? bool(true) Warning: Undefined variable $y in hello.php on line 9
示例 4
您还可以使用等号运算符 (==) 来检查变量是否为 NULL。
<?php $x = NULL; if ($x === NULL) { echo '$x is NULL'; } else { echo '$x is not NULL'; } ?>
它将产生以下输出:
$x is NULL
示例 5
空字符串 "" 不被认为等于 NULL。因此,is_null() 函数以及 "==" 运算符都返回false。请看下面的示例 −
<?php $y = ""; if ($y === NULL) { echo '$y is NULL'; } else { echo '$y is not NULL'; } echo "$y is null?\n"; var_dump(is_null($y)); ?>
它将产生以下输出:
$y is not NULL is null? bool(false)
PHP 中与 is_null() 函数相关的另外两个函数是isset() 函数和empty() 函数。
isset() 函数
isset() 函数确定变量是否已声明且不同于 NULL。
isset(mixed $var, mixed ...$vars): bool
示例
分配为 NULL 的变量被认为是未设置的。
<?php $x = NULL; echo '$x is set? '; var_dump(isset($x)); ?>
它将产生以下输出:
$x is set? bool(false)
请注意,空字符 ("\0") 不等效于 PHP 空常量。
empty() 函数
empty() 函数检查变量是否被认为为空。如果变量不存在或其值为 NULL,则该变量被认为为空。如果变量不存在,empty() 不会生成警告。
示例 1
请看以下示例:
<?php $x = NULL; echo '$x is empty? '; var_dump(empty($x)); $y; echo '$y is empty? '; var_dump(empty($y)); ?>
它将产生以下输出:
$x is empty? bool(true) $y is empty? bool(true)
示例 2
如果变量设置为“0”、“NULL”或根本未设置,则 empty() 函数返回true。
<?php $var = 0; if (empty($var)) { echo '$var is either 0, empty, or not set at all'; } ?>
它将产生以下输出:
$var is either 0, empty, or not set at all
PHP – 系统调用
PHP 的内置函数库包括一类函数,这些函数处理从 PHP 代码内部调用操作系统实用程序和外部程序。在本章中,我们将讨论用于执行系统调用的 PHP 函数。
system() 函数
system() 函数类似于 C 中的 system() 函数,它执行给定的命令并输出结果。
system(string $command, int &$result_code = null): string|false
如果 PHP 作为服务器模块运行,则 system() 调用会尝试在每一行输出后自动刷新 Web 服务器的输出缓冲区。它在成功时返回命令输出的最后一行,在失败时返回 false。
示例
以下 PHP 代码段调用 Windows 操作系统的 DIR 命令,并显示当前目录中的文件列表。
<?php echo '<pre>'; // Outputs all the result of DOS command "dir", and returns // the last output line into $last_line. Stores the return value // of the shell command in $retval. $last_line = system('dir/w', $retval); // Printing additional info echo ' </pre> <hr />Last line of the output: ' . $last_line . ' <hr />Return value: ' . $retval; ?>
它将产生以下输出:
Volume in drive C has no label. Volume Serial Number is 7EE4-E492 Directory of C:\xampp\htdocs [.] [..] applications.html bitnami.css [dashboard] employee.csv favicon.ico hello.csv hello.html hello.php homepage.php [img] index.php [Langi] menu.php myform.php myname.php new.png new.txt test.php test.zip [TPcodes] uploadfile.php [webalizer] welcome.png [xampp] 18 File(s) 123,694 bytes 8 Dir(s) 168,514,232,320 bytes free Last line of the output: 8 Dir(s) 168,514,232,320 bytes free Return value: 0
shell_exec() 函数
shell_exec() 函数与 PHP 的反引号运算符相同。它通过 shell 执行给定的命令并将完整的输出作为字符串返回
shell_exec(string $command): string|false|null
该函数返回一个包含已执行命令输出的字符串,如果无法建立管道则返回 false,如果发生错误或命令没有产生输出则返回 null。
示例
在下面的代码中,我们使用 shell_exec() 函数获取当前目录中扩展名为“.php”的文件列表 −
<?php $output = shell_exec('dir *.php'); echo "<pre>$output</pre>"; ?>
它将产生以下输出:
Volume in drive C has no label. Volume Serial Number is 7EE4-E492 Directory of C:\xampp\htdocs 10/26/2023 08:27 PM 73 hello.php 10/12/2023 10:40 AM 61 homepage.php 07/16/2015 09:02 PM 260 index.php 10/12/2023 10:39 AM 49 menu.php 09/25/2023 01:43 PM 338 myform.php 10/12/2023 10:49 AM 51 myname.php 10/26/2023 02:00 PM 369 test.php 09/25/2023 01:42 PM 555 uploadfile.php 8 File(s) 1,756 bytes 0 Dir(s) 168,517,771,264 bytes free
exec() 函数
exec() 函数将给定的命令作为字符串参数执行。
exec(string $command, array &$output = null, int &$result_code = null):string|false
如果指定了$output 参数,则它是一个数组,其中将填充来自命令的每一行输出。
示例
在这种情况下,我们使用 exec() 函数从程序内部调用 whoami 命令。whoami 命令返回用户名。
<?php // outputs the username that owns the running php/httpd process // (on a system with the "whoami" executable in the path) $output=null; $retval=null; exec('whoami', $output, $retval); echo "Returned with status $retval and output:\n"; var_dump($output); ?>
它将产生以下输出:
Returned with status 0 and output: array(1) { [0]=> string(13) "gnvbgl3\mlath" }
passthru() 函数
passthru() 函数执行外部程序并显示原始输出。尽管 passthru() 函数与 exec() 或 system() 函数类似,因为它执行命令,但在 OS 命令的输出是需要直接传递回浏览器的二进制数据时,应使用它来代替它们。
示例
一个使用 passthu() 函数显示系统 PATH 环境变量内容的 PHP 程序
passthru(string $command, int &$result_code = null): ?false <?php passthru ('PATH'); ?>
它将产生以下输出:
PATH=C:\Python311\Scripts\;C:\Python311\;C:\WINDOWS\system32;C:\WINDOWS; C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\; C:\WINDOWS\System32\OpenSSH\;C:\xampp\php;C:\Users\mlath\AppData\Local \Microsoft\WindowsApps;C:\VSCode\Microsoft VS Code\bin
反引号运算符
PHP 支持一个执行运算符:反引号 (``)。(它们不是单引号!)PHP 将尝试将反引号的内容作为 shell 命令执行;将返回输出。反引号运算符的使用与 shell_exec() 相同。
示例
请看以下示例:
<?php $output = `dir *.php`; echo "<pre>$output</pre>"; ?>
它将产生以下输出:
Volume in drive C has no label. Volume Serial Number is 7EE4-E492 Directory of C:\xampp\htdocs 10/26/2023 08:42 PM 61 hello.php 10/12/2023 10:40 AM 61 homepage.php 07/16/2015 09:02 PM 260 index.php 10/12/2023 10:39 AM 49 menu.php 09/25/2023 01:43 PM 338 myform.php 10/12/2023 10:49 AM 51 myname.php 10/26/2023 02:00 PM 369 test.php 09/25/2023 01:42 PM 555 uploadfile.php 8 File(s) 1,744 bytes 0 Dir(s) 168,471,289,856 bytes free
当shell_exec() 被禁用时,反引号运算符也被禁用。
PHP – HTTP 身份验证
在 PHP 中,header() 函数用于向客户端浏览器发送“需要身份验证”消息,从而使其弹出用户名/密码输入窗口。事实上,header() 允许您发送任何原始 HTTP 标头。
header(string $header, bool $replace = true, int $response_code = 0): void
字符串参数传递给 header() 函数。例如
header("HTTP/1.1 404 Not Found");
它用于确定要发送的 HTTP 状态代码。
您还可以使用 header() 函数将浏览器重定向到另一个 URL。
用户填写用户名和密码后,将再次调用包含 PHP 脚本的 URL,并将预定义变量 PHP_AUTH_USER、PHP_AUTH_PW 和 AUTH_TYPE 分别设置为用户名、密码和身份验证类型。这些预定义变量位于 $_SERVER 数组中。仅支持“Basic”和“Digest”身份验证方法。
<?php /* Redirect browser */ header("Location: http://www.example.com/"); /* Make sure that code below does not get executed when we redirect. */ exit; ?>
可选的 replace 参数指示标头是否应替换之前的类似标头,或者添加第二个相同类型的标头,response_code 参数将 HTTP 响应代码强制为指定的值。
为了能够强制客户端身份验证,您需要在文档根目录文件夹中有一个 .htaccess 文件。打开一个新的文本文件,将以下文本放入其中,并将其保存为 .htaccess。
CGIPassAuth On
示例
一个强制客户端在页面上进行身份验证的示例脚本片段如下所示 −
<?php if (!isset($_SERVER['PHP_AUTH_USER'])) { header('WWW-Authenticate: Basic realm="My Realm"'); header('HTTP/1.0 401 Unauthorized'); echo 'User hits Cancel button';7 exit; } else { echo "<p>Hello {$_SERVER['PHP_AUTH_USER']}.</p>"; echo "<p>You entered {$_SERVER['PHP_AUTH_PW']} as your password.</p>"; } ?>
输出
当您在浏览器中访问脚本时,它会弹出一个对话框,如下所示 −
单击登录按钮后,可能会有一个后端脚本来验证登录凭据。验证通过后,将创建两个服务器变量,其键为 PHP_AUTH_USER 和 PHP_AUTH_PW,可以使用 phpinfo() 函数的输出进行验证。
PHP – 交换变量
PHP 没有提供任何内置函数可以交换或互换两个变量的值。但是,有一些技术可以用来执行交换。
最直接的方法之一是使用第三个变量作为临时占位符来促进交换。以特定顺序使用算术运算符也很有效。您还可以使用二进制 XOR 运算符进行交换。在本章中,我们将用 PHP 实现这些交换技术
临时变量
从逻辑上讲,这是最明显也是最简单的方法。要交换“a”和“b”的值,请使用第三个变量“c”。将“a”的值赋给“c”,用“b”的现有值覆盖“a”,然后将“b”设置为存储在“c”中的“a”的先前值。
示例
请看以下示例:
<?php $a = 10; $b = 20; echo "Before swapping - \$a = $a, \$b = $b". PHP_EOL; $c = $a; $a = $b; $b = $c; echo "After swapping - \$a = $a, \$b = $b". PHP_EOL; ?>
它将产生以下输出:
Before swapping - $a = 10, $b = 20 After swapping - $a = 20, $b = 10
使用加法 (+) 运算符
此解决方案利用了从两个数字的和中减去一个数字会返回第二个数字这一事实。换句话说,“sum(a+b) – a”等于“b”,反之亦然。
示例
让我们利用此属性来交换“a”和“b” −
<?php $a = 10; $b = 20; echo "Before swapping - \$a = $a, \$b = $b". PHP_EOL; $a = $a + $b; $b = $a - $b; $a = $a - $b; echo "After swapping - \$a = $a, \$b = $b". PHP_EOL; ?>
它将产生以下输出:
Before swapping - $a = 10, $b = 20 After swapping - $a = 20, $b = 10
您还可以以类似的方式使用其他算术运算符 – 减法 (-)、乘法 (*) 和除法 (/) 来执行交换。
使用 list() 函数
PHP 中的 list() 函数将数组解包到单独的变量中。这有助于我们实现交换两个变量的目标。为此,构建一个包含“a”和“b”的数组,然后将其解包到“b”和“a”变量以获得具有互换值的“a”和“b”。
示例
请看以下示例:
<?php $a = 10; $b = 20; echo "Before swapping - \$a = $a, \$b = $b". PHP_EOL; $arr = [$a, $b]; list($b, $a) = $arr; echo "After swapping - \$a = $a, \$b = $b". PHP_EOL; ?>
它将产生以下输出:
Before swapping - $a = 10, $b = 20 After swapping - $a = 20, $b = 10
按位 XOR
按位异或 (^) 运算符也可用于交换两个变量“x”和“y”的值。当两个操作数中相同位置的两个位中只有一个为 1 时,它返回 1;否则返回 0。
示例
请看以下示例:
<?php $a = 10; $b = 20; echo "Before swapping - \$a = $a, \$b = $b". PHP_EOL; $a = $a ^ $b; $b = $a ^ $b; $a = $a ^ $b; echo "After swapping - \$a = $a, \$b = $b". PHP_EOL; ?>
它将产生以下输出:
Before swapping - $a = 10, $b = 20 After swapping - $a = 20, $b = 10
PHP – Closure::call()
在 PHP 中,闭包是一个匿名函数,它可以访问其创建范围内的变量,即使该范围已关闭。你需要在其中指定 use 关键字。
闭包是封装函数代码及其创建范围的对象。在 PHP 7 中,引入了一种新的 closure::call() 方法,用于将对象范围绑定到闭包并调用它。
Closure 类中的方法
Closure 类包含以下方法,包括 call() 方法:
final class Closure { /* Methods */ private __construct() public static bind(Closure $closure, ?object $newThis, object|string|null $newScope = "static"): ?Closure public bindTo(?object $newThis, object|string|null $newScope = "static"): ?Closure public call(object $newThis, mixed ...$args): mixed public static fromCallable(callable $callback): Closure }
call() 方法是 Closure 类的静态方法。它作为 bind() 或 bindTo() 方法的快捷方式被引入。
bind() 方法使用特定的绑定对象和类范围复制闭包,而 bindTo() 方法使用新的绑定对象和类范围复制闭包。
call() 方法具有以下签名:
public Closure::call(object $newThis, mixed ...$args): mixed
call() 方法将闭包临时绑定到 newThis,并使用任何给定的参数调用它。
在 PHP 7 之前的版本中,可以使用 bindTo() 方法,如下所示:
<?php class A { private $x = 1; } // Define a closure Pre PHP 7 code $getValue = function() { return $this->x; }; // Bind a clousure $value = $getValue->bindTo(new A, 'A'); print($value()); ?>
程序将$getValue(一个闭包对象)绑定到 A 类的对象,并打印其私有变量$x的值——它是 1。
在 PHP 7 中,绑定是通过 call() 方法实现的,如下所示:
<?php class A { private $x = 1; } // PHP 7+ code, Define $value = function() { return $this->x; }; print($value->call(new A)); ?>
PHP – 过滤后的 unserialize()
在 PHP 中,内置函数 unserialize() 从 PHP 4 版本开始可用。在 PHP 7 中,添加了传递允许的类列表的规定。这允许过滤掉不受信任的来源。unserialize() 函数只对来自受信任类的数进行反序列化。
在 PHP 中,序列化意味着生成值的可存储表示形式。这对于存储或传递 PHP 值非常有用,而不会丢失其类型和结构。内置的 serialize() 函数用于此目的。
serialize(mixed $value): string
unserialize() 函数从序列化的表示形式中获取 PHP 值。从 PHP 7 开始,unserialize() 函数遵循以下格式:
unserialize(string $data, array $options = [ ]): mixed
$data 参数是要反序列化的序列化字符串。
$options 参数是新引入的。它是一个包含以下键的关联数组:
序号 | 名称和描述 |
---|---|
1 | allowed_classes 应该接受的类名数组, or false 表示不接受任何类, or true 表示接受所有类。 省略此选项与将其定义为 true 相同。 |
2 | max_depth 反序列化期间允许的结构的最大深度。 |
示例
请看以下示例:
<?php class MyClass { var int $x; function __construct(int $x) { $this->x = $x; } } class NewClass { var int $y; function __construct(int $y) { $this->y = $y; } } $obj1 = new MyClass(10); $obj2 = new NewClass(20); $sob1 = serialize($obj1); $sob2 = serialize($obj2); // default behaviour that accepts all classes // second argument can be ommited. // if allowed_classes is passed as false, unserialize converts all objects into __PHP_Incomplete_Class object $usob1 = unserialize($sob1 , ["allowed_classes" => true]); // converts all objects into __PHP_Incomplete_Class object except those of MyClass and NewClass $usob2 = unserialize($sob2 , ["allowed_classes" => ["MyClass", "NewClass"]]); echo $usob1->x . PHP_EOL; echo $usob2->y . PHP_EOL; ?>
它将产生以下输出:
10 20
PHP – IntlChar
在 PHP 7 中,引入了一个新的 IntlChar 类。它提供对许多实用程序方法的访问,这些方法可用于访问有关 Unicode 字符的信息。Intl 类中有很多静态方法和常量。它们与底层 ICU(Unicode 国际组件)库使用的名称和行为非常接近。
注意你需要在系统中的 PHP 安装中启用 Intl 扩展。要启用,请打开 php.ini 文件并取消注释(删除行首的分号)
extension=intl
下面用示例解释了 Intl 类中的一些静态函数:
IntlChar::charAge
此函数获取代码点的“年龄”。
public static IntlChar::charAge(int|string $codepoint): ?array
“年龄”是代码点首次指定(作为非字符或专用用途)或分配字符的 Unicode 版本。
示例
请看以下示例:
<?php var_dump(IntlChar::charage("\u{2603}")); ?>
它将产生以下输出:
array(4) { [0]=> int(1) [1]=> int(1) [2]=> int(0) [3]=> int(0) }
IntlChar::charFromName
charFromName() 函数按名称查找 Unicode 字符并返回其代码点值。
public static IntlChar::charFromName(string $name, int $type = IntlChar::UNICODE_CHAR_NAME): ?int
type 参数设置要用于查找的名称。可以是以下任何常量:
IntlChar::UNICODE_CHAR_NAME(默认)
IntlChar::UNICODE_10_CHAR_NAME
IntlChar::EXTENDED_CHAR_NAME
IntlChar::CHAR_NAME_ALIAS
IntlChar::CHAR_NAME_CHOICE_COUNT
示例
请看以下示例:
<?php var_dump(IntlChar::charFromName("LATIN CAPITAL LETTER A")); var_dump(IntlChar::charFromName("SNOWMAN")); ?>
它将产生以下输出:
int(65) int(9731)
IntlChar::charName
charName() 函数检索 Unicode 字符的名称。
public static IntlChar::charName(int|string $codepoint, int $type = IntlChar::UNICODE_CHAR_NAME): ?string
示例
请看以下示例:
<?php var_dump(IntlChar::charName(".", IntlChar::UNICODE_CHAR_NAME)); var_dump(IntlChar::charName("\u{2603}")); ?>
它将产生以下输出:
string(9) "FULL STOP" string(7) "SNOWMAN"
IntlChar::isalpha
isalpha() 函数确定指定的代码点是否为字母字符。对于通用类别“L”(字母)为 true。
public static IntlChar::isalpha(int|string $codepoint): ?bool
示例
请看以下示例:
<?php var_dump(IntlChar::isalpha("A")); var_dump(IntlChar::isalpha("1")); ?>
它将产生以下输出:
bool(true) bool(false)
Intl 类定义了类似的静态方法,例如 isdigit()、isalnum()、isblank() 等。
IntlChar::islower
islower() 函数确定指定的代码点是否具有通用类别“Ll”(小写字母)。
public static IntlChar::islower(int|string $codepoint): ?bool
示例
请看以下示例:
<?php var_dump(IntlChar::islower("A")); var_dump(IntlChar::islower("a")); ?>
它将产生以下输出:
bool(false) bool(true)
类似地,还有诸如 isupper()、istitle()、iswhitespace() 等函数。
IntlChar::toupper
给定字符映射到其大写等价物。
public static IntlChar::toupper(int|string $codepoint): int|string|null
如果字符没有大写等价物,则返回字符本身。
示例
请看以下示例:
<?php var_dump(IntlChar::toupper("A")); var_dump(IntlChar::toupper("a")); ?>
它将产生以下输出:
string(1) "A" string(1) "A"
PHP – CSPRNG
CSPRNG 首字母缩写代表密码学安全的伪随机数生成器。PHP 函数库包含许多生成随机数的函数。例如:
mt_rand() – 通过梅森旋转算法随机数生成器生成随机值。
mt_srand() – 为梅森旋转算法随机数生成器播种。
rand() – 生成一个随机整数。
示例
以下代码显示如何使用mt_rand()函数生成随机数:
<?php # Generates random integer between the range echo "Random integer: " . rand(1,100) . PHP_EOL; # Generate a random value via the Mersenne Twister Random Number Generator echo "Random number: " . mt_rand(1,100); ?>
它将产生以下输出:
Random integer: 45 Random number: 86
请注意,每次执行代码时,输出都可能不同。但是,这些函数生成的随机数不是密码学安全的,因为可以猜测其结果。PHP 7 引入了一些生成安全随机数的函数。
以下函数是新添加的,它们是密码学安全的:
random_bytes() – 生成密码学安全的伪随机字节。
random_int() – 生成密码学安全的伪随机整数。
random_bytes() 函数
random_bytes() 生成任意长度的密码学随机字节字符串,适用于密码学用途,例如生成盐、密钥或初始化向量。
string random_bytes ( int $length )
参数
length – 以字节为单位应返回的随机字符串的长度。
该函数返回一个包含请求数量的密码学安全随机字节的字符串。
如果找不到合适的随机源,将抛出异常。如果给出无效参数,将抛出 TypeError。如果给出无效的字节长度,将抛出 Error。
示例
请看以下示例:
<?php $bytes = random_bytes(5); print(bin2hex($bytes)); ?>
它可能会产生以下输出(每次可能不同):
6a85eec950
random_int() 函数
random_int() 生成密码学随机整数,适用于对无偏结果至关重要的场合。
int random_int ( int $min , int $max )
参数
min – 要返回的最低值,必须大于或等于 PHP_INT_MIN。
max – 要返回的最高值,必须小于或等于 PHP_INT_MAX。
该函数返回 min 到 max(包括 min 和 max)范围内的密码学安全随机整数。
如果找不到合适的随机源,将抛出异常。如果给出无效参数,将抛出 TypeError。如果 max 小于 min,将抛出 Error。
示例
请看以下示例:
<?php print(random_int(100, 999)); print("\n"); print(random_int(-1000, 0)); ?>
它可能会产生以下输出(每次都不同):
495 -563
PHP – 断言
断言是对旧assert()函数向后兼容的增强。断言允许在生产代码中进行零成本断言,并在断言失败时提供抛出自定义异常的能力。
assert()现在是一个语言结构,其中第一个参数是一个表达式,而不是要测试的字符串或布尔值。
assert() 的配置指令
下表列出了 assert() 函数的配置指令:
指令 | 默认值 | 可能的值 |
---|---|---|
zend.assertions | 1 |
1 – 生成并执行代码(开发模式) 0 – 生成代码,但在运行时跳过它 -1 – 不生成代码(生产模式) |
assert.exception | 0 |
1 – 当断言失败时抛出异常,可以通过抛出作为异常提供的对象来抛出,或者如果未提供异常则抛出新的AssertionError对象。 0 – 使用或生成如上所述的可抛出对象,但仅基于该对象生成警告,而不是抛出它(与 PHP 5 行为兼容) |
参数
断言 – 断言。在 PHP 5 中,这必须是要评估的字符串或要测试的布尔值。在 PHP 7 中,这也可以是返回值的任何表达式,该表达式将被执行,其结果用于指示断言成功还是失败。
描述 – 如果断言失败,则包含在失败消息中的可选描述。
异常 – 在 PHP 7 中,第二个参数可以是 Throwable 对象而不是描述性字符串,在这种情况下,如果断言失败并且启用了 assert.exception 配置指令,则这是将要抛出的对象。
返回值
如果断言为 false,则返回 FALSE,否则返回 TRUE。
示例
请看以下示例:
<?php ini_set('assert.exception', 1); class CustomError extends AssertionError {} assert(false, new CustomError('Custom Error Message!')); ?>
它将产生以下输出:
PHP Fatal error: Uncaught CustomError: Custom Error Message! In test.php:6
PHP – “use” 语句
PHP 中的“use”关键字被发现与多种用途相关联,例如别名、插入特性和继承闭包中的变量。
别名
使用 use 运算符实现别名。它允许你使用别名或替代名称来引用外部完全限定名称。
示例
请看以下示例:
use My\namespace\myclass as Another; $obj = new Another;
你也可以按如下方式进行分组使用声明:
use some\namespace\{ClassA, ClassB, ClassC as C}; use function some\namespace\{fn_a, fn_b, fn_c}; use const some\namespace\{ConstA, ConstB, ConstC};
特性
借助 use 关键字,你可以将特性插入类中。特性类似于类,但仅用于以细粒度和一致的方式分组功能。无法自行实例化特性。
示例
请看以下示例:
<?php trait mytrait { public function hello() { echo "Hello World from " . __TRAIT__ .; } } class myclass { use mytrait; } $obj = new myclass(); $obj->hello(); ?>
它将产生以下输出:
Hello World from mytrait
闭包
闭包也是一个匿名函数,它可以借助“use”关键字访问其范围之外的变量。
示例
请看以下示例:
<?php $maxmarks=300; $percent=function ($marks) use ($maxmarks) { return $marks*100/$maxmarks; }; $m = 250; echo "marks=$m percentage=". $percent($m); ?>
它将产生以下输出:
marks=250 percentage=83.333333333333
PHP – 整数除法
PHP 引入了一个新的函数 intdiv(),它执行其操作数的整数除法并返回除法结果为整数。
intdiv() 函数返回两个整数参数的整数商。如果“a/b”的结果是除法为“c”余数为“r”,则:
a=b*c+r
在这种情况下,intdiv(a,b)返回r:
intdiv ( int $x , int $y ) : int
$x 和 $y 是除法表达式的分子和分母部分。intdiv() 函数返回一个整数。如果两个参数都是正数或都是负数,则返回值为正。
示例 1
如果分子 < 分母,intdiv() 函数返回“0”,如下所示:
<?php $x=10; $y=3; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r . "\n"; $r=intdiv($y, $x); echo "intdiv(" . $y . "," . $x . ") = " . $r; ?>
它将产生以下输出:
intdiv(10,3) = 3 intdiv(3,10) = 0
示例 2
在下面的示例中,intdiv() 函数返回负整数,因为分子或分母是负数。
<?php $x=10; $y=-3; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r . "\n"; $x=-10; $y=3; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r . "\n"; ?>
它将产生以下输出:
intdiv(10,-3) = -3 intdiv(-10,3) = -3
示例 3
如果分子和分母都是正数或都是负数,intdiv() 函数返回正整数。
<?php $x=10; $y=3; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r . "\n"; $x=-10; $y=-3; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r ; ?>
它将产生以下输出:
intdiv(10,3) = 3 intdiv(-10,-3) = 3
示例 4
在下面的示例中,分母为“0”。这会导致DivisionByZeroError异常。
<?php $x=10; $y=0; $r=intdiv($x, $y); echo "intdiv(" . $x . "," . $y . ") = " . $r . "\n"; ?>
它将产生以下输出:
PHP Fatal error: Uncaught DivisionByZeroError: Division by zero in hello.php:4
PHP – 已弃用的特性
随着每个新版本的添加一些新特性,也删除了一些特性,因为它们被认为已过时。在本章中,我们将介绍 PHP 5 版本之后已弃用的特性。
在 PHP 7 中已弃用
PHP 4 样式的构造函数
PHP 4 样式的构造函数(与类名相同的函数)现已弃用,将来会移除。如果 PHP 4 构造函数是类中唯一定义的构造函数,PHP 7 将发出 E_DEPRECATED 警告。实现 __construct() 方法的类不受影响。
示例
请看以下示例:
<?php class A { function A() { print('Style Constructor'); } } ?>
它在浏览器上产生以下输出:
Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; A has a deprecated constructor in...
对非静态方法的静态调用
对非静态方法的静态调用已弃用,将来可能会移除。
示例
请看以下示例:
<?php class A { function b() { print('Non-static call'); } } A::b(); ?>
它在浏览器上产生以下输出:
Deprecated: Non-static method A::b() should not be called statically in... Non-static call
password_hash() 的 salt 选项
password_hash() 函数的 salt 选项已弃用,以防止开发者生成自己的(通常不安全的)salt。如果开发者未提供 salt,该函数本身会生成密码学安全的 salt,因此不再需要自定义 salt 生成。
capture_session_meta SSL 上下文选项
capture_session_meta SSL 上下文选项已弃用。现在通过 stream_get_meta_data() 函数使用 SSL 元数据。
ext/mcrypt
mcrypt 扩展已弃用,建议使用 OpenSSL。
未加引号的字符串
未加引号且不存在的全局常量将被视为字符串本身。此行为过去会发出 E_NOTICE 警告,现在将发出 E_WARNING 警告。在 PHP 的下一个主要版本中,将抛出 Error 异常。
__autoload() 方法
__autoload() 方法已弃用,因为它不如 spl_autoload_register() (因为它无法链接自动加载器),并且这两种自动加载方式之间没有互操作性。
create_function() 函数
鉴于此函数的安全问题,它现已弃用。建议使用匿名函数作为替代。
each() 函数
此函数会导致某些语言更改的实现问题。因此,它已被弃用。
不区分大小写的常量
不区分大小写的常量声明已弃用。现在,将 true 作为第三个参数传递给 define() 将生成弃用警告。
(real) 类型转换和 is_real() 函数
(real) 类型转换已弃用,请改用 (float)。is_real() 函数也已弃用,请改用 is_float()。
"parent" 关键字
在没有父类的类中使用 parent 已弃用,将来会引发编译时错误。目前,只有在运行时访问父类时才会生成错误。
PHP 8 中已弃用
如果带有默认值的参数后面跟着必需参数,则默认值无效。从 PHP 8.0.0 开始,这已被弃用,通常可以通过删除默认值来解决,而不会改变功能:
<?php function test($a = [], $b) {} // Before function test($a, $b) {} // After ?>
此规则的一个例外是 Type $param = null 形式的参数,其中 null 默认值使类型隐式可为空。此用法仍然允许,但建议改用显式可空类型:
<?php function test(A $a = null, $b) {} // Still allowed function test(?A $a, $b) {} // Recommended ?>
将 get_defined_functions() 的 exclude_disabled 显式设置为 false 已弃用,并且不再有效。get_defined_functions() 永远不会包含禁用的函数。
返回 true 或 false 的排序比较函数现在将抛出弃用警告,应将其替换为返回小于、等于或大于零的整数的实现。
<?php // Replace usort($array, fn($a, $b) => $a > $b); // With usort($array, fn($a, $b) => $a <=> $b); ?>
隐式不兼容的 float 到 int 转换
导致精度损失的 float 到 int 的隐式转换现已弃用。这会影响数组键、强制模式下的 int 类型声明以及对 int 进行运算的运算符。
在 Trait 上调用静态元素
直接在 Trait 上调用静态方法或访问静态属性已弃用。静态方法和属性只能在使用该 Trait 的类上访问。
日期函数
date_sunrise() 和 date_sunset() 已弃用。请改用 date_sun_info()。
strptime() 已弃用。请改用 date_parse_from_format()(用于与区域设置无关的解析)或 IntlDateFormatter::parse()(用于与区域设置相关的解析)。
strftime() 和 gmstrftime() 已弃用。您可以改用 date()(用于与区域设置无关的格式化)或 IntlDateFormatter::format()(用于与区域设置相关的格式化)。
动态属性
创建动态属性已弃用。请改用允许动态属性的 stdClass。
PHP – 已移除的扩展和 SAPI
PHP 的每个新版本都会添加新功能,同时也会移除某些过时的功能。PHP 7 是一个主要版本,其中删除了许多 PHP 扩展和 SAPI(服务器端应用程序编程接口)。在随后的 PHP 8 版本中,还删除了一些扩展。
在 PHP 中,扩展是用 C/C++ 编写的库或插件,编译成共享库以便可以加载到 PHP 解释器中。PHP 解释器启动后,扩展中的函数即可供 PHP 脚本使用。
定期移除扩展,因为它们要么不再维护,要么已被更新的替代方案取代。例如,与 PHP 7 同时,ereg 扩展被 preg 扩展取代,mssql 扩展被 PDO_MSSQL 扩展取代。
已移除的扩展
从 PHP 7 开始,已移除以下扩展:
ereg 扩展已由 preg 替代
mssql 扩展已由 pdo_mssql 替代
mysql 扩展已由 mysqli 替代
sybase_ct 已由 pdo_sybase 替代
从 PHP 8 开始,已移除以下扩展:
Mcrypt - Mcrypt 扩展用于加密和解密,但自 PHP 7.1 起已弃用,并在 PHP 8 中由于安全漏洞而被移除。
MDB2 - MDB2 扩展以前用于访问 MDB 数据库文件,由于缺乏维护,在 PHP 8 中被移除。
Ming - 由于 Flash 现在不再流行,用于生成 Flash 内容的 Ming 扩展自 PHP 5.5 起已弃用,并在 PHP 8 中被移除。
Phar Data - Phar Data 扩展用于访问 PHAR 存档中的数据,但在 PHP 8 中被移除,因为还有其他方法可以访问 PHAR 数据。
SNMP - 由于没有维护,SNMP 扩展已在 PHP 8 中移除。
Tidy - 由于添加了新的 HTML 验证库,Tidy 扩展已在 PHP 中移除。
Tokenizer - Tokenizer 扩展也因同样的原因在 PHP 8 中被移除。
cURL - cURL 扩展在 PHP 8.1 中被移除,因为它不再维护。
已移除的 SAPI
SAPI 代表 PHP 中的服务器端应用程序编程接口。SAPI 负责将 PHP 代码转换为 Web 服务器可以理解的内容。它解析 PHP 代码并调用相应的 Web 服务器函数。然后,Web 服务器生成 HTTP 响应并将其发送回客户端。
从 PHP 7 开始,已移除以下 SAPI(服务器端应用程序编程接口):
aolserver
apache
apache_hooks
apache2filter
caudium
cgi
cgi-fcgi
fastcgi
isapi
litespeed
nsapi
pwsapi
router
thttpd
uwsgi
webserver
apache2filter
continuity
isapi
milter
nsapi
pi3web
roxen
thttpd
tux
webjames
PHP – PEAR
PEAR 是 **PHP Extension and Application Repository** 的缩写。它是 PHP 包或扩展的存储库。您可以自由地将 PEAR 中的任何这些扩展合并到您的代码中。PEAR 项目由 Stig S. Bakken 于 1999 年创建。
大多数 PHP 的预编译发行版(如 XAMPP)都已捆绑了 PEAR。如果没有,您可以从 https://pear.php.net/go-pear.phar 下载 go-pear.phar 文件并运行
php go-pear.phar
Windows 命令提示符以启动安装。
根据您对安装步骤的响应,PEAR 包管理器将安装在安装过程中指定的路径中。
然后,您可以将该安装路径添加到您的 PATH 环境变量中。您可以手动执行此操作(开始 > 控制面板 > 系统 > 环境),或者运行(双击)现在位于 PHP 源目录中的新生成的 PEAR_ENV.reg。
现在,您可以通过运行以下命令访问 PEAR 包管理器:
C:\xampp\php>pear
在 Windows 命令提示符中。
您将获得以下 PEAR 命令列表:
C:\xampp\php>pear Commands: build Build an Extension From C Source bundle Unpacks a Pecl Package channel-add Add a Channel channel-alias Specify an alias to a channel name channel-delete Remove a Channel From the List channel-discover Initialize a Channel from its server channel-info Retrieve Information on a Channel channel-login Connects and authenticates to remote channel server channel-logout Logs out from the remote channel server channel-update Update an Existing Channel clear-cache Clear Web Services Cache config-create Create a Default configuration file config-get Show One Setting config-help Show Information About Setting config-set Change Setting config-show Show All Settings convert Convert a package.xml 1.0 to package.xml 2.0 format cvsdiff Run a "cvs diff" for all files in a package cvstag Set CVS Release Tag download Download Package download-all Downloads each available package from the default channel info Display information about a package install Install Package list List Installed Packages In The Default Channel list-all List All Packages list-channels List Available Channels list-files List Files In Installed Package list-upgrades List Available Upgrades login Connects and authenticates to remote server [Deprecated in favor of channel-login] logout Logs out from the remote server [Deprecated in favor of channel-logout] makerpm Builds an RPM spec file from a PEAR package package Build Package package-dependencies Show package dependencies package-validate Validate Package Consistency pickle Build PECL Package remote-info Information About Remote Packages remote-list List Remote Packages run-scripts Run Post-Install Scripts bundled with a package run-tests Run Regression Tests search Search remote package database shell-test Shell Script Test sign Sign a package distribution file svntag Set SVN Release Tag uninstall Un-install Package update-channels Update the Channel List upgrade Upgrade Package upgrade-all Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]
使用 PEAR 安装包非常容易。查找包的一种方法是使用官方 PEAR 网站 https://pear.php.net/packages.php,然后运行
pear install <package-name>
下一步是在您的代码中使用 PEAR 包。为此,您应该使用 include、require、include_once 或 require_once 语句将包的主 PHP 脚本包含到您的程序中。
<?php include "PEARPACKAGE.php"; . . . . . // rest of the code . . . . . ?>
一个名为 Composer 的较新的 PHP 包管理器是用于管理 PHP 项目包的替代方案。Composer 还支持安装 PEAR 包。许多人更喜欢使用 Composer 而不是 PEAR 来分发 PHP 包。
PHP – CSRF
"CSRF" 是跨站请求伪造的缩写。CSRF 是一种互联网漏洞,涉及受信任的网站用户发出未经授权的命令。可以通过本章中解释的措施来为 PHP Web 应用程序提供针对此攻击的充分保护。
默认情况下,浏览器使用“GET”请求方法发送数据。这通常用作 CSRF 中的漏洞点。为了将命令注入到特定网站,攻击者使用诸如“IMG”之类的 HTML 标签。例如,Web 应用程序的 URL 端点(例如“/delete.php?empcode=1234”)会删除从 GET 请求的 empcode 参数传递的帐户。现在,如果经过身份验证的用户在任何其他应用程序中遇到以下脚本:
<img src="http://example.com/delete.php?empcode=1234" width="0" height="0" border="0">
无意中导致与 empcode=1234 相关的数据被删除。
解决此问题的常用方法是使用 CSRF 令牌。CSRF 令牌是由嵌入到请求中的随机字符组成的字符串,以便 Web 应用程序可以信任该请求已从预期来源(根据正常工作流程)接收。
实现 CSRF 的步骤
在 PHP 中实现 CSRF 令牌保护的步骤如下:
通过启动新会话来开始脚本。
生成一个随机字符令牌。您可以使用 PHP 提供的几个内置函数中的任何一个来生成随机字符串。让我们使用 md5() 函数来获取生成唯一随机字符串的 uniqueid() 函数的哈希值。
在要提供给用户提交数据的 HTML 表单中,包含一个隐藏字段,其值为上述步骤中生成的随机令牌。
然后,服务器在表单提交后根据用户会话验证令牌,以消除恶意请求。
您还可以添加另一个会话变量,其值为当前时间,并发送到期时间以进行验证。
示例
以下是实现 CSRF 令牌验证机制的 PHP 代码。以下脚本生成令牌并将其嵌入到 HTML 表单中。
<?php session_start(); if(!isset($_SESSION["csrf_token"])) { // No token present, generate a new one $token = md5(uniqid(rand(), true)); $_SESSION["csrf_token"] = $token; } else { // Reuse the token $token = $_SESSION["csrf_token"]; } ?> <html> <body> <form method="get" action="test.php"> <input type="text" name="empcode" placeholder="empcode" /> <input type="hidden" name="csrf_token" value="<?php echo $token;?>" /> <input type="submit" /> </form> </body> </html>
表单提交到以下“test.php”脚本:
<?php session_start(); echo "hello"; if ($_GET["csrf_token"] == $_SESSION["csrf_token"]) { // Reset token echo $_GET["csrf_token"] . "<br>"; echo $_SESSION["csrf_token"] . "<br>"; echo "<h3>CSRF token validation successful. Proceed to further action</h3>"; } else { echo "<h3>CSRF token validation failed</h3>"; } ?>
它将产生以下输出:
要模拟 CSRF 验证失败,请打开浏览器的检查工具,手动编辑隐藏字段中的值,然后提交表单,您将看到令牌不匹配,导致验证失败。
PHP – FastCGI 进程
PHP FastCGI 进程管理器 (PHP-FPM) 是处理 PHP 请求(尤其是在高流量环境中)的传统基于 CGI 的方法的有效替代方案。PHP-FPM 具有许多重要功能。这些功能如下:
降低内存消耗
借助用于处理请求的 worker 进程池,与为每个请求生成新进程的传统 CGI 方法相比,PHP-FPM 大大降低了内存开销。
性能提升
PHP-FPM 的 worker 进程是持久的。它允许它们处理多个请求。它不需要重复创建和销毁进程。这导致响应时间更快,并且可以更好地处理高并发。
可扩展性增强
PHP-FPM 的 worker 进程池可以根据流量需求动态调整,使其能够有效地扩展以处理不同的工作负载。
高级进程管理
PHP-FPM 提供优雅的启动和关闭功能。它还对进程管理具有精细的控制,包括紧急重启和工作进程监控。
环境隔离
PHP-FPM 允许为不同的应用程序或用户组创建单独的进程池,从而为每个环境提供更好的隔离和安全性。
可自定义配置
PHP-FPM 使用基于 php.ini 的配置选项。通过这些广泛的选项,可以微调其行为以匹配特定的应用程序需求。
支持多个 PHP 版本
PHP-FPM 可以同时管理多个 PHP 版本,从而能够在一台服务器上部署不同的 PHP 应用程序。
PHP-FPM 通常与 Nginx 或 Apache 等 Web 服务器一起使用。它充当处理 PHP 请求的后端处理器。由于其性能、可扩展性和可靠性,它已成为在生产环境中管理 PHP 应用程序的首选方法。
PHP – PDO 扩展
PDO 是 PHP 数据对象的缩写。PHP 可以与大多数关系型和 NoSQL 数据库交互。默认的 PHP 安装已经安装并启用了特定于供应商的数据库扩展。除了特定于某种类型数据库的数据库驱动程序(例如 MySQL 的 mysqli 扩展)之外,PHP 还支持 PDO 和 ODBC 等抽象层。
PDO 扩展定义了一个轻量级、一致的接口,用于在 PHP 中访问数据库。每个特定于供应商的扩展的功能都各不相同。因此,如果您打算更改某个 PHP 应用程序的后端数据库(例如,从 PostGreSql 更改为 MySQL),则需要对代码进行大量更改。另一方面,PDO API 只需要指定要使用的新的数据库的 URL 和凭据,而无需进行任何其他更改。
您的当前 PHP 安装必须具有相应的 PDO 驱动程序才能工作。目前,以下数据库支持相应的 PDO 接口:
驱动程序名称 | 支持的数据库 |
---|---|
PDO_CUBRID | Cubrid |
PDO_DBLIB | FreeTDS / Microsoft SQL Server / Sybase |
PDO_FIREBIRD | Firebird |
PDO_IBM | IBM DB2 |
PDO_INFORMIX | IBM Informix Dynamic Server |
PDO_MYSQL | MySQL 3.x/4.x/5.x/8.x |
PDO_OCI | Oracle 调用接口 |
PDO_ODBC | ODBC v3 (IBM DB2, unixODBC 和 win32 ODBC) |
PDO_PGSQL | PostgreSQL |
PDO_SQLITE | SQLite 3 和 SQLite 2 |
PDO_SQLSRV | Microsoft SQL Server / SQL Azure |
默认情况下,PDO_SQLITE 驱动程序在 php.ini 的设置中已启用,因此,如果您希望使用 PDO 与 MySQL 数据库交互,请确保通过删除前面的分号取消以下行的注释。
extension=pdo_mysql
您可以通过调用 PDO 类中的 PDO::getAvailableDrivers() 静态函数来获取当前可用 PDO 驱动程序的列表。
PDO 连接
PDO 基类的实例表示数据库连接。构造函数接受用于指定数据库源(称为 DSN)的参数,以及可选的用户名和密码(如果有)。
以下代码段是建立与 MySQL 数据库连接的典型方法:
<?php $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass); ?>
如果存在任何连接错误,将抛出 PDOException 对象。
示例
请看以下示例:
<?php $dsn="localhost"; $dbName="myDB"; $username="root"; $password=""; try{ $dbConn= new PDO("mysql:host=$dsn;dbname=$dbName",$username,$password); Echo "Successfully connected with $dbName database"; } catch(Exception $e){ echo "Connection failed" . $e->getMessage(); } ?>
它将产生以下输出:
Successfully connected with myDB database
错误情况下:
Connection failedSQLSTATE[HY000] [1049] Unknown database 'mydb'
PDO 类方法
PDO 类定义了以下静态方法:
PDO::beginTransaction
获取连接对象后,应调用此方法来启动事务。
public PDO::beginTransaction(): bool
此方法关闭自动提交模式。因此,您需要调用 commit() 方法才能对数据库进行持久性更改。调用 rollBack() 将回滚对数据库的所有更改并将连接返回到自动提交模式。此方法在成功时返回 true,失败时返回 false。
PDO::commit
commit() 方法提交事务。
public PDO::commit(): bool
由于 BeginTransaction 禁用了自动提交模式,因此您应该在事务后调用此方法。它提交事务,将数据库连接返回到自动提交模式,直到下次调用 PDO::beginTransaction() 启动新事务为止。此方法在成功时返回 true,失败时返回 false。
PDO::exec
exec() 方法执行 SQL 语句并返回受影响的行数
public PDO::exec(string $statement): int|false
exec() 方法在一个函数调用中执行 SQL 语句,返回受语句影响的行数。
请注意,它不返回 SELECT 语句的结果。如果您有一个仅在程序中执行一次的 SELECT 语句,请考虑使用 PDO::query()。
另一方面,对于需要多次执行的语句,请使用 PDO::prepare() 准备 PDOStatement 对象,并使用 PDOStatement::execute() 执行语句。
exec() 方法需要一个字符串参数,该参数表示要准备和执行的 SQL 语句,并返回由您发出的 SQL 语句修改或删除的行数。如果未受影响的行,PDO::exec() 返回 0。
PDO::query
query() 方法准备和执行不带占位符的 SQL 语句
public PDO::query(string $query, ?int $fetchMode = null): PDOStatement|false
此方法在一个函数调用中准备和执行 SQL 语句,并将语句作为 PDOStatement 对象返回。
PDO::rollBack
rollback() 方法回滚由 PDO::beginTransaction() 启动的事务。
public PDO::rollBack(): bool
如果数据库设置为自动提交模式,则此函数将在回滚事务后恢复自动提交模式。
请注意,包括 MySQL 在内的一些数据库在事务中发出 DDL 语句(例如 DROP TABLE 或 CREATE TABLE)时会自动发出隐式 COMMIT,因此它将阻止您回滚事务边界内的任何其他更改。此方法在成功时返回 true,失败时返回 false。
示例
以下代码在 MySQL 服务器上的 myDB 数据库中创建一个 student 表。
<?php $dsn="localhost"; $dbName="myDB"; $username="root"; $password=""; try{ $conn= new PDO("mysql:host=$dsn;dbname=$dbName",$username,$password); Echo "Successfully connected with $dbName database"; $qry = <<<STRING CREATE TABLE IF NOT EXISTS STUDENT ( student_id INT AUTO_INCREMENT, name VARCHAR(255) NOT NULL, marks INTEGER(3), PRIMARY KEY (student_id) ); STRING; echo $qry . PHP_EOL; $conn->exec($qry); $conn->commit(); echo "Table created\n"; } catch(Exception $e){ echo "Connection failed : " . $e->getMessage(); } ?>
示例
使用以下代码在上面示例中创建的 student 表中插入新记录:
<?php $dsn="localhost"; $dbName="myDB"; $username="root"; $password=""; try { $conn= new PDO("mysql:host=$dsn;dbname=$dbName",$username,$password); echo "Successfully connected with $dbName database"; $sql = "INSERT INTO STUDENT values(1, 'Raju', 60)"; $conn->exec($sql); $conn->commit(); echo "A record inserted\n"; } catch(Exception $e){ echo "Connection failed : " . $e->getMessage(); } ?>
示例
以下 PHP 脚本获取 student 表中的所有记录:
<?php $dsn="localhost"; $dbName="myDB"; $username="root"; $password=""; try { $conn= new PDO("mysql:host=$dsn;dbname=$dbName",$username,$password); echo "Successfully connected with $dbName database"; $sql = "SELECT * from student"; $statement = $conn->query($sql); $rows = $statement->fetchAll(PDO::FETCH_ASSOC); foreach ($rows as $row) { var_dump($row); } } catch(Exception $e){ echo "Connection failed : " . $e->getMessage(); } ?>
PHP - 函数参考
PHP 在内置函数方面非常丰富。以下是各种重要函数类别的列表。此处未涵盖其他各种函数类别。
选择一个类别以查看与该类别相关的所有函数的列表。