ZetCode PHP 教程(一)
原文:ZetCode
PHP 教程
这是 PHP 教程。 本教程涵盖了 PHP 编程语言的核心。 它使用 PHP CLI。 PHP 教程适合初学者。
目录
PHP
PHP 是一种专为 Web 开发而设计的脚本语言。 它用于产生动态网页。 当前,PHP 是使用最广泛的编程语言之一。 它的大部分语法是从 C,Java 和 Perl 借来的,它们具有几个特定于 PHP 的独特功能。 PHP 可以嵌入 HTML 代码中,并且通常在 Web 服务器上运行。
相关教程
您可能还会对以下教程感兴趣: PHP 文件系统函数, MongoDB PHP 教程, PHP SQLite3 教程, [PHP 7 中的新语言功能 , MySQL PHP 教程或 PostgreSQL PHP 教程。
PHP
在 PHP 教程的这一部分中,我们通常讨论 PHP 编程语言。
目标
本教程的目标是使您开始使用 PHP 编程语言。 本教程涵盖了 PHP 语言的核心:变量,数组,控件结构和其他核心功能。 它不涉及 Web 开发,数据库或其他众多主题。 在本教程中,我们使用 PHP 7.2。
PHP
PHP 是一种专为 Web 开发而设计的脚本语言。 它用于产生动态网页。 当前,PHP 是使用最广泛的编程语言之一。 它的大部分语法是从 C,Java 和 Perl 借来的,它们具有几个特定于 PHP 的独特功能。 PHP 可以嵌入 HTML 代码中,并且通常在 Web 服务器上运行。 需要将 Web 服务器配置为处理 PHP 代码并从中创建 Web 网页内容。 它可以部署在大多数 Web 服务器和操作系统上。 PHP 是一个免费软件。 PHP 于 1995 年首次创建,此后一直在积极开发。
PHP 支持面向对象和过程编程风格。
PHP 编程语言的官方网站是 php.net
安装 PHP
可以通过安装包或开发包 WAMP,MAMP 或 XAMPP 安装 PHP。
$ php -v
PHP 7.2.11 (cli) (built: Oct 10 2018 02:39:52) ( ZTS MSVC15 (Visual C++ 2017) x86 )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
我们得到了 PHP 版本。
PHP CLI
PHP CLI 是 PHP 语言的命令行解释器。 这对于从外壳测试 PHP 脚本很有用。 在本教程中,我们使用 PHP 命令行解释器。 我们专注于 PHP 语言的核心。
simple.php
<?php
echo "this is PHP language\n";
这里我们有一个简单的 PHP 脚本。
$ php simple.php
this is PHP language
我们执行脚本。
PHP 交互式 Shell
与 Python 或 Ruby 一样,PHP 也具有交互式 Shell。 测试小型语言结构很有用。
$ php -a
Interactive mode enabled
php> print PHP_OS;
Linux
php> print PHP_VERSION;
7.2.11
通过php
命令的-a
选项调用 PHP Shell。 Shell 使用php>
提示符。
参考文献
在 PHP 教程的这一部分中,我们介绍了 PHP 语言。
PHP 语法结构
像人类语言一样,计算机语言也具有词汇结构。 PHP 脚本的源代码由令牌组成。 令牌是原子代码元素。 在 PHP 语言中,我们具有注释,变量,字面值,运算符,定界符和关键字。
PHP 注释
注释被人类用来阐明源代码。 PHP 中的所有注释均以#
字符结尾。
<?php
# comments.php
# Author Jan Bodnar
# ZetCode 2016
echo "This is comments.php script\n";
PHP 解释器将忽略#
字符后的所有内容。
// comments.php
// author Jan Bodnar
// ZetCode 2016
/*
comments.php
author Jan Bodnar
ZetCode 2016
*/
PHP 还可以识别来自 C 语言的注释。
PHP 空白字符
PHP 中的空白字符用于分隔 PHP 源文件中的标记。 它用于提高源代码的可读性。
public $isRunning;
在某些地方需要空格。 例如在访问说明符和变量名之间。 在其他地方,这是禁止的。 它不能出现在变量标识符中。
$a=1;
$b = 2;
$c = 3;
标记之间放置的空间量与 PHP 解释器无关。 它基于程序员的喜好和风格。
$a = 1;
$b = 2; $c = 3;
$d
=
4;
我们可以将两个语句放在一行中。 或将一条语句分成三行。 但是,源代码应该是人类可读的。 存在有关如何布置源代码的公认标准。
PHP 分号
分号用于标记 PHP 语句的结尾。 这是强制性的。
$a = 34;
$b = $a * 34 - 34;
echo $a;
在这里,我们有三个不同的 PHP 语句。 首先是一项任务。 它将一个值放入$a
变量。 第二个是表达式。 计算表达式并将输出提供给$b
变量。 第三个是命令。 打印$a
变量。
PHP 变量
variable
是一个标识符,它保存一个值。 在编程中,我们说我们为变量分配了一个值。 从技术上讲,变量是对存储值的计算机内存的引用。 在 PHP 语言中,变量可以包含字符串,数字或各种对象,例如函数或类。 可以随时间为变量分配不同的值。
PHP 中的变量由$
字符(称为符号)和标签组成。 可以使用字母数字字符和下划线_
字符创建标签。 变量不能以数字开头。 然后,PHP 解释器可以更轻松地区分数字和变量。
$Value
$value2
$company_name
这些是有效的 PHP 标识符。
$12Val
$exx$
$first-name
这些是无效的 PHP 标识符的示例。
变量为区分大小写。 这意味着$Price
,$price
和$PRICE
是三个不同的标识符。
case.php
<?php
$number = 10;
$Number = 11;
$NUMBER = 12;
echo $number, $Number, $NUMBER;
echo "\n";
在脚本中,我们将三个数值分配给三个变量并打印出来。 但是,出于清楚的原因,不建议创建仅在大小写不同的变量。 这被认为是不好的做法。
$ php case.php
101112
这是脚本的输出。
PHP 常量
常量是在脚本执行期间不能更改的值的标识符。 按照约定,常量标识符始终为大写。
constants.php
<?php
define("SIZE", 300);
define("EDGE", 100);
#SIZE = 100;
echo SIZE;
echo EDGE;
echo "\n";
在脚本中,我们定义了两个常量。
define("SIZE", 300);
define("EDGE", 100);
常量是使用define()
函数创建的。
# SIZE = 100;
常量与变量不同。 我们不能为现有常量分配其他值。 如果我们取消注释该行,脚本将失败。
echo SIZE;
echo EDGE;
常量不使用美元符号。
$ php constants.php
300100
这是constants
脚本的输出。
以下是 PHP 编译时间常数的列表。
__CLASS__ __DIR__ __FILE__ __FUNCTION__
__METHOD__ __NAMESPACE__
PHP 字面值
literal
是表示 PHP 源代码中的值的任何符号。 从技术上讲,字面值是在编译时分配一个值的,而变量是在运行时分配的。
$age = 29;
$nationality = "Hungarian";
在这里,我们为变量分配了两个字面值。 数字 29 和字符串"Hungarian"
是字面值。
literals.php
<?php
$name1 = "Jane ";
$age1 = 17;
$name2 = "Rose ";
$age2 = 16;
echo "Patrick 34\n";
echo "Luke 22\n";
echo $name1, $age1, "\n";
echo $name2, $age2, "\n";
如果我们不为变量分配字面值,则无法使用它-删除它。
$ php literals.php
Patrick 34
Luke 22
Jane 17
Rose 16
这是literals.php
脚本的输出。
PHP 运算符
operator
是用于对某个值执行操作的符号。
+ - * / % ** ++ -- ?: ??
= += -= *= /= .= %=
== != === !== <> > < >= <= <=>
&& || ! xor or
& ^ | ~ . << >>
这些是 PHP 运算符。 我们将在本教程的后面部分讨论运算符。
PHP 分隔符
delimiter
是一个或多个字符的序列,用于指定纯文本或其他数据流中单独的独立区域之间的边界。
$a = "PHP";
$b = 'Java';
单字符和双字符用于标记字符串的开头和结尾。
function setDate($date) {
$this->date = $data;
}
if ($a > $b) {
echo "\$a is bigger than \$b";
}
括号用于标记函数签名。 签名是函数参数。 圆括号用于标记函数主体的开始和结束。 它们还用于控制流。
$a = array(1, 2, 3);
echo $a[1];
方括号用于标记数组索引。
/*
Author Jan Bodnar
January 2019
ZetCode
*/
/**/
分隔符用于在 PHP 中提供 C 样式注释。
<?php
// PHP code
<?php
分隔符用于声明 PHP 代码的开始。
PHP 关键字
关键字是 PHP 编程语言中的保留字。 关键字用于在计算机程序中执行特定任务; 例如,打印值,执行重复性任务或执行逻辑操作。 程序员不能将关键字用作普通变量。
以下是 PHP 关键字的列表。
abstract and array() as break
case catch class clone const
continue declare default do else
elseif enddeclare endfor endforeach endif
endswitch endwhile extends final for
foreach function global goto if
implements interface instanceof namespace new
or private protected public static
switch throw try use var
while xor yield yield from
接下来,我们还有其他语言构造。
die() echo() empty() exit() eval()
include() include_once() isset() list() require()
require_once() return() print() unset()
在 PHP 教程的这一部分中,我们介绍了 PHP 语言的基本词汇结构。
PHP 基础
在 PHP 教程的这一部分中,我们讨论 PHP 的基本编程。
所有 PHP 代码都由两个定界符<?php
和?>
包围。
<?php
# PHP code
PHP 代码放在两个定界符之间。
PHP 控制台输出
我们的 PHP 脚本的输出将发送到控制台。 注意我们之所以说控制台,是因为这里我们使用PHP_CLI
命令行解释器。 如果我们在网络上测试这些示例,则输出将发送到浏览器。
printing.php
<?php
$a = 23;
print $a;
该 PHP 脚本为变量分配值。 它将打印到控制台。
$a = 23;
我们为$a
变量分配一个值 23。 每个变量都以美元字符开头。 此 PHP 代码行是一条语句。 每个语句以分号结尾。 在 PHP 中,分号不是像 JavaScript 或 Ruby 中那样可选的。 他们是必须的。
print $a;
我们将$a
变量打印到控制台。 print
关键字不会在输出中添加新行。 如果要换行,则必须手动放置。 print
关键字仅接受一个参数。
echoing.php
<?php
$a = 23;
$b = 24;
echo $a, "\n", $b, "\n";
在此脚本中,我们使用echo
关键字。 它类似于print
关键字。 与print
关键字不同,它可以采用多个参数。
$a = 23;
$b = 24;
我们定义两个变量。
echo $a, "\n", $b, "\n";
我们将变量打印到控制台。 我们还包括换行符。 参数可以用逗号分隔。
$ php echoing.php
23
24
这是脚本的输出。
PHP 命令行参数
PHP 脚本可以接收命令行参数。 它们遵循程序的名称。 $argv
是一个包含 PHP 脚本的所有参数的数组。 $argc
保留传递的参数数量,包括 PHP 脚本的名称。
arguments.php
<?php
echo "There are $argc arguments\n";
for ($i=0; $i < $argc; $i++) {
echo $argv[$i] . "\n";
}
该脚本与命令行参数一起使用。
echo "There are $argc arguments\n";
我们打印传递给脚本的参数数量。
for ($i=0; $i < $argc; $i++) {
echo $argv[$i] . "\n";
}
在for
循环中,我们遍历并打印所有参数。 循环将在本教程的后面部分介绍。
$ php arguments.php 1 2 3
There are 4 arguments
arguments.php
1
2
3
我们将三个参数传递给脚本。 脚本的名称也是 PHP 脚本的参数。
PHP 类型
PHP 是一种弱类型语言。 它适用于类型,但是程序员在声明变量时不指定它们。 数据类型是多种类型的数据之一,如double
,integer
或boolean
。 某种数据类型的值来自特定范围的值,这些值说明该类型的可能值,对该类型可以执行的操作以及该类型的值的存储方式。 PHP 与数据类型隐式地工作。 程序员没有明确指定数据类型。
dynamic.php
<?php
$a = "Jane";
echo "$a \n";
$a = 12;
echo "$a \n";
$a = 56.4;
echo "$a \n";
$a = true;
echo "$a \n";
在此 PHP 脚本中,我们有一个$a
变量。 首先,我们给它分配一个字符串,然后是一个整数,一个双精度数,最后是一个布尔值。 如果我们将字符串分配给变量,PHP 会自动创建一个字符串变量。
$ php dynamic.php
Jane
12
56.4
1
运行脚本,我们得到此输出。
gettype.php
<?php
$temperature = 12.4;
$name = "Jane";
$age = 17;
$values = array(1, 2, 3, 4, 5, 6);
class Being {};
$somebody = new Being();
echo gettype($temperature), "\n";
echo gettype($name), "\n";
echo gettype($age), "\n";
echo gettype($values), "\n";
echo gettype($somebody), "\n";
在上面的 PHP 脚本中,我们动态创建了五种类型。
$temperature = 12.4;
定义了一个双变量。
$name = "Jane";
定义了一个字符串变量。
$age = 17;
定义了一个整数变量。
$values = array(1, 2, 3, 4, 5, 6);
class Being {};
这是一个数组和一个类。 稍后将更详细地介绍这两种类型。
echo gettype($temperature), "\n";
gettype()
函数返回相关变量的类型。
$ php gettype.php
double
string
integer
array
object
该脚本列出了 PHP 的基本类型。
PHP 常量
在 PHP 中,我们可以创建常量。 常量是值的名称,与变量不同,该值不能与其他值重新关联。 我们使用define()
函数在 PHP 中创建常量。
constants.php
<?php
define("BLUE", "0000FF");
echo BLUE, "\n";
echo defined("BLUE");
echo "\n";
在此 PHP 脚本中,我们定义一个BLUE
常量。
define("BLUE", "0000FF");
在这里,我们定义BLUE
常数。 按照惯例,用大写字母写常量。
echo BLUE, "\n";
在这里我们使用它。 请注意,常量前面没有$
美元字符。
echo defined("BLUE");
我们使用了另一个功能defined()
函数。 它检查是否存在特定常数。 如果是,则返回true
。
$ php constant.php
0000FF
1
运行示例将得到以上输出。
PHP 还具有一些预定义的常量。
predefined_constants.php
<?php
echo TRUE;
echo "\n";
echo PHP_VERSION;
echo "\n";
echo PHP_OS;
echo "\n";
echo __LINE__;
echo "\n";
echo __FILE__;
echo "\n";
echo DIRECTORY_SEPARATOR;
echo "\n";
echo PHP_DATADIR;
echo "\n";
在这里,我们打印一些内置的 PHP 常量。 例如,PHP_OS
常量打印构建 PHP 的 OS 版本。
$ php predefined_constants.php
1
5.6.17
Linux
9
/home/janbodnar/prog/php/basics/predefined_constants.php
/
/usr/local/share/php
在我们的系统上,我们得到此输出。
PHP 变量插值
变量插值正在用字符串字面值中的值替换变量。 变量插值的另一个名称是:变量替换或变量扩展。
interpolation.php
<?php
$age = 17;
echo "Jane is $age years old\n";
$age
变量用双引号括起来的字符串中的值 17 代替。
$ php interpolation.php
Jane is 17 years old
这是输出。
nointerpolation.php
<?php
$age = 17;
echo 'Jane is $age years old\n';
但是,如果我们使用单引号,则此方法不起作用。 在这种情况下,不会发生插值,也不会运行特殊字符。
$ php nointerpolation.php
Jane is $age years old\n
我们看到了字符串的逐字输出。
PHP 包括文件
PHP 代码被分成多个文件,以用于更大的程序。 我们使用include
语句来连接各种 PHP 文件。
common.php
<?php
define("VERSION", 1.12);
function get_max($x, $y) {
if ($x > $y) {
return $x;
} else {
return $y;
}
}
假设我们有一个common.php
文件,其中定义了一些常量和函数。
myfile.php
<?php
include "common.php";
echo "The version is " . VERSION . "\n";
$a = 5;
$b = 3;
echo get_max($a, $b), "\n";
我们还有另一个文件要使用上述定义。
include "common.php";
我们只需使用include
关键字将定义包含到文件中即可。 我们必须指定common.php
文件的确切路径。 在我们的简单情况下,两个文件都在同一目录中。
$ php myfile.php
The version is 1.12
5
这是输出。
本章介绍了 PHP 语言的一些基础知识。
PHP 数据类型
在 PHP 教程的这一部分中,我们将讨论数据类型。
计算机程序可以处理数据。 用于各种数据类型的工具是现代计算机语言的基本组成部分。 data type
是一组值以及对这些值的允许操作。
PHP 数据类型列表
PHP 具有八种数据类型:
标量类型
bool
int
float
string
复合类型
array
object
特殊类型
resources
null
与 Java,C 或 Visual Basic 等语言不同,PHP 中没有提供变量的显式类型定义。 变量的类型在运行时由 PHP 确定。 如果我们将字符串分配给变量,它将变成字符串变量。 稍后,如果我们分配一个整数值,该变量将成为一个整数变量。
PHP 布尔值
我们的世界建立了双重性。 有天与地,水与火,阴与阳,男人与女人,爱与恨。 在 PHP 中,布尔数据类型是具有以下两个值之一的原始数据类型:True
或False
。 这是基本的数据类型。
快乐的父母正在等待孩子的出生。 他们为两种可能性都选择了名称。 如果要成为男孩,他们选择了约翰。 如果要成为女孩,他们会选择维多利亚。
kid.php
<?php
$male = False;
$r = rand(0, 1);
$male = $r ? True: False;
if ($male) {
echo "We will use name John\n";
} else {
echo "We will use name Victoria\n";
}
该脚本使用随机整数生成器来模拟我们的情况。
$r = rand(0, 1);
rand()
函数从给定的整数边界返回一个随机数。 在我们的情况下为 0 或 1。
$male = $r ? True: False;
我们使用三元运算符设置$male
变量。 该变量基于随机$r
值。 如果$r
等于 1,则$male
变量设置为True
。 如果$r
等于 0,则$male
变量设置为False
。
if ($male) {
echo "We will use name John\n";
} else {
echo "We will use name Victoria\n";
}
我们打印名称。 if
命令适用于布尔值。 如果变量$male
为True
,则将"We will use name John"
打印到控制台。 如果其值为False
,我们将打印另一个字符串。
$ php kid.php
We will use name Victoria
$ php kid.php
We will use name John
$ php kid.php
We will use name Victoria
$ php kid.php
We will use name Victoria
该脚本运行了几次。
以下脚本显示了一些视为True
或False
的常见值。 例如,空字符串,空数组,0 被认为是False
。
boolean.php
<?php
class Object {};
var_dump((bool) "");
var_dump((bool) 0);
var_dump((bool) -1);
var_dump((bool) "PHP");
var_dump((bool) array(32));
var_dump((bool) array());
var_dump((bool) "false");
var_dump((bool) new Object());
var_dump((bool) NULL);
在此脚本中,我们在布尔上下文中检查一些值。 var_dump()
函数显示有关变量的信息。 (bool)
构建体称为转换。 在它的临时上下文中,0 值是一个数字。 在布尔上下文中,它为False
。 布尔上下文是当我们使用(布尔)强制转换,何时使用某些运算符(否定,比较运算符)以及何时使用if/else
,while
关键字时。
$ php boolean.php
bool(false)
bool(false)
bool(true)
bool(true)
bool(true)
bool(false)
bool(true)
bool(true)
bool(false)
这是脚本的结果。
PHP 整数
整数是实数的子集。 它们写时没有小数或小数部分。 整数落在集合Z = {...,-2,-1,0,1,2,...}
中。 整数是无限的。
在许多计算机语言中,整数是原始数据类型。 实际上,计算机只能使用整数值的子集,因为计算机的容量有限。 整数用于计算离散实体。 我们可以有 3、4、6 个人,但不能有 3.33 个人。 我们可以有 3.33 公斤。
在 PHP 中,可以使用四种不同的表示法指定整数:十进制,十六进制,八进制和二进制。 八进制值以0
开头,十六进制以0x
开头,二进制以0b
开头。
notation.php
<?php
$decimal_var = 31;
$octal_var = 031;
$hexadecimal_var = 0x31;
$binary_var = 0b01001110;
echo "$decimal_var\n";
echo "$octal_var\n";
echo "$hexadecimal_var\n";
echo "$binary_var\n";
我们定义了四个变量; 它们每个都有不同的整数符号。
$ php notation.php
31
25
49
78
默认符号是十进制。 脚本以十进制打印这四个数字。
PHP 中的整数具有固定的最大大小。 整数的大小取决于平台。 PHP 具有内置常量,可显示整数的最大大小。
$ uname -mo
x86_64 GNU/Linux
$ php -a
Interactive mode enabled
php> echo PHP_INT_SIZE;
8
php> echo PHP_INT_MAX;
9223372036854775807
在我的 64 位 Ubuntu Linux 系统上,整数值为 8 个字节。 最大值是 9223372036854775807。
在 Java 和 C 中,如果整数值大于允许的最大值,则发生整数溢出。 PHP 的工作方式不同。 在 PHP 中,整数变为浮点数。 浮点数具有更大的边界。
boundary.php
<?php
$var = PHP_INT_MAX;
echo var_dump($var);
$var++;
echo var_dump($var);
我们为$var
变量分配一个最大整数值。 我们将变量增加一。 var_dump()
函数转储有关给定变量的信息。
$ php boundary.php
int(9223372036854775807)
float(9.2233720368548E+18)
如前所述,在内部,数字成为浮点值。
在 Java 中,增加后的值为-2147483648。 这是整数溢出一词的来历。 该数字超过顶部并成为可分配给变量的最小负整数值。
如果我们使用整数,那么我们将处理离散实体。 例如,我们将使用整数来计算苹果。
apples.php
<?php
# number of baskets
$baskets = 16;
# number of apples in each basket
$apples_in_basket = 24;
# total number of apples
$total = $baskets * $apples_in_basket;
echo "There are total of $total apples \n";
在脚本中,我们计算了苹果的总量。 我们使用乘法运算。
$ php apples.php
There are total of 384 apples
脚本的输出。
PHP 浮点数
浮点数表示计算中的实数。 实数测量连续的数量,例如重量,高度或速度。 PHP 中的浮点数可以大于整数,并且可以具有小数点。 浮标的大小取决于平台。
我们可以使用各种语法来创建浮点值。
floats.php
<?php
$a = 1.245;
$b = 1.2e3;
$c = 2E-10;
$d = 1264275425335735;
var_dump($a);
var_dump($b);
var_dump($c);
var_dump($d);
在此示例中,我们有两种表示法的情况,科学家使用它们来表示浮点值。 另外$d
变量被分配了一个大数字,因此它会自动转换为浮点型。
$ php floats.php
float(1.245)
float(1200)
float(2.0E-10)
int(1264275425335735)
这是上述脚本的示例输出。
根据文档,不应对浮点数进行相等性测试。 我们将举例说明为什么。
$ php -a
Interactive mode enabled
php> echo 1/3;
0.33333333333333
php> $var = (0.33333333333333 == 1/3);
php> var_dump($var);
bool(false)
在此示例中,我们比较了两个看起来相同的值,但是它们产生了意外的结果。
假设一个短跑运动员跑了 100m,跑了 9.87s。 他的公里/小时速度是多少?
sprinter.php
<?php
# 100m is 0.1 km
$distance = 0.1;
# 9.87s is 9.87/60*60 h
$time = 9.87 / 3600;
$speed = $distance / $time;
echo "The average speed of a sprinter is $speed \n";
在此示例中,必须使用浮点值。
$speed = $distance / $time;
为了获得速度,我们将距离除以时间。
$ php sprinter.php
The average speed of a sprinter is 36.474164133739
这是sprinter
脚本的输出。 36.474164133739 是浮点数。
通常需要舍入浮点数。
rounding.php
<?php
$a = 1.4567;
echo round($a, 2) . "\n";
echo round($a, 3) . "\n";
echo sprintf("%0.3f", $a) . "\n" ;
In this example, it is necessary to use floating point values.
echo round($a, 2) . "\n";
echo round($a, 3) . "\n";
使用round()
函数,将浮点值四舍五入到两个和三个位置。
echo sprintf("%0.3f", $a) . "\n" ;
或者,我们也可以使用sprintf()
函数,该函数根据指定的格式化字符串对字符串进行格式化。
$ php rounding.php
1.46
1.457
1.457
这是rounding.php
脚本的输出。
PHP 字符串
字符串是一种数据类型,表示计算机程序中的文本数据。
由于字符串在每种编程语言中都非常重要,因此我们将为它们专门整整一章。 在这里,我们仅举一个小例子。
strings.php
<?php
$a = "PHP ";
$b = 'Perl';
echo $a, $b;
echo "\n";
我们可以使用单引号和双引号来创建字符串字面值。
$ php strings.php
PHP Perl
该脚本将两个字符串输出到控制台。 \n
是一个特殊的序列,换行。 此字符的效果就像在键入文本时按Enter
键一样。
PHP 数组
数组是处理元素集合的复杂数据类型。 每个元素都可以通过索引访问。 在 PHP 中,数组更为复杂。 数组可以视为数组,列表或字典。 换句话说,数组在其他语言中都是我们所谓的数组,列表,字典。
由于集合在所有计算机语言中都非常重要,因此我们将两章专门介绍集合-数组。 这里我们仅显示一个小例子。
arrays.php
<?php
$names = [ "Jane", "Lucy", "Timea", "Beky", "Lenka" ];
print_r($names);
使用速记符号创建一个数组,在此使用方括号。 数组的元素用逗号分隔。 元素是字符串。 print_r()
函数将有关变量的人类可读信息打印到控制台。
$ php arrays.php
Array
(
[0] => Jane
[1] => Lucy
[2] => Timea
[3] => Beky
[4] => Lenka
)
这是脚本的输出。 这些数字是指数,我们可以通过它们访问数组元素。
PHP 对象
到目前为止,我们一直在讨论内置数据类型。 对象是用户定义的数据类型。 程序员可以创建适合其域的数据类型。 在有关面向对象的程序设计(OOP)的一章中,有关对象的更多信息。
PHP 资源
资源是特殊的数据类型。 他们拥有对外部资源的引用。 它们是由特殊功能创建的。 资源是打开文件,数据库连接或图像画布区域的处理器。
PHP NULL
还有另一种特殊的数据类型-NULL
。 基本上,数据类型表示不存在,未知或为空。
在 PHP 中,在三种情况下,变量为NULL
:
- 它没有分配值
- 它被分配了一个特殊的
NULL
常量 - 它是用
unset()
函数取消设置的
nulltype.php
<?php
$a;
$b = NULL;
$c = 1;
unset($c);
$d = 2;
if (is_null($a)) echo "\$a is null\n";
if (is_null($b)) echo "\$b is null\n";
if (is_null($c)) echo "\$c is null\n";
if (is_null($d)) echo "\$d is null\n";
在我们的示例中,我们有四个变量。 其中三个被认为是NULL
。 我们使用is_null()
函数来确定变量是否为NULL
。
$ php nulltype.php
$a is null
$b is null
$c is null
这是脚本的结果。
PHP 类型转换
我们经常一次处理多种数据类型。 将一种数据类型转换为另一种数据类型是编程中的常见工作。 类型转换或类型转换是指将一种数据类型的实体更改为另一种。 有两种转换类型:隐式转换和显式转换。 隐式类型转换,也称为强制转换,是编译器自动进行的类型转换。
php> echo "45" + 12;
57
php> echo 12 + 12.4;
24.4
在上面的示例中,我们有两个隐式类型转换的示例。 在第一个语句中,字符串将转换为整数并添加到第二个操作数。 如果两个操作数中的任何一个都是浮点数,则两个操作数都将被求值为浮点数,结果将是一个浮点数。
当我们使用诸如(boolean)
之类的强制转换构造时,会发生显式转换。
php> $a = 12.43;
php> var_dump($a);
float(12.43)
php> $a = (integer) $a;
php> var_dump($a);
int(12)
php> $a = (string) $a;
php> var_dump($a);
string(2) "12"
php> $a = (boolean) $a;
php> var_dump($a);
bool(true)
此代码段显示了实际的强制转换。 首先,我们将浮点值分配给变量。 稍后我们将其转换为整数,字符串,最后转换为布尔数据类型。
在 PHP 教程的这一部分中,我们介绍了 PHP 数据类型。
PHP 字符串
在 PHP 编程教程的这一部分中,我们将更详细地处理字符串数据。
字符串是计算机语言中非常重要的数据类型。 这就是为什么我们将一整章专门讨论在 PHP 中使用字符串的原因。
PHP 字符串字面值
字符串字面值是表示计算机程序文本内的字符串值的符号。 在 PHP 中,可以使用单引号,双引号或使用 heredoc 或 nowdoc 语法创建字符串。
literals.php
<?php
$a = "PHP";
$b = 'PERL';
echo $a, $b;
在此代码示例中,我们创建两个字符串并将它们分配给$a
和$b
变量。 我们用echo
关键字打印它们。 第一个字符串使用双引号定界符创建,第二个字符串使用单引号定界符。
下一个示例将使用 heredoc 语法创建一个字符串。 Heredoc 保留文本中的换行符和其他空格(包括缩进)。 heredoc 使用<<<
来创建,后跟定界标识符,然后从下一行开始,在要引用的文本之后,再在同一行中以相同的标识符关闭。 结束标识符不能缩进。 它只能包含字母数字字符和下划线,并且必须以非数字字符或下划线开头。
heredoc.php
<?php
$str = <<<TEXT
"That is just as I intended." Vautrin said. "You know quite well what
you are about. Good, my little eaglet! You are born to command, you
are strong, you stand firm on your feet, you are game! I respect you."
TEXT;
echo $str, "\n";
该示例打印直接语音的示例。
$ php heredoc.php
"That is just as I intended." Vautrin said. "You know quite well what
you are about. Good, my little eaglet! You are born to command, you
are strong, you stand firm on your feet, you are game! I respect you."
这是示例的输出。
nowdoc 的指定方式与 Heredoc 相似,但是在 nowdoc 内部未进行任何解析。 nowdoc 的标识与 Heredocs 所使用的序列相同<<<
,但是后面的标识符用单引号引起来,例如<<<'TEXT'
。
nowdoc.php
<?php
$str = <<<'TEXT'
Fear is among the greatest obstacles which prevent us from enjoying life
to its fullest extent. Since of the most commonly held fears among
people are the fear of heights and the fear of falling from heights.
Rock climbing is a fantastic way to conquer these fears.
TEXT;
echo $str, "\n";
该示例使用 nowdoc 语法打印三个句子。
$ php nowdoc.php
Fear is among the greatest obstacles which prevent us from enjoying life
to its fullest extent. Since of the most commonly held fears among
people are the fear of heights and the fear of falling from heights.
Rock climbing is a fantastic way to conquer these fears.
这是nowdoc.php
脚本的输出。
PHP 插值
变量被插入双引号中的字符串中。
interpolation.php
<?php
$quantity = 5;
echo "There are $quantity roses in the vase\n";
$quantity
变量将在字符串输出中替换为其值。
$ php interpolation.php
There are 5 roses in the vase
这是interpolation.php
脚本的输出。
当变量名称位于另一个字符旁边时,可以使用大括号。
curlybraces.php
<?php
$quantity = 5;
$item_name = "rose";
echo "There are $quantity {$item_name}s in the vase\n";
没有花括号,PHP 解释器将查找$item_names
变量,该变量不存在。
$ php curlybraces.php
There are 5 roses in the vase
这是curlybraces.php
脚本的输出。
PHP 字符串连接
PHP 使用点.
运算符来连接字符串。
php > echo "PHP " . "language\n";
PHP language
该示例连接了两个字符串。
php > $a = "Java ";
php > $a .= "language\n";
php > echo $a;
Java language
PHP 还支持.=
复合运算符。
PHP 转义字符
转义字符是指定用于对字符序列中紧随其后的字符调用替代解释的单个字符。
php> echo " bbb\raaa";
aaabbb
回车\r
是控制字符,用于将行尾返回到行首。
strophe.php
<?php
echo "Incompatible, it don't matter though\n'cos someone's bound to hear my cry\n";
echo "Speak out if you do\nYou're not easy to find\n";
新行是一个控制字符,它开始一行新文本。
$ php strophe.php
Incompatible, it don't matter though
'cos someone's bound to hear my cry
Speak out if you do
You're not easy to find
这是strophe.php
脚本的输出。
php> echo "Towering\tinferno\n";
Towering inferno
水平选项卡在文本之间放置一个空格。
"Johnie's dog"
'Johnie\'s dog'
单引号和双引号可以嵌套。 或者,如果仅使用单引号,则可以使用反斜杠来转义单引号的默认含义。
backslash.php
<?php
$text = "
\"That is just as I intended.\" Vautrin said. \"You know quite well what
you are about. Good, my little eaglet! You are born to command, you
are strong, you stand firm on your feet, you are game! I respect you.\"
";
echo $text;
在此示例中,我们有一个多行文本,其中包括直接语音。 双引号用反斜杠字符转义。
php> $var = 233;
php> echo "$var";
233
php> echo "\$var is $var";
$var is 233
美元符号$
在 PHP 中也有特殊含义; 它表示一个变量。 如果在字符串中使用了变量,则会对其进行插值,即使用变量的值。 为了回显变量名,我们转义了$
字符\$
。
PHP 字符串操作
PHP 具有大量有用的有用内置函数,可用于处理字符串。
echo strlen("Eagle"); # prints 5
echo strtoupper("Eagle"); # prints EAGLE
echo strtolower("Eagle"); # prints eagle
在这里,我们使用三个函数。 strlen()
函数返回字符串中的许多字符。 strtoupper()
将字符转换为大写字母,strtolower()
将字符转换为小写字母。
letters.php
<?php
$sentence = "There are 22 apples";
$alphas = 0;
$digits = 0;
$spaces = 0;
$length = strlen($sentence);
for ($i = 0; $i < $length; $i++) {
$c = $sentence[$i];
if (ctype_alpha($c)) $alphas++;
if (ctype_digit($c)) $digits++;
if (ctype_space($c)) $spaces++;
}
echo "There are $length characters.\n";
echo "There are $alphas alphabetic characters.\n";
echo "There are $digits digits.\n";
echo "There are $spaces spaces.\n";
在我们的示例中,我们有一个字符串句子。 我们计算句子中的绝对字符数,字母字符数,数字和空格。 为此,我们使用以下函数:strlen()
,ctype_alpha()
,ctype_digit()
和ctype_space()
。
$ php letters.php
There are 19 characters.
There are 14 alphabetic characters.
There are 2 digits.
There are 3 spaces.
这是letters.php
脚本的输出。
接下来,我们介绍substr()
函数。
echo substr("PHP language", 0, 3); # prints PHP
echo substr("PHP language", -8); # prints language
该函数返回字符串的一部分。 第一个参数是指定的字符串。 第二个参数是子字符串的开头。 第三个参数是可选的。 它是返回的子字符串的长度。 默认值为返回到字符串末尾。
str_repeat()
函数将字符串重复指定的次数。
repeat.php
<?php
echo str_repeat("#", 18);
echo "\nProject Neurea\n";
echo "Priority high\n";
echo "Security maximum\n";
echo str_repeat("#", 18);
echo "\n";
我们使用str_repeat()
函数创建两行#
字符。
$ php repeat.php
##################
Project Neurea
Priority high
Security maximum
##################
这是repeat.php
脚本的输出。
在下一个示例中,我们将随机修改一个字符串。
shuffling.php
<?php
$string = "ZetCode";
echo str_shuffle($string), "\n";
echo str_shuffle($string), "\n";
echo str_shuffle($string), "\n";
echo str_shuffle($string), "\n";
echo str_shuffle($string), "\n";
echo str_shuffle($string), "\n";
echo str_shuffle($string), "\n";
str_shuffle()
随机随机播放一个字符串。
$ php shuffling.php
ZtCeoed
eodtCZe
toZeeCd
oCdeteZ
edtCZoe
tdeCeoZ
oeZdteC
这是shuffling.php
脚本的示例输出。
explode()
函数用于将字符串分成多个部分。 它返回一个分割字符串部分的数组。
exploding.php
<?php
$nums = "1,2,3,4,5,6,7,8,9,10,11";
$vals = explode(",", $nums);
$len = count($vals);
echo "There are $len numbers in the string\n";
字符串中包含整数,并用逗号分隔。 我们计算整数的数量。
$vals = explode(",", $nums);
在这里,我们使用explode()
函数分割文本。 每当找到点,
字符时,该函数就会将其切成小段。
$ php exploding.php
There are 11 numbers in the string
示例的输出。
teams1.php
<?php
echo "Ajax Amsterdam" . " - " . "Inter Milano " . "2:3\n";
echo "Real Madridi" . " - " . "AC Milano " . "3:3\n";
echo "Dortmund" . " - " . "Sparta Praha ". "2:1\n";
我们用点运算符连接字符串。
$ php teams1.php
Ajax Amsterdam - Inter Milano 2:3
Real Madridi - AC Milano 3:3
Dortmund - Sparta Praha 2:1
输出不是最佳的。 我们将对其进行更改,以使其看起来更整洁。
teams2.php
<?php
$teams = array(
array("Ajax Amsterdam", "Inter Milano"),
array("Real Madrid", "AC Milano"),
array("Dortmund", "Sparta Praha")
);
$results = array("2:3", "3:3", "2:1");
$i = 0;
foreach ($teams as $team) {
echo str_pad($team[0], 14);
echo str_pad("-", 3, " ", STR_PAD_BOTH);
echo str_pad($team[1], 14);
echo str_pad($results[$i], 3, " ", STR_PAD_LEFT);
echo "\n";
$i++;
}
我们使用str_pad()
函数改善了输出格式。 它将在字符串的左侧,右侧或两侧添加指定的字符串(在我们的示例中为空格)。
$ php teams2.php
Ajax Amsterdam - Inter Milano 2:3
Real Madrid - AC Milano 3:3
Dortmund - Sparta Praha 2:1
我们设法提供了更好的格式化输出。
字符数组
PHP 中的字符串是一个字符数组。
array_of_chars.php
<?php
$site = "zetcode.com";
for ($i=0; $i < strlen($site); $i++) {
$o = ord($site[$i]);
echo "$site[$i] has ASCII code $o\n";
}
在示例中,我们遍历字符串并打印每个字符的 ASCII 码。
$site = "zetcode.com";
定义了一个字符串。 它包含十一个字符。
for ($i=0; $i < strlen($site); $i++) {
$o = ord($site[$i]);
echo "$site[$i] has ASCII code $o\n";
}
我们使用for
循环遍历字符串。 字符串的大小由strlen()
函数确定。 ord()
函数返回字符的 ASCII 值。 我们使用数组索引符号来获取字符。
$ php array_of_chars.php
z has ASCII code 122
e has ASCII code 101
t has ASCII code 116
c has ASCII code 99
o has ASCII code 111
d has ASCII code 100
e has ASCII code 101
. has ASCII code 46
c has ASCII code 99
o has ASCII code 111
m has ASCII code 109
这是array_of_chars.php
示例的输出。
PHP 字符串格式化
字符串格式化或字符串插值是将各种值动态地放入字符串中。
fruits.php
<?php
printf("There are %d oranges and %d apples in the basket.\n", 12, 32);
我们使用%d
格式说明符。 指定者希望传递一个整数值。
$ php fruits.php
There are 12 oranges and 32 apples in the basket.
在下一个示例中,我们传递一个float
和一个字符串值。
height.php
<?php
printf("Height: %f %s\n", 172.3, "cm");
浮点值的格式说明符为%f
,字符串为%s
。
$ php height.php
Height: 172.300000 cm
我们可能不喜欢上面示例中的数字默认情况下具有 6 个小数位的事实。 我们可以控制格式说明符中的小数位数。
height2.php
<?php
printf("Height: %.1f %s\n", 172.3, 'cm');
小数点后跟一个整数控制小数位数。 在我们的例子中,数字恰好有一位小数。
$ php height2.php
Height: 172.3 cm
下面的示例显示其他格式设置选项。
formatting.php
<?php
# hexadecimal
printf("%x\n", 300);
# octal
printf("%o\n", 300);
# scientific
printf("%e\n", 300000);
第一种格式适用于十六进制数字。 x
字符以十六进制格式格式化数字。 o
字符以八进制格式显示数字。 e
字符以科学格式显示数字。
$ php formatting.php
12c
454
3.000000e+5
下一个示例显示三列数字。
columns.php
<?php
foreach (range(1,11) as $num) {
echo $num , " ", $num*$num, " ",
$num*$num*$num, "\n";
}
数字左对齐,输出不整齐。
$ php columns.php
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
11 121 1331
为了解决这个问题,我们使用宽度说明符。 宽度说明符定义对象的最小宽度。 如果对象小于宽度,则将填充空格。
columns2.php
<?php
foreach (range(1,11) as $num) {
printf("%2d %3d %4d\n", $num, $num*$num, $num*$num*$num);
}
现在输出看起来正常。 数字 2 表示第一列的宽度为 2 个字符。
$ php columns2.php
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
11 121 1331
PHP 教程的这一部分介绍了字符串。
PHP 运算符
在 PHP 编程教程的这一部分中,我们讨论 PHP 运算符。
运算符是特殊符号,表示已执行某个过程。 编程语言的运算符来自数学。 程序员处理数据。 运算符用于处理数据。
PHP 运算符类型
我们有几种类型的运算符:
- 算术运算符
- 布尔运算符
- 关系运算符
- 按位运算符
一个运算符可以有一个或两个操作数。 操作数是运算符的输入(参数)之一。 仅使用一个操作数的那些运算符称为一元运算符。 那些使用两个操作数的对象称为二进制运算符。
+和-可以是加减运算符,也可以是一元符号运算符。 这取决于实际情况。
php> print +2;
2
php> print -2;
-2
php> print 2;
2
php> print 2+2;
4
php> print 2-2;
0
加号可用于表示我们有一个正数,但通常不使用它。 减号更改值的符号。
php> $a = 1;
php> print -$a;
-1
php> print -(-$a);
1
乘法和加法运算符是二进制运算符的示例。 它们与两个操作数一起使用。
php> print 3 * 3;
9
php> print 3 + 3;
6
PHP 赋值运算符
赋值运算符=
将值赋给变量。 variable
是值的占位符。 在 PHP 中,变量以$
字符开头。 (在数学上,=
运算符具有不同的含义。在一个方程式中,=
运算符是一个相等运算符。该方程式的左侧等于右侧的等式。)
php> $x = 1;
php> print $x;
1
在这里,我们为$x
变量分配一个数字。
php> $x = $x + 1;
php> print $x;
2
先前的表达式在数学上没有意义,但是在编程中是合法的。 该表达式意味着我们向$x
变量加 1。 右边等于 2,并且 2 分配给$x
。
php> 3 = $x;
Parse error: syntax error, unexpected '=' in php shell code on line 1
此代码示例导致语法错误。 我们无法为字面值分配值。
PHP 算术运算符
下表是 PHP 中的算术运算符表。
符号 | 名称 |
---|---|
+ |
加法 |
- |
减法 |
* |
乘法 |
/ |
除法 |
% |
模数 |
以下示例显示了算术运算。
arithmetic.php
<?php
$a = 10;
$b = 11;
$c = 12;
$add = $a + $b + $c;
$sub = $c - $a;
$mult = $a * $b;
$div = $c / 3;
echo "$add $sub $mult $div\n";
所有这些都是数学上已知的运算符。
$ php arithmetic.php
33 2 110 4
%
运算符称为模运算符。 它找到一个数除以另一个的余数。
php> print 9 % 4;
1
9 % 4
,9 模 4 为 1,因为 4 两次进入 9 且余数为 1。
PHP 计算素数
质数是大于 1 的整数,只能被 1 或本身平均除。
primes.php
<?php
$nums = range(0, 100, 1);
foreach ($nums as $n) {
if ($n <= 1) continue;
if ($n == 2 or $n == 3) {
echo "$n ";
continue;
}
$i = (int) sqrt($n);
$isPrime = true;
while ($i > 1) {
if ($n % $i == 0) {
$isPrime = False;
}
$i--;
}
if ($isPrime == True) {
echo "$n ";
}
}
echo "\n";
模运算符用于计算素数。 计算素数的算法是这样的:我们选取一个数字并将其除以数字,从 1 到选取的数字。 已经证明,我们不需要尝试所有较小的数字。 尝试数字直到所选数字的平方根就足够了。
$nums = range(0, 100, 1);
我们使用range()
函数创建一个从 0 到 100 的整数数组。
if ($n <= 1) continue;
根据定义,素数是大于 1 的数; 因此,我们跳过计算并继续下一个数字。
if ($n == 2 or $n == 3) {
echo "$n ";
continue;
}
数字 2 和 3 是质数。
$i = (int) sqrt($n);
如果我们仅尝试小于数字平方根的数字,那就可以了。
while ($i > 1) {
...
}
使用while
循环。 $i
是计算出的数字的平方根。 我们使用减量运算符将每个循环周期的$i
减 1。 当$i
小于 1 时,我们终止循环。 例如,我们有 9。9 的平方根是 3。我们将 9 除以 3 和 2。
if ($n % $i == 0) {
$isPrime = False;
}
这是算法的核心。 如果对于任何$i
值,余数除法运算符返回 0,则说明的数字不是质数。
$ php primes.php
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
这些是 0 到 100 之间的质数。
PHP 连接字符串
我们使用点.
运算符来连接字符串。
php> print 'return' . 'of' . 'the' . 'king';
returnoftheking
点运算符从四个字符串中得出一个字符串。
php> print 3 . 'apples';
3apples
我们可以使用点运算符将字符串与数字连接起来。 在内部,数字将转换为字符串,最后将两个字符串连接在一起。
php> print 'apples' * 3;
0
php> print 'apples' - 'oranges';
0
php> print 'apples' + 'oranges';
0
对字符串使用其他运算符没有多大意义; 我们得到零。
php> print (Integer) 'apple';
0
这是因为在数字上下文中,字符串等于零。
PHP 布尔运算符
在 PHP 中,我们有and
,or
和否定!
布尔运算符。 使用布尔运算符,我们可以执行逻辑运算。 这些常与if
和while
关键字一起使用。
andop.php
<?php
$a = (True and True);
$b = (True and False);
$c = (False and True);
$d = (False and False);
var_dump($a, $b, $c, $d);
此示例显示了逻辑and
运算符。 仅当两个操作数均为True
时,逻辑和运算符才求值为True
。
$ php andop.php
bool(true)
bool(false)
bool(false)
bool(false)
如果两个操作数中的任何一个为True
,则逻辑or
运算符的计算结果为True
。
orop.php
<?php
$a = (True or True);
$b = (True or False);
$c = (False or True);
$d = (False or False);
var_dump($a, $b, $c, $d);
如果运算符的任一侧为True
,则运算结果为True
。
$ php orop.php
bool(true)
bool(true)
bool(true)
bool(false)
否定运算符!
设为True False
和False True
。
negation.php
<?php
$a = ! False;
$b = ! True;
$c = ! (4<3);
var_dump($a, $b, $c);
该示例显示了否定运算符的作用。
$ php negation.php
bool(true)
bool(false)
bool(true)
并且,或者对短路进行了求值。 短路求值意味着仅当第一个参数不足以确定表达式的值时,才求值第二个参数:当和的第一个参数求值为false
时,总值必须为false
; 当或的第一个参数为true
时,总值必须为true
。
一个典型的例子如下。
shortcircuit.php
<?php
$x = 10;
$y = 0;
if ($y != 0 and x/y < 100) {
echo "a small value";
}
表达式的第一部分计算为False
。 表达式的第二部分不计算。 否则,我们将得到除以零的错误。
PHP 关系运算符
关系运算符用于比较值。 这些运算符总是产生布尔值。
符号 | 含义 |
---|---|
< |
小于 |
<= |
小于或等于 |
> |
大于 |
>= |
大于或等于 |
== |
等于 |
!= 或<> |
不等于 |
=== |
相同 |
!== |
不相同 |
该表显示了八个 PHP 关系运算符。
php> var_dump(3 < 4);
bool(true)
php> var_dump(3 == 4);
bool(false)
php> var_dump(4 >= 3);
bool(true)
正如我们已经提到的,关系运算符返回布尔值。
注意,关系运算符不限于数字。 我们也可以将它们用于其他对象。 尽管它们可能并不总是有意义的。
php> var_dump("six" == "six");
bool(true)
php> var_dump("a" > 6);
bool(false)
php> var_dump('a' < 'b');
bool(true)
我们也可以比较字符串对象。 我们可以将关系运算符用于不同的对象类型。 在我们的例子中,我们将字符串与数字进行比较。
php> var_dump('a' < 'b');
这里到底发生了什么? 计算机不知道字符或字符串。 对于他们来说,一切都只是数字。 字符是存储在特定表中的特殊数字,例如 ASCII。 因此,最后,将比较两个 ASCII 数字。 由于 a 在 b 之前,因此它的数字较小,因此该操作返回true
。
compare.php
<?php
echo 'a' < 'b';
echo "\n";
echo 'a is:', ord('a');
echo "\n";
echo 'b is:', ord('b');
echo "\n";
在内部,a
和b
字符是数字。 因此,当我们比较两个字符时,我们将比较它们的存储数字。 内置的ord()
函数返回单个字符的 ASCII 值。
$ php compare.php
1
a is:97
b is:98
实际上,我们比较两个数字:97 与 98。
php> print "ab" > "aa";
1
假设我们有一个包含更多字符的字符串。 如果前几个字符相等,则比较下一个字符。 在我们的情况下,第二个位置的b
字符的值比a
字符大。 这就是为什么"ab"
字符串大于"aa"
字符串的原因。 当然,以这种方式比较字符串没有多大意义。 但这在技术上是可能的。
PHP 赋值,相等和身份
您可能会注意到,有一个符号运算符=
,两个符号运算符==
和三个符号===
运算符。 现在我们将讨论这些运算符之间的区别。
一个符号=
运算符是赋值运算符。 它将值加载到变量。
php > $a = 6;
php > echo $a;
6
在示例中,我们为$a
变量分配值 6。 $a
变量现在包含数字 6。 我们可以使用echo
命令显示$a
变量的内容。
两个符号==
运算符是宽松相等运算符。 它用于测试所讨论的值是否相等。 请注意,使用此运算符时,PHP 解释器会进行一些隐式转换。 这导致一些非直觉的结果。
php> var_dump(false == 0);
bool(true)
php> var_dump(false == array());
bool(true)
php> var_dump(true == 1);
bool(true)
php> var_dump(true == "string");
bool(true)
php> var_dump(117 == "000117");
bool(true)
对于许多来自其他语言的程序员,初学者或程序员来说,这些结果可能令人惊讶。 如果将数字与字符串进行比较,或者比较涉及数字字符串,则每个字符串都将转换为数字,然后以数字方式进行比较。
三个符号===
运算符是严格比较运算符。 它称为身份运算符。 仅当操作数的值相同且类型相同时,此运算符才返回true
。
php> var_dump(false === 0);
bool(false)
php> var_dump(false === array());
bool(false)
php> var_dump(true === 1);
bool(false)
php> var_dump(true === "string");
bool(false)
php> var_dump(117 === "000117");
bool(false)
如我们所见,身份运算符返回相反的结果。 该运算符更直观,使用更安全。
PHP 按位运算符
小数对人类是自然的。 二进制数是计算机固有的。 二进制,八进制,十进制或十六进制符号仅是数字符号。 按位运算符使用二进制数的位。 我们还有二进制逻辑运算符和移位运算符。
很少在高级语言(如 PHP)中使用按位运算符。
符号 | 含义 |
---|---|
~ |
按位取反 |
^ |
按位异或 |
& |
按位与 |
| |
按位或 |
<< |
左移 |
>> |
右移 |
按位取反运算符分别将 1 更改为 0,将 0 更改为 1。
php> print ~7;
-8
php> print ~-8;
7
运算符恢复数字 7 的所有位。这些位之一还确定数字是否为负。 如果我们再一次对所有位取反,我们将再次得到 7。
按位,运算符在两个数字之间进行逐位比较。 仅当操作数中的两个对应位均为 1 时,位位置的结果才为 1。
00110
& 00011
= 00010
第一个数字是二进制符号 6,第二个数字是 3,结果是 2。
php> print 6 & 3;
2
php> print 3 & 6;
2
按位或运算符在两个数字之间进行逐位比较。 如果操作数中的任何对应位为 1,则位位置的结果为 1。
00110
| 00011
= 00111
结果为00110
或十进制 7。
php> print 6 | 3;
7
按位互斥或运算符在两个数字键之间执行逐位比较。 如果操作数中对应位中的一个或另一个(但不是全部)为 1,则位位置的结果为 1。
00110
^ 00011
= 00101
结果为00101
或十进制 5。
php> print 6 ^ 3;
5
最后,我们还有按位移位运算符。 按位移位运算符向右或向左移位。
number << n : multiply number 2 to the nth power
number >> n : divide number by 2 to the nth power
这些运算符也称为算术移位。
00110
>> 00001
= 00011
我们将数字 6 的每个位向右移动。 等于将 6 除以 2。结果为00011
或十进制 3。
php> print 6 >> 1;
3
00110
<< 00001
= 01100
我们将数字 6 的每个位向左移动。 等于将数字 6 乘以 2。结果为01100
或十进制 12。
php> print 6 << 1;
12
PHP 复合赋值运算符
复合赋值运算符由两个运算符组成。 他们是速记员。
php> $i = 1;
php> $i = $i + 1;
php> print $i;
2
php> $i += 1;
php> print $i;
3
+=
复合运算符是这些速记运算符之一。 它们比完整的表达式可读性差,但是经验丰富的程序员经常使用它们。
其他复合运算符是:
-= *= .= /= %= &= |= ^= >>= <<=
PHP 运算符优先级
运算符优先级告诉我们首先求值哪个运算符。 优先级对于避免表达式中的歧义是必要的。
以下表达式 28 或 40 的结果是什么?
3 + 5 * 5
像数学中一样,乘法运算符的优先级高于加法运算符。 结果是 28。
(3 + 5) * 5
要更改求值顺序,可以使用方括号。 方括号内的表达式始终首先被求值。
以下列表显示了按优先级排序的常见 PHP 运算符(优先级最高):
运算符 | 描述 |
---|---|
++ -- |
增减 |
(int) (float) (string) (array) (object) (bool) |
转型 |
! |
逻辑非 |
* / % |
算术 |
+ - . |
算术和字符串 |
<< >> |
按位 |
< <= > >= <> |
比较 |
== != === !== |
比较 |
&& |
逻辑“与” |
|| |
逻辑或 |
? : |
三元运算符 |
= += -= *= /= .= %= |
赋值 |
and |
逻辑与 |
xor |
逻辑异或 |
or |
逻辑或 |
, |
逗号运算符 |
列表中同一行上的运算符具有相同的优先级。
precedence.php
<?php
print 3 + 5 * 5;
print "\n";
print (3 + 5) * 5;
print "\n";
var_dump(! True or True);
var_dump(! (True or True));
在此代码示例中,我们显示一些常见的表达式。 每个表达式的结果取决于优先级。
var_dump(! True or True);
在这种情况下,否定运算符具有更高的优先级。 首先,将第一个True
值取反为False
,然后 OR 运算符组合False
和True
,最后得到True
。
$ php precedence.php
28
40
bool(true)
bool(false)
关系运算符的优先级高于逻辑运算符。
positive.php
<?php
$a = 1;
$b = 2;
if ($a > 0 and $b > 0) {
echo "\$a and \$b are positive integers\n";
}
和运算符等待两个布尔值。 如果其中一个操作数不是布尔值,则会出现语法错误。
$ php positive.php
$a and $b are positive integers
PHP 关联规则
有时,优先级不能令人满意地确定表达式的结果。 还有另一个规则称为关联性。 运算符的关联性确定优先级与相同的运算符的求值顺序。
9 / 3 * 3
此表达式的结果是 9 还是 1? 乘法,删除和模运算符从左到右关联。 因此,该表达式的计算方式为:(9 / 3) * 3
,结果为 9。
算术,布尔,关系和按位运算符都是从左到右关联的。
另一方面,赋值运算符是正确关联的。
php> $a = $b = $c = $d = 0;
php> echo $a, $b, $c, $d;
0000
如果关联从左到右,则以前的表达式将不可能。
复合赋值运算符从右到左关联。
php> $j = 0;
php> $j *= 3 + 1;
php> print $j;
0
您可能期望结果为 1,但是由于关联性,实际结果为 0。 首先求值右边的表达式,然后应用复合赋值运算符。
PHP 中的其他运算符
PHP 具有沉默(@
)运算符。 它用于关闭错误消息。 它通常与网络或数据库连接一起使用。 请谨慎使用此运算符,因为它可能导致调试问题。
php> echo 3 / 0;
Warning: Division by zero in php shell code on line 1
php> echo @ (3 / 0);
php>
在第一种情况下,我们收到除以零的错误消息。 在第二种情况下,@
运算符将关闭错误消息。
引用(&)运算符。 它创建对对象的引用。
php> $a = 12;
php> $b = &$a;
php> echo $b;
12
php> $b = 24;
php> echo $b;
24
php> echo $a;
24
在上面的示例中,我们将值传递给$a
变量,并将对$a
的引用传递给$b
变量。
php> $b = &$a;
我们创建一个指向$a
变量的新变量$b
。 换句话说,我们为$a
变量创建一个别名。
php> $b = 24;
php> echo $b;
24
php> echo $a;
24
为$b
分配新值也会影响$a
。
反引号()运算符用于执行命令。 它与
shell_exec()`函数调用相同。
php> $list = `ls -l | head -3`;
php> echo $list;
total 52
-rw-rw-r-- 1 janbodnar janbodnar 130 Jan 19 11:35 andop.php
-rw-rw-r-- 1 janbodnar janbodnar 140 Jan 19 11:21 arithmetic.php
我们执行ls
命令,该命令在 Unix 系统上列出当前目录的内容。
在 PHP 教程的这一部分中,我们介绍了 PHP 运算符。
PHP 中的控制流
在 PHP 教程的这一部分中,我们讨论流控制。 我们定义了几个关键字,这些关键字使我们能够控制 PHP 脚本的流程。
PHP if
语句
if
语句具有以下一般形式:
if (expression)
statement
if
关键字用于检查表达式是否为真。 如果为true
,则执行一条语句。 该语句可以是单个语句或复合语句。 复合语句由用大括号括起来的多个语句组成。
ifstatement.php
<?php
$num = 31;
if ($num > 0)
echo "\$num variable is positive\n";
我们有一个$num
变量。 它分配了值 31。if
关键字检查布尔表达式。 表达式放在方括号之间。 表达式31 > 0
为true
,因此将执行下一条语句。 如果只有一条语句要执行,则花括号是可选的。
$ php ifstatement.php
$num variable is positive
这是示例的输出。
ifstatement2.php
<?php
$num = 31;
if ($num > 0) {
echo "\$num variable is positive\n";
echo "\$num variable equals to $num\n";
}
如果我们打算执行多个语句,则必须将它们放在方括号内。 如果我们不使用它们,则只会执行第一条语句。 圆括号形成了if
语句的主体。
我们可以使用else
关键字来创建一个简单的分支。 如果if
关键字后面方括号内的表达式的值为false
,则else
主体内的语句将自动执行。
boyorgirl.php
<?php
$sex = "female";
if ($sex == "male") {
echo "It is a boy\n";
} else {
echo "It is a girl\n";
}
我们有一个$sex
变量。 它具有"female"
字符串。 布尔表达式的计算结果为false
,我们在控制台中得到"It is a girl"
。
$ php boyorgirl.php
It is a girl
This is the output of the example.
我们可以使用elseif
关键字创建多个分支。 仅当不满足先前条件时,elseif
关键字才会测试其他条件。 请注意,我们可以在测试中使用多个elseif
关键字。
ifelsestm.php
<?php
echo "Enter a number: ";
$a = intval(fgets(STDIN));
if ($a < 0) {
printf("%d is a negative number\n", $a);
} elseif ($a == 0) {
printf("%d is a zero\n", $a);
} elseif ($a > 0) {
printf("%d is a positive number\n", $a);
}
我们使用fgets()
函数从用户读取一个值。 将测试该值是负数还是正数或等于零。
$ php ifelsestm.php
Enter a number: 4
4 is a positive number
$ php ifelsestm.php
Enter a number: -3
-3 is a negative number
程序的示例输出。
PHP switch
语句
switch
语句是选择控制流语句。 它允许变量或表达式的值通过多路分支控制程序执行的流程。 与使用if
和elseif
语句相比,它以更简单的方式创建多个分支。
switch
语句与其他两个关键字一起使用:case
和break
。 case
关键字用于根据圆括号中的值测试标签。 如果标签等于该值,则执行案例后面的语句。 break
关键字用于跳出switch
语句。 有一个可选的default
语句。 如果所有标签都不等于该值,则执行默认语句。
domains.php
<?php
$domain = 'sk';
switch ($domain) {
case 'us':
echo "United States\n";
break;
case 'de':
echo "Germany\n";
break;
case 'sk':
echo "Slovakia\n";
break;
case 'hu':
echo "Hungary\n";
break;
default:
echo "Unknown\n";
break;
}
在我们的脚本中,我们有一个$domains
变量。 它具有"sk"
字符串。 我们使用switch
语句测试变量的值。 有几种选择。 如果该值等于"us"
,则将"United States"
字符串打印到控制台。
$ php domains.php
Slovakia
我们得到Slovakia
。 如果将$domains
变量更改为'rr'
,则会得到'Unknown'
字符串。
PHP while
循环
while
是一个控制流语句,它允许根据给定的布尔条件重复执行代码。
这是while
循环的一般形式:
while (expression):
statement
当表达式的值为真时,while
循环执行该语句。 该语句是一个简单的语句,以分号或用大括号括起来的复合语句终止。
whilestm.php
<?php
$i = 0;
while ($i < 5) {
echo "PHP language\n";
$i++;
}
在代码示例中,我们反复将"PHP language\n"
字符串打印到控制台。
while
循环包含三个部分:初始化,测试和更新。 语句的每次执行都称为循环。
$i = 0;
我们启动$i
变量。 它在我们的脚本中用作计数器。
while ($i < 5) {
...
}
方括号内的表达式是第二阶段,即测试。 while
循环在主体中执行语句,直到表达式的计算结果为false
。
$i++;
while
循环的最后第三阶段是更新。 计数器增加。 请注意,对while
循环的不正确处理可能会导致循环不断。
$ php whilestm.php
PHP language
PHP language
PHP language
PHP language
PHP language
该程序将消息打印到控制台五次。
do while
循环是while
循环的版本。 不同之处在于,保证该版本至少运行一次。
dowhile.php
<?php
$count = 0;
do {
echo "$count\n";
} while ($count != 0)
首先执行迭代,然后求值真值表达式。
while
循环通常与list()
和each()
函数一起使用。
seasons.php
<?php
$seasons = ["Spring", "Summer", "Autumn", "Winter"];
while (list($idx , $val) = each($seasons)) {
echo "$val\n";
}
$seasons
数组有四个季节。 我们浏览所有值并将它们打印到控制台。 each()
函数从数组返回当前键和值对,并前进数组光标。 当函数到达数组末尾时,它返回false
并终止循环。 each()
函数返回一个数组。 赋值的左侧也必须有一个数组。 我们使用list()
函数从两个变量创建一个数组。
$ php seasons.php
Spring
Summer
Autumn
Winter
这是seasons.php
脚本的输出。
PHP 关键字
for
循环与while
循环具有相同的作用。 只是将所有三个阶段(初始化,测试和更新)放在圆括号之间。 它主要用于在进入循环之前知道迭代次数的情况。
让我们举一个for
循环的例子。
forloop.php
<?php
$days = [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday", "Sunday" ];
$len = count($days);
for ($i = 0; $i < $len; $i++) {
echo $days[$i], "\n";
}
我们每周有几天。 我们希望从数组中打印所有这些天。
$len = count($days);
或者我们可以以编程方式找出数组中的项目数。
for ($i = 0; $i < $len; $i++) {
echo $days[$i], "\n";
}
这里我们有for
循环结构。 这三个阶段用分号分隔。 首先,启动$i
计数器。 启动部分仅发生一次。 接下来,进行测试。 如果测试结果为true
,则执行该语句。 最后,计数器增加。 这是一个周期。 for
循环迭代直到测试表达式为假。
$ php forloop.php
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
这是forloop.php
脚本的输出。
PHP foreach
语句
foreach
构造简化了遍历数据集合的过程。 它没有明确的计数器。 foreach
语句一个接一个地遍历数组,并将当前值复制到构造中定义的变量中。 在 PHP 中,我们可以使用它遍历数组。
foreachstm.php
<?php
$planets = [ "Mercury", "Venus", "Earth", "Mars", "Jupiter",
"Saturn", "Uranus", "Neptune" ];
foreach ($planets as $item) {
echo "$item ";
}
echo "\n";
在此示例中,我们使用foreach
语句遍历一系列行星。
foreach ($planets as $item) {
echo "$item ";
}
foreach
语句的用法很简单。 $planets
是我们迭代通过的数组。 $item
是具有数组中当前值的临时变量。 foreach
语句遍历所有行星并将它们打印到控制台。
$ php foreachstm.php
Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune
运行上面的 PHP 脚本将给出此输出。
foreach
语句还有另一种语法。 它与地图一起使用。
foreachstm2.php
<?php
$benelux = [ 'be' => 'Belgium',
'lu' => 'Luxembourgh',
'nl' => 'Netherlands' ];
foreach ($benelux as $key => $value) {
echo "$key is $value\n";
}
在我们的脚本中,我们有一个$benelux
映射。 它包含映射到比荷卢三国的域名。 我们遍历数组并将键及其值都打印到控制台。
$ php foreachstm2.php
be is Belgium
lu is Luxembourgh
nl is Netherlands
这是脚本的结果。
PHP break
,continue
语句
break
语句用于终止循环。 continue
语句用于跳过循环的一部分,并继续循环的下一个迭代。
testbreak.php
<?php
while (true) {
$val = rand(1, 30);
echo $val, " ";
if ($val == 22) break;
}
echo "\n";
我们定义了一个无限的while
循环。 使用break
语句,只有一种方法可以跳出这样的循环。 我们从 1 到 30 中选择一个随机值并打印出来。 如果该值等于 22,则结束无穷的while
循环。
$ php testbreak.php
6 11 13 5 5 21 9 1 21 22
我们可能会得到这样的东西。
在下面的示例中,我们打印一个数字列表,这些数字不能除以 2 而没有余数。
testcontinue.php
<?php
$num = 0;
while ($num < 1000) {
$num++;
if (($num % 2) == 0) continue;
echo "$num ";
}
echo "\n";
我们使用while
循环遍历数字1..999
。
if (($num % 2) == 0) continue;
如果表达式$num % 2
返回 0,则可以将所讨论的数字除以 2。执行continue
语句,并跳过循环的其余部分。 在我们的例子中,循环的最后一条语句将被跳过,并且数字不会输出到控制台。 下一个迭代开始。
在 PHP 教程的这一部分中,我们正在讨论控制流结构。
PHP 数组
在 PHP 编程教程的这一部分中,我们介绍了数组。 我们初始化数组并从中读取数据。
PHP 数组定义
数组是数据的集合。 变量一次只能容纳一项。 数组可以容纳多个项目。 大多数编程语言都有各种类型的集合,包括列表,映射,数组,队列,栈和元组。 PHP 有不同的方法。 它具有一种通用集合,即数组。 使用不同的语法,PHP 中的数组将表现为列表,数组或映射。
从技术上讲,PHP 数组是一个映射。 它也称为关联数组。 映射将值与键相关联。
数组用于存储我们应用的数据。 我们对数组做三件事。 首先,我们使用应用数据初始化它们。 接下来,我们使用赋值或 PHP 数组函数修改数据。 我们有很多函数可用于数组。 它们使我们能够修改,排序,合并,切片,混洗数组内的数据。 有一些特定的数据库处理函数可用于从数据库查询中填充数组。 其他几个函数返回数组。 最后,我们将数据显示到控制台,或在 Web 应用中显示到浏览器。
PHP 初始化数组
从 PHP 5.4 开始,可以使用方括号使用短数组语法初始化数组。
init1.php
<?php
$names = ["Jane", "Lucy", "Timea", "Beky", "Lenka"];
print_r($names);
我们创建一个$names
数组,该数组存储五个女性名称。 print_r()
函数打印有关该变量的人类可读信息。
$ php init1.php
Array
(
[0] => Jane
[1] => Lucy
[2] => Timea
[3] => Beky
[4] => Lenka
)
从输出中,我们可以看到名称及其索引,从而可以访问它们。
传统上,数组是使用array()
函数初始化的。 以最简单的形式,该函数采用任意数量的逗号分隔值。
init2.php
<?php
$names = array("Jane", "Lucy", "Timea", "Beky", "Lenka");
print_r($names);
使用array()
函数创建相同的女性名称数组。
可以通过将值分配给数组索引来初始化数组。
init3.php
<?php
$continents[0] = "America";
$continents[1] = "Africa";
$continents[2] = "Europe";
$continents[3] = "Asia";
$continents[4] = "Antarctica";
$continents[5] = "Australia";
print_r($continents);
我们通过将值分配给数组索引来创建$continents
数组。 "America"
的索引为 0,"Europe"
的索引为 2,依此类推。
init4.php
<?php
$continents = [ 1 => "America", 2 => "Africa",
3 => "Europe", 4 => "Asia", 5 => "Antarctica",
6 => "Australia" ];
print_r($continents);
在此示例中,我们使用指定的索引创建$continents
数组。 默认情况下,第一个索引为零。 在我们的例子中,我们从 1 开始。
$ php init4.php
Array
(
[1] => America
[2] => Africa
[3] => Europe
[4] => Asia
[5] => Antarctica
[6] => Australia
)
现在,我们有了一系列具有选定索引的大洲。
索引不必是连续的数字。
init5.php
<?php
$languages[10] = "PHP";
$languages[20] = "Python";
$languages[30] = "Ruby";
$languages[40] = "PERL";
$languages[50] = "Java";
print_r($languages);
在示例中,我们选择数字 10、20、30、40 和 50 作为$languages
数组的索引。
当我们对 PHP 数组进行赋值初始化时,可以省略索引。 PHP 将自动为我们创建索引。
init6.php
<?php
$actors[] = "Philip Seymour Hoffman";
$actors[] = "Tom Cruise";
$actors[] = "Bill Paxton";
$actors[] = "Adrien Brody";
$actors[] = "Danie Craig";
print_r($actors);
创建了一组参与者。 没有设置特定的索引。
$ php init6.php
Array
(
[0] => Philip Seymour Hoffman
[1] => Tom Cruise
[2] => Bill Paxton
[3] => Adrien Brody
[4] => Danie Craig
)
PHP 解释器已创建从零开始的连续索引。
init7.php
<?php
$novels[10] = "Doctor Zhivago";
$novels[11] = "War and Peace";
$novels[] = "In Cold Blood";
$novels[20] = "Crime and Punishment";
$novels[] = "Catch XII";
print_r($novels);
在此脚本中,我们省略了两个索引。 PHP 将添加它们。 它将创建索引 12 和索引 21。
$ php init5.php
Array
(
[10] => Doctor Zhivago
[11] => War and Peace
[12] => In Cold Blood
[20] => Crime and Punishment
[21] => Catch XII
)
PHP 已自动创建索引 12 和 21。
数组的键也可以是字符串。
init8.php
<?php
$countries = [
"de" => "Germany", "sk" => "Slovakia",
"us" => "United States", "ru" => "Russia",
"hu" => "Hungaria", "pl" => "Poland" ];
echo $countries["de"] . "\n";
echo $countries["sk"] . "\n";
我们创建一个带有字符串索引的$countries
数组。
$ php init8.php
Germany
Slovakia
这是init8.php
示例的输出。
PHP 读取数组
接下来,我们将读取数组的内容。 有几种方法可以显示数组中的数据。
peruse1.php
<?php
$languages[10] = "PHP";
$languages[20] = "Python";
$languages[30] = "Ruby";
$languages[40] = "PERL";
$languages[50] = "Java";
echo $languages[10], "\n";
echo $languages[20], "\n";
echo $languages[30], "\n";
echo $languages[40], "\n";
echo $languages[50], "\n";
我们可以通过数组的索引访问数据。
$ php peruse1.php
PHP
Python
Ruby
PERL
Java
我们已将所有五种语言打印到控制台。
peruse2.php
<?php
$continents = [ "America", "Africa", "Europe",
"Asia", "Australia", "Antarctica" ];
$len = count($continents);
for ($i = 0; $i < $len; $i++) {
echo $continents[$i], "\n";
}
在此示例中,我们使用for
语句细读$continents
数组。
$len = count($continents);
首先,我们使用count()
函数计算数组中的元素数量。
for ($i = 0; $i < $len; $i++) {
echo $continents[$i], "\n";
}
for
循环通过索引0 .. $len-1
打印数组中的元素。
peruse3.php
<?php
$continents = [ "America", "Africa", "Europe", "Asia",
"Australia", "Antarctica" ];
foreach ($continents as $continent) {
echo $continent, "\n";
}
细读数组的最简单方法是使用foreach
语句。 该语句一个接一个地遍历数组,并将当前元素放入临时$continent
变量中。 它访问数据时不使用其索引或键。
walk.php
<?php
$countries = [ "de" => "Germany", "sk" => "Slovakia",
"us" => "United States", "ru" => "Russia",
"hu" => "Hungaria", "pl" => "Poland" ];
function show_values($value, $key) {
echo "The $key stands for the $value\n";
}
array_walk($countries, 'show_values');
在最后一个示例中,我们使用array_walk()
函数细读数组。 它将用户函数应用于数组的每个成员。 用户函数将键和项目的值作为参数。
$ php walk.php
The de stands for the Germany
The sk stands for the Slovakia
The us stands for the United States
The ru stands for the Russia
The hu stands for the Hungary
The pl stands for the Poland
我们将关键字和值都打印到句子中的控制台上。
在 PHP 教程的这一部分中,我们使用了数组。 我们初始化了数组并从中读取数据。 在下一章中,我们将使用各种 PHP 数组函数。
PHP 数组函数
在上一章中,我们讨论了数组的初始化和细读。 在本章中,我们将介绍各种 PHP 数组函数。 这些功能使我们能够修改,排序,合并,切片和随机排列数组内的数据。
PHP 排序数组
首先,我们将对数组进行排序。
sort.php
<?php
$names = [ "Jane", "Rebecca", "Lucy", "Lenka", "Ada" ];
echo "Unsorted: \n";
foreach ($names as $name) {
echo "$name ";
}
echo "\n";
sort($names);
echo "Sorted: \n";
foreach ($names as $name) {
echo "$name ";
}
echo "\n";
在上面的脚本中,我们有一个$names
数组。 我们使用sort()
函数对数组的内容进行排序。
$ php sort.php
Unsorted:
Jane Rebecca Lucy Lenka Ada
Sorted:
Ada Jane Lenka Lucy Rebecca
脚本的输出显示未排序和已排序的女性姓名。
rsort()
函数以相反的顺序对数组进行排序。
sort2.php
<?php
$numbers = [ 12, 3, 5, 1, 6, 7, 10, 0, 9, 8, 11];
sort($numbers);
echo "Ascending order: \n";
foreach ($numbers as $n) {
echo "$n ";
}
echo "\n";
rsort($numbers);
echo "Descending order: \n";
foreach ($numbers as $n) {
echo "$n ";
}
echo "\n";
有一个整数数组。 它按升序和降序排序。
sort($numbers);
sort()
函数按升序对整数进行排序。
rsort($numbers);
rsort()
函数按降序对整数进行排序。
$ php sort2.php
Ascending order:
0 1 3 5 6 7 8 9 10 11 12
Descending order:
12 11 10 9 8 7 6 5 3 1 0
这是sort2.php
脚本的输出。
在下面的示例中,我们显示了如何对重音字符进行排序。
locale_sort.php
<?php
setlocale(LC_ALL, 'sk_SK.utf8');
$words = [ "ďateľ", "auto", "železo", "byt", "kocka", "dáma",
"zem", "autor", "ceduľa", "čižma"];
sort($words, SORT_LOCALE_STRING);
echo "Ascending order: \n";
foreach ($words as $w) {
echo "$w ";
}
echo "\n";
rsort($words, SORT_LOCALE_STRING);
echo "Descending order: \n";
foreach ($words as $w) {
echo "$w ";
}
echo "\n";
我们有一系列包含特定口音的斯洛伐克语单词。
setlocale(LC_ALL, 'sk_SK.utf8');
我们使用setlocale()
函数设置斯洛伐克语区域设置。 语言环境代表特定的地理,政治或文化区域。
$words = [ "ďateľ", "auto", "železo", "byt", "kocka", "dáma",
"zem", "autor", "ceduľa", "čižma"];
$words
是带有重音符号的斯洛伐克语单词的数组。
sort($words, SORT_LOCALE_STRING);
我们使用sort()
函数以升序对数组进行排序。 我们向函数传递SORT_LOCALE_STRING
标志,该标志告诉sort()
考虑到语言环境。
$ php locale_sort.php
Ascending order:
auto autor byt ceduľa čižma dáma ďateľ kocka zem železo
Descending order:
železo zem kocka ďateľ dáma čižma ceduľa byt autor auto
单词已根据斯洛伐克语标准正确排序。
有时我们需要执行自定义排序。 对于自定义排序,我们在 PHP 中具有usort()
函数。
custom_sorting.php
<?php
$names = [ "Michael Brown", "Albert Einstein", "Gerry Miller",
"Tom Willis", "Michael Gray", "Luke Smith" ];
function sort_second_names($a, $b) {
$name1 = explode(" ", $a);
$name2 = explode(" ", $b);
return strcmp($name1[1], $name2[1]);
}
usort($names, 'sort_second_names');
foreach ($names as $name) {
echo "$name\n";
}
echo "\n";
我们有一个全名数组。 sort()
函数将根据名字对这些字符串进行排序,因为它们在第二个名字之前。 我们创建了一个解决方案,以根据它们的名字对这些名字进行排序。
function sort_second_names($a, $b) {
$name1 = explode(" ", $a);
$name2 = explode(" ", $b);
return strcmp($name1[1], $name2[1]);
}
我们有一个自定义的排序函数。 名称由explode()
函数分割,并将第二个名称与strcmp()
函数进行比较。
usort($names, 'sort_second_names');
usort()
函数接受比较函数作为其第二个参数。
$ php custom_sorting.php
Michael Brown
Albert Einstein
Michael Gray
Gerry Miller
Luke Smith
Tom Willis
名称将根据其第二名正确排序。
PHP 计算数组大小
count()
函数对数组中的元素数进行计数。 array_sum()
函数计算所有值的总和。 array_product()
函数计算数组中值的乘积。
counting.php
<?php
$numbers = [ 1, 2, 4, 5, 2, 3, 5, 2 ];
$len = count($numbers);
$sum = array_sum($numbers);
$prod = array_product($numbers);
echo "In the array, there are $len numbers\n";
echo "The sum of the numbers is $sum\n";
echo "The product of the numbers is $prod\n";
在示例中,我们有一个数字数组。 我们将上述定义的函数应用于数组。
$ php counting.php
In the array, there are 8 numbers
The sum of the numbers is 24
The product of the numbers is 2400
这是脚本的输出。
PHP 唯一值
在下面的示例中,我们在数组中找出唯一值。
unique.php
<?php
$numbers = array(3, 4, 4, 3, 2, 4);
$count_values = array_count_values($numbers);
print_r($count_values);
$unique = array_unique($numbers);
print_r($unique);
在此脚本中,数组中有重复项。 array_count_values()
函数返回一个数组,其中包含每个值的出现次数。 array_unique()
函数返回一个没有重复的数组。
$ php unique.php
Array
(
[3] => 2
[4] => 3
[2] => 1
)
Array
(
[0] => 3
[1] => 4
[4] => 2
)
第一个数组表示 3 次出现两次,4 次出现 3 次,2 次出现一次。 第二个数组表示数组中存在三个值:3、4 和 2。值 3 的索引为 0,4 的索引为 1,2 的索引为 4。array_unique()
函数保持索引不变。
PHP 切片数组
array_slice()
函数从数组中返回其偏移量和长度参数所指定的元素序列。
slicing.php
<?php
$nums = range(1, 20);
$slice1 = array_slice($nums, 0, 3);
echo "Slice1:\n";
foreach ($slice1 as $s) {
echo "$s ";
}
echo "\n";
$slice2 = array_slice($nums, -3);
echo "Slice2:\n";
foreach ($slice2 as $s) {
echo "$s ";
}
echo "\n";
在示例中,我们创建了一个整数数组的两个切片。
$slice1 = array_slice($nums, 0, 3);
我们从第一个元素开始创建一个切片; 切片的长度是三个元素。
$slice2 = array_slice($nums, -3);
通过提供负偏移量,可以从数组的末尾创建切片。
$ php slicing.php
Slice1:
1 2 3
Slice2:
18 19 20
这是slicing.php
示例的输出。
PHP 数组指针
PHP 具有内部数组指针。 在下面的示例中,我们介绍了操作该指针的函数。
array_pointer.php
<?php
$continents = [ "America", "Africa", "Europe", "Asia", "Australia",
"Antarctica" ];
$item1 = current($continents);
$item2 = next($continents);
$item3 = next($continents);
$item4 = end($continents);
$item5 = prev($continents);
echo "$item1, $item2, $item3, $item4, $item5\n";
reset($continents);
while(list($idx, $val) = each($continents)) {
echo "Index: $idx, Value: $val\n";
}
在此示例中,我们使用移动内部数组指针的函数遍历数组。
$item1 = current($continents);
$item2 = next($continents);
$item3 = next($continents);
$item4 = end($continents);
$item5 = prev($continents);
current()
函数返回数组中的当前元素。 首先,它是数组的第一个元素。 next()
函数使指针前进一个位置。 end()
函数返回最后一个元素。 prev()
元素返回该元素,即当前元素之前的一个位置。 在我们的情况下,它是最后一个元素的下一个。
reset($continents);
while(list($idx, $val) = each($continents)) {
echo "Index: $idx, Value: $val\n";
}
在这里,我们使用reset()
函数再次将内部指针设置为第一个元素,并仔细阅读$continents
数组。
$ php array_pointer.php
America, Africa, Europe, Antarctica, Australia
Index: 0, Value: America
Index: 1, Value: Africa
Index: 2, Value: Europe
Index: 3, Value: Asia
Index: 4, Value: Australia
Index: 5, Value: Antarctica
这是array_pointer.php
脚本的输出。
PHP 合并数组
array_merge()
函数合并数组。
merge.php
<?php
$names1 = [ "Jane", "Lucy", "Rebecca" ];
$names2 = [ "Lenka", "Timea", "Victoria" ];
$names = array_merge($names1, $names2);
foreach ($names as $name) {
echo "$name ";
}
echo "\n";
在此示例中,我们有两个数组:$names1
和$names2
。 我们使用array_merge()
函数通过合并前两个数组来创建$names
数组。
$ php merge.php
Jane Lucy Rebecca Lenka Timea Victoria
新数组有六个名称。
PHP 修改数组
可以使用array_push()
,array_pop()
,array_shift()
或array_unshift()
函数修改 PHP 数组。
modify.php
<?php
$numbers = [ 1, 2, 3, 4 ];
array_push($numbers, 5, 6);
foreach ($numbers as $num) {
echo $num, " ";
}
echo "\n";
array_pop($numbers);
foreach ($numbers as $num) {
echo $num, " ";
}
echo "\n";
array_unshift($numbers, -1, 0);
foreach ($numbers as $num) {
echo $num, " ";
}
echo "\n";
array_shift($numbers);
foreach ($numbers as $num) {
echo $num, " ";
}
echo "\n";
在上面的脚本中,我们使用了修改数组内容的函数。 我们有一个$numbers
数组,其中包含 4 个数字:1、2、3 和 4。
array_push($numbers, 5, 6);
array_push()
函数将一个或多个项目插入数组的末尾。 现在,我们的数组包含值 1、2、3、4、5 和 6。
array_pop($numbers);
array_pop()
函数从数组中删除最后一项。 我们的数组现在存储数字 1、2、3、4 和 5。
array_unshift($numbers, -1, 0);
array_unshift()
函数将 -1 和 0 添加到数组的开头。 该数组包含值-1、0、1、2、3、4 和 5。
array_shift($numbers);
最后,array_shift()
函数从数组中删除第一项。 现在我们在数组中具有值 0、1、2、3、4 和 5。
$ php modify.php
1 2 3 4 5 6
1 2 3 4 5
-1 0 1 2 3 4 5
0 1 2 3 4 5
这是modify.php
示例的输出。
PHP 范围函数
range()
函数通过自动创建元素序列来简化数组创建。 它接受三个参数:序列开始,序列结束和可选的增量,默认为 1。
range.php
<?php
$numbers1 = range(1, 15);
foreach ($numbers1 as $num) {
echo "$num ";
}
echo "\n";
$numbers2 = range(15, 1, -1);
foreach ($numbers2 as $num) {
echo "$num ";
}
echo "\n";
range()
函数使我们能够轻松创建连续数字列表。
$numbers1 = range(1, 15);
创建一个数字为 1,2,... 15 的数组。
$numbers2 = range(15, 1, -1);
通过指定负增量可以创建值的降序序列。
$ php range.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
这是range.php
函数的输出。
PHP 随机化数组值
array_rand()
函数从数组中选择一个或多个随机条目。 shuffle()
函数可将数组中元素的顺序随机化。
randomize.php
<?php
$nums = range(1, 20);
echo ($nums[array_rand($nums)]) . "\n";
$r = array_rand($nums, 2);
echo $nums[$r[0]] . "\n";
echo $nums[$r[1]] . "\n";
shuffle($nums);
foreach ($nums as $n) {
echo "$n ";
}
echo "\n";
在示例中,我们从数组中选择随机值,并随机化其元素顺序。
echo ($nums[array_rand($nums)]) . "\n";
array_rand()
函数从$num
数组返回一个随机键。
$r = array_rand($nums, 2);
在这种情况下,array_rand()
函数返回两个随机键的数组。
$ php randomize.php
4
2
19
13 19 4 3 17 11 20 16 10 9 8 14 15 12 18 2 6 5 1 7
这是randomize.php
程序的示例输出。
PHP in_array
函数
in_array()
函数检查数组中是否有特定元素。
inarray.php
<?php
$names = [ "Jane", "Adriana", "Lucy", "Rebecca" ];
if (in_array("Jane", $names)) {
echo "Jane is in the array\n";
} else {
echo "Jane is not in the array\n";
}
if (in_array("Monica", $names)) {
echo "Monica is in the array\n";
} else {
echo "Monica is not in the array\n";
}
我们的脚本检查$names
数组中是否为'Jane'和'Monica'。
$ php inarray.php
Jane is in the array
Monica is not in the array
简中有简,但莫妮卡中没有。
PHP 数组键和值
PHP 数组是一个由键和值对组成的关联数组。
keysvalues.php
<?php
$domains = [ "sk" => "Slovakia", "de" => "Germany",
"hu" => "Hungary", "ru" => "Russia" ];
$keys = array_keys($domains);
$values = array_values($domains);
foreach ($keys as $key) {
echo "$key ";
}
echo "\n";
foreach ($values as $value) {
echo "$value ";
}
echo "\n";
array_keys()
函数返回数组的所有键。 array_values()
函数返回数组的所有值。
$ php keysvalues.php
sk de hu ru
Slovakia Germany Hungary Russia
第一行包含顶级域名。 这些是$domains
数组的键。 第二行是相应国家的名称。 这些是数组的值。
PHP array_walk
函数
array_walk()
函数将用户定义的函数应用于数组的每个成员。
array_walk.php
<?php
$countries = [ "de" => "Germany", "sk" => "Slovakia",
"us" => "United States", "ru" => "Russia",
"hu" => "Hungaria", "pl" => "Poland" ];
function show_values($value, $key) {
echo "The $key stands for the $value\n";
}
array_walk($countries, 'show_values');
我们有一个$countries
数组。 我们将show_values
函数应用于数组的每个元素。 该函数仅打印每个元素的键和值。
$ php array_walk.php
The de stands for the Germany
The sk stands for the Slovakia
The us stands for the United States
The ru stands for the Russia
The hu stands for the Hungaria
The pl stands for the Poland
这是array_walk()
函数的输出。
在 PHP 教程的这一部分中,我们介绍了一些 PHP 数组函数。
PHP 中的函数
在 PHP 编程教程的这一部分中,我们讨论函数。
函数是较大程序中的一段代码。 该函数执行特定任务。 使用函数的优点是:
- 减少代码重复
- 将复杂的问题分解成更简单的部分
- 提高代码的清晰度
- 重用代码
- 信息隐藏
有两种基本类型的函数。 内置函数和用户定义的函数。 内置函数是 PHP 语言的一部分。 示例是:phpinfo()
,round()
或abs()
。 用户定义的函数由应用员创建,以满足其需求。 它们是使用function
关键字创建的。
PHP 定义函数
使用function
关键字创建一个函数。
simple.php
<?php
function displayVersion() {
echo "this is PHP " . phpversion();
echo "\n";
}
displayVersion();
function
关键字后跟带有圆括号的函数名称。 函数的主体位于大括号之间。 我们说我们将称为函数。 如果我们调用一个函数,则会执行函数体内的语句。
displayVersion();
该行代码调用该函数。
$ php simple.php
this is PHP 5.5.9-1ubuntu4.14
在这里,我们看到了脚本的结果。
PHP return
关键字
return
关键字用于从函数返回值。 函数可能会也可能不会返回值。
returning.php
<?php
function maximum($x, $y) {
if ($x > $y) {
return $x;
} else {
return $y;
}
}
$a = 23;
$b = 32;
$val = maximum($a, $b);
echo "The max of $a and $b is $val \n";
我们有一个maximum()
函数。 它返回两个数字的最大值。 我们无法将其命名为max
,因为已经有内置的max()
函数。 创建此示例是出于学习目的; 我们始终希望在现实世界的程序中使用内置函数。
if ($x > $y) {
return $x;
} else {
return $y;
}
如果$x
变量大于$y
,则返回$x
。 否则,我们返回$y
。
$val = maximum($a, $b);
maximum()
函数返回的值分配给$val
变量。
echo "The max of $a and $b is $val \n";
我们将两个数字的最大值打印到控制台。
PHP 函数参数
大多数函数接受参数。 参数是发送到函数的值。 函数处理值,并可能返回一些结果。
fahrenheit.php
<?php
function FTC($c) {
return $c * 9/5 + 32;
}
echo FTC(100);
echo "\n";
echo FTC(0);
echo "\n";
echo FTC(30);
echo "\n";
在我们的示例中,我们将华氏温度转换为摄氏温度。 FTC()
函数接受一个参数$c
,即摄氏温度。
$ php fahrenheit.php
212
32
86
PHP 隐式值
PHP 函数中的参数可能具有隐式值。 如果未提供任何值,则使用隐式值。
implicit_value.php
<?php
function power($a, $b=2) {
if ($b == 2) {
return $a * $a;
}
$value = 1;
for ($i = 0; $i < $b; $i++) {
$value *= $a;
}
return $value;
}
$v1 = power(5);
$v2 = power(5, 4);
echo "5^2 is $v1 \n";
echo "5^4 is $v2 \n";
在这里,我们创建了幂函数。 该函数有一个带有隐式值的参数。 我们可以使用一个或两个参数来调用该函数。
$ php implicit_value.php
5^2 is 25
5^4 is 625
PHP 可变参数数量
一个函数可以接受可变数量的参数。 换句话说,有时我们不知道将有多少参数传递给该函数。 func_get_args()
函数返回一个包含函数的参数列表的数组。
从 PHP 5.6 开始,...
运算符可用于创建可变函数。
variable_arguments1.php
<?php
function sum(...$nums) {
$sum = 0;
foreach ($nums as $n) {
$sum += $n;
}
return $sum;
}
echo sum(1, 2, 3) . "\n";
echo sum(1, 2, 3, 4) . "\n";
echo sum(1, 2, 3, 4, 5) . "\n";
我们创建一个sum()
方法,该方法可以使用可变数量的参数。 该方法计算传递给该方法的值的总和。
$sum = 0;
foreach ($args as $n) {
$sum += $n;
}
return $sum;
我们计算并返回值的总和。
echo sum(1, 2, 3) . "\n";
echo sum(1, 2, 3, 4) . "\n";
echo sum(1, 2, 3, 4, 5) . "\n";
我们将三个,四个和五个值传递给sum()
函数。
$ php variable_arguments1.php
6
10
15
这是输出。
variable_arguments2.php
<?php
function sum() {
$args = func_get_args();
$sum = 0;
foreach ($args as $n) {
$sum += $n;
}
return $sum;
}
echo sum(1, 2, 3) . "\n";
echo sum(1, 2, 3, 4) . "\n";
echo sum(1, 2, 3, 4, 5) . "\n";
现在,使用func_get_args()
函数创建相同的示例。
PHP 静态变量
静态变量是已静态分配的变量,其生存期遍及整个程序运行。 默认的局部变量不会在函数的连续调用中保留其值。
non_static.php
<?php
function nonstatic() {
$value = 0;
$value += 1;
return $value;
}
nonstatic();
nonstatic();
nonstatic();
nonstatic();
echo nonstatic(), "\n";
在上面的示例中,我们有一个普通的非静态变量。 每次调用函数时,我们都会增加变量。 我们调用该函数 5 次。 但是,对于函数的每次调用都会启动非静态变量。 在 5 个函数调用之后,$value
等于 2。
首次调用函数时,静态变量仅启动一次。 之后,他们保留自己的值。
static.php
<?php
function staticfun() {
static $value = 0;
$value += 1;
return $value;
}
staticfun();
staticfun();
staticfun();
staticfun();
echo staticfun(), "\n";
连续 5 次通话后,$value
等于 5。
$ php nonstatic.php
2
$ php static.php
6
PHP 匿名函数
匿名函数没有名称。
anonymous.php
<?php
$var = function() {
echo "This is anonymous function\n";
};
$var();
我们将函数主体分配给变量。 只能通过此变量来调用函数。
$var = function() {
echo "This is anonymous function\n";
};
注意右花括号后的分号。 这是必需的,因为构造是分配。
$ php anonymous.php
This is anonymous function
这是示例的输出。
通过值和引用传递参数
PHP 支持两种将参数传递给函数的方式。 默认方式是按值传递参数。 当我们按值传递参数时,该函数仅适用于值的副本。 当我们处理大量数据时,这可能会导致性能开销。
当我们通过引用传递值时,该函数会收到对实际值的引用。 修改后,原始值会受到影响。 这种传递值的方式更加节省时间和空间。 另一方面,它更容易出错。
我们应该使用哪种方式传递参数? 这取决于实际情况。 假设我们有一组数据,即员工工资。 如果我们要计算数据的某些统计信息,则无需修改它们。 我们通过值。 如果我们处理大量数据,并且计算速度至关重要,则可以引用。 如果我们要修改数据,例如进行一些减薪或加薪,我们可以引用一下。
以下两个示例涵盖了这两个概念。
swap1.php
<?php
function swap($a, $b) {
$temp = $a;
$a = $b;
$b = $temp;
echo "inside swap function:\n";
echo "\$a is $a \n";
echo "\$b is $b \n";
}
$a = 4;
$b = 7;
echo "outside swap function:\n";
echo "\$a is $a \n";
echo "\$b is $b \n";
swap($a, $b);
echo "outside swap function:\n";
echo "\$a is $a \n";
echo "\$b is $b \n";
交换函数在$a
和$b
变量之间交换数字。 原始变量不受影响。
$a = 4;
$b = 7;
最初,这两个变量被启动。
swap($a, $b);
我们称为swap()
函数。 该函数将$a
和$b
变量作为参数。
$temp = $a;
$a = $b;
$b = $temp;
在swap()
函数内部,我们更改值。 请注意,$a
和$b
变量是在本地定义的。 它们仅在swap()
函数内部有效。
$ php swap1.php
outside swap function:
$a is 4
$b is 7
inside swap function:
$a is 7
$b is 4
outside swap function:
$a is 4
$b is 7
输出显示原始变量不受影响。
下一个代码示例通过引用将值传递给函数。 原始变量在swap()
函数内更改。
swap2.php
<?php
function swap(&$a, &$b) {
$temp = $a;
$a = $b;
$b = $temp;
echo "Inside the swap function:\n";
echo "\$a is $a \n";
echo "\$b is $b \n";
}
$a = 4;
$b = 7;
echo "Outside the swap function:\n";
echo "\$a is $a \n";
echo "\$b is $b \n";
swap($a, $b);
echo "Outside the swap function:\n";
echo "\$a is $a \n";
echo "\$b is $b \n";
我们使用&
字符通过引用传递值。
function swap(&$a, &$b) {
...
}
这个例子几乎与前面的例子相同。 除&字符外。
$ php swap2.php
Outside the swap function:
$a is 4
$b is 7
Inside the swap function:
$a is 7
$b is 4
Outside the swap function:
$a is 7
$b is 4
在这里我们看到swap()
函数确实改变了变量的值。
PHP 函数递归
在数学和计算机科学中,递归是一种定义函数的方法,其中所定义的函数在其自己的定义内应用。 换句话说,递归函数调用自身以完成其工作。 递归是迭代的替代方法。 递归是函数式语言中的主要方法。
一个典型的例子是阶乘的计算。
recursion.php
<?php
function factorial($n) {
if ($n==0) {
return 1;
} else {
return $n * factorial($n - 1);
}
}
echo factorial(4), "\n";
echo factorial(10), "\n";
在此代码示例中,我们计算两个数字的阶乘。
return $n * factorial($n - 1);
在阶乘函数的主体内部,我们使用经过修改的参数调用阶乘函数。 该函数调用自身。
$ php recursion.php
24
3628800
这些就是结果。
PHP 全局和局部变量
接下来,我们将讨论 PHP 中变量的范围。 范围是可以引用变量的范围。 当我们使用函数时,有两个基本范围:全局范围和局部范围。 局部作用域也称为函数作用域。
scope1.php
<?php
$value = 1;
function simple() {
var_dump($value);
}
simple();
在函数体内定义的变量不能在函数内引用。
$ php scope1.php
PHP Notice: Undefined variable: value in /home/janbodnar/prog/php/functions/scope1.php on line 7
NULL
simple()
函数中的$value
变量为NULL
。
scope2.php
<?php
$value = 4;
function simple() {
$value = 3;
echo $value, "\n";
}
simple();
echo $value, "\n";
在此示例中,我们有两个具有相同名称的变量。 它们不会冲突,因为它们存在于不同的范围内。
$ php scope2.php
3
4
该值在函数内部为 3,在函数外部为 4。
在下一个示例中,我们将在函数内部修改一个值。
scope3.php
<?php
$value = 1;
function simple() {
global $value;
$value = 2;
}
echo $value, "\n";
simple();
echo $value, "\n";
我们使用global
关键字来引用在函数主体外部定义的变量。
$ php scope3.php
1
2
$value
已在simple()
函数内成功修改。
在 PHP 教程的这一部分中,我们介绍了 PHP 函数。
PHP 正则表达式
在 PHP 教程的这一部分中,我们介绍了 PHP 中的正则表达式。
正则表达式用于文本搜索和更高级的文本操作。 正则表达式是内置工具,如grep
,sed
,文本编辑器(如 vi,emacs),编程语言(如 Tcl,Perl 和 Python)。 PHP 也具有对正则表达式的内置支持。
在 PHP 中,有两个用于正则表达式的模块:POSIX Regex 和 PCRE。 POSIX 正则表达式已贬值。 在本章中,我们将使用 PCRE 示例。 PCRE 代表与 Perl 兼容的正则表达式。
使用正则表达式时,需要做两件事:正则表达式函数和模式。
模式是一个正则表达式,用于定义我们正在搜索或操纵的文本。 它由文本文字和元字符组成。 该模式放置在两个定界符内。 这些通常是//
,##
或@@
字符。 它们通知正则表达式函数模式的开始和结束位置。
这是 PCRE 中使用的部分元字符列表。
. |
匹配任何单个字符。 |
* |
与前面的元素匹配零次或多次。 |
[ ] |
括号表达。 与方括号内的字符匹配。 |
[^ ] |
匹配方括号中未包含的单个字符。 |
^ |
匹配字符串中的起始位置。 |
` | |
--- | --- |
. |
匹配任何单个字符。 |
* |
与前面的元素匹配零次或多次。 |
[ ] |
括号表达。 与方括号内的字符匹配。 |
[^ ] |
匹配方括号中未包含的单个字符。 |
^ |
匹配字符串中的起始位置。 |
匹配字符串中的结束位置。 | |
| |
备用运算符。 |
PRCE 函数
我们定义一些 PCRE regex 函数。 它们都有一个preg
前缀。
preg_split()
- 按正则表达式模式分割字符串preg_match()
- 执行正则表达式匹配preg_replace()
- 用正则表达式模式搜索和替换字符串preg_grep()
- 返回与正则表达式模式匹配的数组条目
接下来,我们将为每个函数提供一个示例。
php> print_r(preg_split("@\s@", "Jane\tKate\nLucy Marion"));
Array
(
[0] => Jane
[1] => Kate
[2] => Lucy
[3] => Marion
)
我们有四个名字,用空格分开。 \s
是代表空格的字符类。 preg_split()
函数返回数组中的拆分字符串。
php> echo preg_match("#[a-z]#", "s");
1
preg_match()
函数查看字符类[a-z]
中是否包含's'
字符。 该类代表从a
到z
的所有字符。 成功返回 1。
php> echo preg_replace("/Jane/","Beky","I saw Jane. Jane was beautiful.");
I saw Beky. Beky was beautiful.
preg_replace()
函数将单词"Jane"
的所有出现替换为单词"Beky"
。
php> print_r(preg_grep("#Jane#", ["Jane", "jane", "Joan", "JANE"]));
Array
(
[0] => Jane
)
preg_grep()
函数返回与给定模式匹配的单词数组。 在此示例中,数组中仅返回一个单词。 这是因为默认情况下,搜索区分大小写。
php> print_r(preg_grep("#Jane#i", ["Jane", "jane", "Joan", "JANE"]));
Array
(
[0] => Jane
[1] => jane
[3] => JANE
)
在此示例中,我们执行不区分大小写的grep
。 我们将i
修饰符放在右定界符之后。 现在,返回的数组包含三个单词。
点元字符
.
(点)元字符代表文本中的任何单个字符。
single.php
<?php
$words = [ "Seven", "even", "Maven", "Amen", "Leven" ];
$pattern = "/.even/";
foreach ($words as $word) {
if (preg_match($pattern, $word)) {
echo "$word matches the pattern\n";
} else {
echo "$word does not match the pattern\n";
}
}
在$words
数组中,我们有五个词。
$pattern = "/.even/";
在这里,我们定义搜索模式。 模式是一个字符串。 正则表达式位于分隔符内。 分隔符是强制性的。 在我们的例子中,我们使用正斜杠/ /
作为分隔符。 请注意,如果需要,我们可以使用不同的定界符。 点字符代表任何单个字符。
if (preg_match($pattern, $word)) {
echo "$word matches the pattern\n";
} else {
echo "$word does not match the pattern\n";
}
如果这五个词与模式匹配,我们将对其进行测试。
$ php single.php
Seven matches the pattern
even does not match the pattern
Maven does not match the pattern
Amen does not match the pattern
Leven matches the pattern
七个和七个词与我们的搜索模式匹配。
锚点
锚点匹配给定文本内字符的位置。
在下一个示例中,我们查看字符串是否位于句子的开头。
anchors.php
<?php
$sentence1 = "Everywhere I look I see Jane";
$sentence2 = "Jane is the best thing that happened to me";
if (preg_match("/^Jane/", $sentence1)) {
echo "Jane is at the beginning of the \$sentence1\n";
} else {
echo "Jane is not at the beginning of the \$sentence1\n";
}
if (preg_match("/^Jane/", $sentence2)) {
echo "Jane is at the beginning of the \$sentence2\n";
} else {
echo "Jane is not at the beginning of the \$sentence2\n";
}
我们有两个句子。 模式是^Jane
。 该模式检查'Jane'字符串是否位于文本的开头。
$ php anchors.php
Jane is not at the beginning of the $sentence1
Jane is at the beginning of the $sentence2
php> echo preg_match("#Jane$#", "I love Jane");
1
php> echo preg_match("#Jane$#", "Jane does not love me");
0
Jane$
模式与字符串"Jane"
结尾的字符串匹配。
完全匹配
在以下示例中,我们显示了如何查找完全匹配的单词。
php> echo preg_match("/mother/", "mother");
1
php> echo preg_match("/mother/", "motherboard");
1
php> echo preg_match("/mother/", "motherland");
1
mother
模式适合单词mother
,motherboard
和motherland
。 说,我们只想查找完全匹配的单词。 我们将使用前面提到的锚点^
和$
字符。
php> echo preg_match("/^mother$/", "motherland");
0
php> echo preg_match("/^mother$/", "Who is your mother?");
0
php> echo preg_match("/^mother$/", "mother");
1
使用定位字符,我们可以获得与模式完全匹配的单词。
量词
标记或组之后的量词指定允许前面的元素出现的频率。
? - 0 or 1 match
* - 0 or more
+ - 1 or more
{n} - exactly n
{n,} - n or more
{,n} - n or less (??)
{n,m} - range n to m
上面是常见量词的列表。
问号?
表示存在零或前一个元素之一。
zeroorone.php
<?php
$words = [ "color", "colour", "comic", "colourful", "colored",
"cosmos", "coloseum", "coloured", "colourful" ];
$pattern = "/colou?r/";
foreach ($words as $word) {
if (preg_match($pattern, $word)) {
echo "$word matches the pattern\n";
} else {
echo "$word does not match the pattern\n";
}
}
$words
数组中有四个 9。
$pattern = "/colou?r/";
颜色用于美式英语,颜色用于英式英语。 此模式匹配两种情况。
$ php zeroorone.php
color matches the pattern
colour matches the pattern
comic does not match the pattern
colourful matches the pattern
colored matches the pattern
cosmos does not match the pattern
coloseum does not match the pattern
coloured matches the pattern
colourful matches the pattern
这是zeroorone.php
脚本的输出。
*
元字符与前面的元素匹配零次或更多次。
zeroormore.php
<?php
$words = [ "Seven", "even", "Maven", "Amen", "Leven" ];
$pattern = "/.*even/";
foreach ($words as $word) {
if (preg_match($pattern, $word)) {
echo "$word matches the pattern\n";
} else {
echo "$word does not match the pattern\n";
}
}
在上面的脚本中,我们添加了*
元字符。 .*
组合表示零个,一个或多个单个字符。
$ php zeroormore.php
Seven matches the pattern
even matches the pattern
Maven does not match the pattern
Amen does not match the pattern
Leven matches the pattern
现在该模式匹配三个单词:Seven
,even
和Leven
。
php> print_r(preg_grep("#o{2}#", ["gool", "root", "foot", "dog"]));
Array
(
[0] => gool
[1] => root
[2] => foot
)
o{2}
模式匹配恰好包含两个'o'字符的字符串。
php> print_r(preg_grep("#^\d{2,4}$#", ["1", "12", "123", "1234", "12345"]));
Array
(
[1] => 12
[2] => 123
[3] => 1234
)
我们有这个^\d{2,4}$
模式。 \d
是一个字符集; 它代表数字。 该模式匹配具有 2、3 或 4 位数字的数字。
交替
下一个示例说明了交替运算符|
。 该运算符使您可以创建具有多种选择的正则表达式。
alternation.php
<?php
$names = [ "Jane", "Thomas", "Robert", "Lucy", "Beky",
"John", "Peter", "Andy" ];
$pattern = "/Jane|Beky|Robert/";
foreach ($names as $name) {
if (preg_match($pattern, $name)) {
echo "$name is my friend\n";
} else {
echo "$name is not my friend\n";
}
}
$names
数组中有八个名称。
$pattern = "/Jane|Beky|Robert/";
这是搜索模式。 该模式查找"Jane"
,"Beky"
或"Robert"
字符串。
$ php alternation.php
Jane is my friend
Thomas is not my friend
Robert is my friend
Lucy is not my friend
Beky is my friend
John is not my friend
Peter is not my friend
Andy is not my friend
这是脚本的输出。
子模式
我们可以使用方括号()
在样式内创建子模式。
php> echo preg_match("/book(worm)?$/", "bookworm");
1
php> echo preg_match("/book(worm)?$/", "book");
1
php> echo preg_match("/book(worm)?$/", "worm");
0
我们有以下正则表达式模式:book(worm)?$
。 (worm)
是子模式。 ? 字符跟随子模式,这意味着该子模式在最终模式中可能出现 0、1 次。 这里的$
字符用于字符串的精确末尾匹配。 没有它,诸如bookstore
,bookmania
之类的词也将匹配。
php> echo preg_match("/book(shelf|worm)?$/", "book");
1
php> echo preg_match("/book(shelf|worm)?$/", "bookshelf");
1
php> echo preg_match("/book(shelf|worm)?$/", "bookworm");
1
php> echo preg_match("/book(shelf|worm)?$/", "bookstore");
0
子模式经常交替使用。 (shelf|worm)
子模式可创建多个单词组合。
字符类
我们可以使用方括号将字符组合成字符类。 字符类与括号中指定的任何字符匹配。
characterclass.php
<?php
$words = [ "sit", "MIT", "fit", "fat", "lot" ];
$pattern = "/[fs]it/";
foreach ($words as $word) {
if (preg_match($pattern, $word)) {
echo "$word matches the pattern\n";
} else {
echo "$word does not match the pattern\n";
}
}
我们用两个字符定义一个字符集。
$pattern = "/[fs]it/";
这是我们的模式。 [fs]
是字符类。 请注意,我们一次只能处理一个字符。 我们要么考虑f
要么s
,但不能同时考虑两者。
$ php characterclass.php
sit matches the pattern
MIT does not match the pattern
fit matches the pattern
fat does not match the pattern
lot does not match the pattern
这是脚本的结果。
我们还可以将速记元字符用于字符类。 \w
代表字母数字字符,\d
代表数字,\s
空格字符。
shorthand.php
<?php
$words = [ "Prague", "111978", "terry2", "mitt##" ];
$pattern = "/\w{6}/";
foreach ($words as $word) {
if (preg_match($pattern, $word)) {
echo "$word matches the pattern\n";
} else {
echo "$word does not match the pattern\n";
}
}
在上面的脚本中,我们测试包含字母数字字符的单词。 \w{6}
代表六个字母数字字符。 仅单词mitt##
不匹配,因为它包含非字母数字字符。
php> echo preg_match("#[^a-z]{3}#", "ABC");
1
#[^a-z]{3}#
模式代表三个不在a-z
类中的字符。 "ABC"
字符符合条件。
php> print_r(preg_grep("#\d{2,4}#", [ "32", "234", "2345", "3d3", "2"]));
Array
(
[0] => 32
[1] => 234
[2] => 2345
)
在上面的示例中,我们有一个匹配 2、3 和 4 位数字的模式。
提取匹配
preg_match()
具有可选的第三个参数。 如果提供,则将其填充为搜索结果。 变量是一个数组,其第一个元素包含与完整模式匹配的文本,第二个元素包含第一个捕获的带括号的子模式,依此类推。
extract_matches.php
<?php
$times = [ "10:10:22", "23:23:11", "09:06:56" ];
$pattern = "/(\d\d):(\d\d):(\d\d)/";
foreach ($times as $time) {
$r = preg_match($pattern, $time, $match);
if ($r) {
echo "The $match[0] is split into:\n";
echo "Hour: $match[1]\n";
echo "Minute: $match[2]\n";
echo "Second: $match[3]\n";
}
}
在示例中,我们提取时间字符串的一部分。
$times = [ "10:10:22", "23:23:11", "09:06:56" ];
我们在英语语言环境中有三个时间字符串。
$pattern = "/(\d\d):(\d\d):(\d\d)/";
模式使用方括号分为三个子模式。 我们想确切地指每个部分。
$r = preg_match($pattern, $time, $match);
我们将第三个参数传递给preg_match()
函数。 如果匹配,则包含匹配字符串的文本部分。
if ($r) {
echo "The $match[0] is split into:\n";
echo "Hour: $match[1]\n";
echo "Minute: $match[2]\n";
echo "Second: $match[3]\n";
}
$match[0]
包含与完整模式匹配的文本,$match[1]
包含与第一个子模式匹配的文本,$match[2]
与第二个子模式匹配,$match[3]
与第三个子模式匹配。
$ php extract_matches.php
The 10:10:22 is split into:
Hour: 10
Minute: 10
Second: 22
The 23:23:11 is split into:
Hour: 23
Minute: 23
Second: 11
The 09:06:56 is split into:
Hour: 09
Minute: 06
Second: 56
这是示例的输出。
电子邮件示例
接下来有一个实际的例子。 我们创建一个正则表达式模式来检查电子邮件地址。
emails.php
<?php
$emails = [ "[email protected]", "andy@yahoocom", "34234sdfa#2345",
"[email protected]"];
# regular expression for emails
$pattern = "/^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,18}$/";
foreach ($emails as $email) {
if (preg_match($pattern, $email)) {
echo "$email matches \n";
} else {
echo "$email does not match\n";
}
}
>?
请注意,此示例仅提供一种解决方案。 它不一定是最好的。
$pattern = "/^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,18}$/";
这就是模式。 这里的第一个^
和最后一个$
字符可得到精确的模式匹配。 模式前后不允许有字符。 电子邮件分为五个部分。 第一部分是本地部分。 这通常是公司,个人或昵称的名称。 [a-zA-Z0-9._-]+
列出了所有可能的字符,我们可以在本地使用。 它们可以使用一次或多次。 第二部分是文字@
字符。 第三部分是领域部分。 通常是电子邮件提供商的域名,例如 yahoo 或 gmail。 [a-zA-Z0-9-]+
是一个字符集,提供了可在域名中使用的所有字符。 +
量词使用这些字符中的一个或多个。 第四部分是点字符。 它前面有转义字符(\
)。 这是因为点字符是一个元字符,并且具有特殊含义。 通过转义,我们得到一个文字点。 最后一部分是顶级域。 模式如下:[a-zA-Z.]{2,18}
顶级域可以包含 2 到 18 个字符,例如sk, net, info, travel, cleaning, travelinsurance
。 最大长度可以为 63 个字符,但是今天大多数域都少于 18 个字符。 还有一个点字符。 这是因为某些顶级域包含两个部分: 例如co.uk
。
$ php emails.php
[email protected] matches
andy@yahoocom does not match
34234sdfa#2345 does not match
[email protected] matches
这是emails.php
示例的输出。
总结
最后,我们快速回顾一下正则表达式模式。
Jane the 'Jane' string
^Jane 'Jane' at the start of a string
Jane$ 'Jane' at the end of a string
^Jane$ exact match of the string 'Jane'
[abc] a, b, or c
[a-z] any lowercase letter
[^A-Z] any character that is not a uppercase letter
(Jane|Becky) Matches either 'Jane' or 'Becky'
[a-z]+ one or more lowercase letters
^[98]?$ digits 9, 8 or empty string
([wx])([yz]) wy, wz, xy, or xz
[0-9] any digit
[^A-Za-z0-9] any symbol (not a number or a letter)
在本章中,我们介绍了 PHP 中的正则表达式。
PHP 中的面向对象编程
在 PHP 教程的这一部分中,我们将讨论 PHP 中的面向对象编程。
那里有三种广泛使用的编程范例:过程编程,函数编程和面向对象的编程。 PHP 5 支持过程式编程和面向对象的编程。 PHP 的早期版本对 OOP 的支持有限或不支持。
面向对象编程(OOP)是一种使用对象及其相互作用设计应用和计算机程序的编程范例。
OOP 中的基本编程概念是:
- 抽象
- 多态
- 封装
- 继承
抽象通过建模适合该问题的类来简化复杂的现实。 多态是将运算符或函数以不同方式用于不同数据输入的过程。 封装对其他对象隐藏了类的实现细节。 继承是一种使用已经定义的类形成新类的方法。
PHP 对象
对象是 PHP OOP 程序的基本构建块。 对象是数据和方法的组合。 在 OOP 程序中,我们创建对象。 这些对象通过方法进行通信。 每个对象都可以接收消息,发送消息和处理数据。
创建对象有两个步骤。 首先,我们创建一个类。 类是对象的模板。 它是一个蓝图,描述了类对象共享的状态和行为。 一个类可以用来创建许多对象。 在运行时从类创建的对象称为该特定类的实例。
simpleclass.php
<?php
class Simple {}
$object = new Simple();
print_r($object);
echo gettype($object), "\n";
在第一个示例中,我们创建一个简单的对象。
class Simple {}
这是一个简单的类定义。 模板的主体为空。 它没有任何数据或方法。
$object = new Simple();
我们创建Simple
类的新实例。 为此,我们使用了new
关键字。 $object
变量是创建对象的句柄。
print_r($object);
echo gettype($object), "\n";
我们使用print_r()
函数获取有关对象的信息,并使用gettype()
函数获取变量的类型。
$ php simpleclass.php
Simple Object
(
)
object
由于类定义为空,因此我们没有太多信息。 变量的类型为object
。
PHP 对象属性
对象属性是捆绑在类实例中的数据。 对象属性称为实例变量或成员字段。 实例变量是在类中定义的变量,该类中的每个对象都有一个单独的副本。
memberfields.php
<?php
class Person {
public $name = "";
}
$p1 = new Person();
$p1->name = "Jane";
$p2 = new Person();
$p2->name = "Beky";
echo $p1->name . "\n";
echo $p2->name . "\n";
在上面的 PHP 脚本中,我们有一个带有一个成员字段的Person
类。
$p1 = new Person();
$p1->name = "Jane";
我们创建一个Person
类的实例,并将$name
变量设置为"Jane"
。 我们使用->
运算符访问对象的属性。
$p2 = new Person();
$p2->name = "Beky";
我们创建Person
类的另一个实例。 在这里,我们将变量设置为"Beky"
。
echo $p1->name . "\n";
echo $p2->name . "\n";
我们将变量的内容打印到控制台。
$ php memberfields.php
Jane
Beky
我们看到了脚本的输出。 Person
类的每个实例都有$name
成员字段的单独副本。
PHP 方法
方法是在类主体内定义的函数。 它们用于通过对象的属性执行操作。 在 OOP 范式的封装概念中,方法至关重要。 例如,我们的AccessDatabase
类中可能有一个connect()
方法。 我们无需知道方法connect()
与数据库的连接方式如何。 我们只知道它用于连接数据库。 这对于划分编程中的职责至关重要,尤其是在大型应用中。
circle.php
<?php
class Circle {
public $radius;
function setRadius($radius) {
$this->radius = $radius;
}
function area() {
return $this->radius * $this->radius * M_PI;
}
}
$c = new Circle();
$c->setRadius(5);
echo $c->area(), "\n";
在代码示例中,我们有一个Circle
类。 我们定义了两种方法。
public $radius;
我们只有一个成员字段。 它是圆的半径。 public
关键字是访问说明符。 它表明该变量可以从外界完全访问。
function setRadius($radius) {
$this->radius = $radius;
}
这是setRadius()
方法。 这是一个正常的 PHP 函数。 我们将在类内定义的函数称为方法。 $this
变量是一个特殊变量,我们用它来访问方法中的成员字段。
function area() {
return $this->radius * $this->radius * M_PI;
}
area()
方法返回圆的面积。 M_PI
是内置常数。
$ php circle.php
78.539816339745
运行示例将给出此输出。
PHP 访问修饰符
访问修饰符设置方法和成员字段的可见性。 PHP 具有三个访问修饰符:public
,protected
和private
。 可以从任何地方访问public
成员。 protected
成员只能在类本身内以及被继承的和父类访问。 private
成员只能由定义该成员的类访问。
访问修饰符可防止意外修改数据。 它们使程序更强大。
access1.php
<?php
class Person {
public $name = "";
private $age;
}
$p = new Person();
$p->name = "Jane";
#$p->age = 17;
echo $p->name . "\n";
在上面的 PHP 脚本中,我们有两个成员字段; 一个被宣布为公开,另一个被宣布为私有。
$p->name = "Jane";
#$p->age = 17;
我们从外部访问$name
成员。 在外部世界,我们的意思是“不在类中”。 可以,因为$name
变量被声明为public
。 无法访问$age
成员。 private
修饰符禁止这样做。 如果取消注释代码行,则将出现“致命错误:无法访问私有属性Person::$age
”错误。
access2.php
<?php
class Base {
public $name = "Base";
protected $id = 6124;
private $is_defined = "yes";
}
class Derived extends Base {
public function info() {
echo "This is Derived class\n";
echo "Members inherited: \n";
echo $this->name . "\n";
echo $this->id . "\n";
echo $this->is_defined . "\n";
}
}
$derived = new Derived();
$derived->info();
在此 PHP 脚本中,我们有一个Derived
类,该类扩展了Base
类。 Base
类具有三个成员字段,所有成员字段均具有不同的访问修饰符。 $is_defined
成员未继承。 private
修饰符可以防止这种情况。
public function info() {
info()
方法具有public
访问修饰符。 这意味着可以在类环境之外调用它。
$ php access2.php
This is Derived class
Members inherited:
Base
6124
运行 PHP 脚本,我们收到此输出。 公共成员和受保护成员是继承的,私有成员则不是。
system.php
<?php
class SysInfo {
private function get_date() {
return date("Y/m/d");
}
private function get_version() {
return phpversion();
}
public function getInfo() {
$date = $this->get_date();
$version = $this->get_version();
echo "The date is: $date\n";
echo "The PHP version is: $version\n";
}
}
$sys = new SysInfo();
$sys->getInfo();
#$sys->get_date();
在此脚本中,我们有一个SysInfo
类。 它将一些系统信息输出到控制台。 我们有两个私有职能和一个公共职能。 这里的私有方法仅用于SysInfo
类的内部工作。 他们不应该在类外被调用。
$sys = new SysInfo();
$sys->getInfo();
#$sys->get_date();
我们创建SysInfo
类的实例,并调用可公开使用的getInfo()
方法。 getInfo()
方法在内部使用私有方法来完成其工作。 取消注释最后的代码行会产生错误。
PHP 方法重载
方法重载允许创建多个具有相同名称的方法,它们的输入类型彼此不同。
方法重载有什么好处? Qt4 库提供了一个很好的用法示例。 QPainter
类具有三种绘制矩形的方法。 它们的名称为drawRect()
,其参数不同。 一个引用一个浮点矩形对象,另一个引用一个整数矩形对象,最后一个引用四个参数,x
,y
,width
,height
。 如果开发 Qt 的 C++ 语言没有方法重载,则库的创建者必须将其命名为drawRectRectF()
,drawRectRect()
和drawRectXYWH()
之类的方法。 方法重载的解决方案更为优雅。
overloading1.php
<?php
class Sum {
public function getSum() {
return 0;
}
public function getSum($x) {
return $x;
}
public function getSum($x, $y) {
return $x + $y;
}
}
$s = new Sum();
echo $s->getSum() . "\n" ;
echo $s->getSum(5) . "\n" ;
echo $s->getSum(3, 4) . "\n" ;
这是一种方法重载,我们从 C# ,Java 或 C++ 等语言知道。 但这在 PHP 中不起作用。 运行此示例,我们得到以下错误:“致命错误:无法重新声明Sum::getSum()
”。 PHP 函数默认可以接受任意数量的变量。
为了模拟 PHP 中的方法重载,我们使用func_get_args()
函数。
overloading2.php
<?php
class Sum {
public function getSum() {
$args = func_get_args();
if (empty($args)) return 0;
foreach ($args as $arg) {
$sum += $arg;
}
return $sum;
}
}
$s = new Sum();
echo $s->getSum() . "\n" ;
echo $s->getSum(5) . "\n" ;
echo $s->getSum(3, 4) . "\n" ;
echo $s->getSum(3, 4, 7) . "\n" ;
这次,脚本将运行。
$args = func_get_args();
func_get_args()
函数返回一个包含函数的参数列表的数组。
foreach ($args as $arg) {
$sum += $arg;
}
我们遍历数组的所有成员,然后计算总和。
echo $s->getSum() . "\n" ;
echo $s->getSum(5) . "\n" ;
echo $s->getSum(3, 4) . "\n" ;
echo $s->getSum(3, 4, 7) . "\n" ;
我们用不同数量的输入调用相同的方法名称。
$ php overloading2.php
0
5
7
14
这是overloading2.php
脚本的输出。
PHP 构造器
构造器是一种特殊的方法。 创建对象时会自动调用它。 构造器的目的是初始化对象的状态。 PHP 中的构造器名称为__construct()
(带有两个下划线)。
constructor.php
<?php
class Song {
function __construct() {
echo "Song object is created \n";
}
}
$song = new Song();
我们有一个Song
类。 此类具有构造器,该构造器将消息输出到控制台。
$song = new Song();
这是创建对象并调用构造器的时间。 我们在控制台中收到一条消息。
$ php constructor.php
Song object is created
这是脚本的输出。
构造器经常会争论。
constructor2.php
<?php
class Song {
function __construct($song) {
echo "Song $song is created \n";
}
}
$song = new Song("Bad romance");
我们对前面的示例进行一些修改。 我们将一个值传递给构造器。
function __construct($song) {
echo "Song $song is created \n";
}
传递的参数存储在本地$song
变量中。
$ php constructor2.php
Song Bad romance is created
现在,我们有一条消息,其中的歌曲标题印在控制台上。
在下一个示例中,我们初始化类的数据成员。 变量的初始化是构造器的典型工作。
friend.php
<?php
class Friend {
private $born;
private $name;
function __construct($name, $born) {
$this->name = $name;
$this->born = $born;
}
function getInfo() {
echo "My friend $this->name was born in $this->born\n";
}
}
$friend = new Friend("Monika", 1990);
$friend->getInfo();
我们有一个带有数据成员和方法的Friend
类。
private $born;
private $name;
类定义中有两个变量。 private
关键字是访问修饰符。 它是一种封装。 private
关键字是限制性最强的修饰符。 它仅允许有问题的对象访问变量。 没有子孙,没有其他物件。 稍后会更多有关此主题的信息。
function __construct($name, $born) {
$this->name = $name;
$this->born = $born;
}
在构造器中,我们启动两个数据成员。 $this
变量是用于引用对象变量的处理器。
$friend = new Friend("Monika", 1990);
$friend->getInfo();
我们创建带有两个参数的Friend
对象。 然后,我们调用对象的getInfo()
方法。 要调用对象方法,我们使用->
运算符。
$ php friend.php
My friend Monika was born in 1990
PHP 类常量
PHP 可以创建类常量。 这些常量不属于具体对象。 他们属于阶级。 按照约定,常量用大写字母表示。
constants.php
<?php
class Math {
const PI = 3.14159265359;
public function getPI() {
echo self::PI;
}
}
$math = new Math();
echo Math::PI, "\n";
echo $math->getPI(), "\n";
我们有一个带有PI
常数的Math
类。
const PI = 3.14159265359;
const
关键字用于定义常数。
public function getPI() {
echo self::PI;
}
使用self
关键字后接两个冒号从方法内部访问类常量。
echo Math::PI, "\n";
echo $math->getPI(), "\n";
我们将PI
常量打印到控制台。 在第一种情况下,我们通过引用类名称来获得常量值,然后是两个冒号和一个常量名称。 请注意,不需要任何对象即可获取类常量。 在第二种情况下,我们使用对象方法。
PHP instanceof
关键字
instanceof
关键字用于确定 PHP 变量是否是某个类的实例化对象。
instanceof.php
<?php
class Cat {}
class Dog {}
class Bird {}
$objects = [ new Cat(), new Dog(), new Cat(), new Bird(), new Bird(),
new Dog(), new Dog(), new Cat(), new Bird() ];
shuffle($objects);
foreach ($objects as $object) {
if ($object instanceof Cat) {
echo "It is a Cat\n";
} elseif ($object instanceof Dog) {
echo "It is a Dog\n";
} else if ($object instanceof Bird) {
echo "It is a Bird\n";
}
}
在上面的脚本中,我们有三个类:Cat
,Dog
和Bird
。 我们遍历数组并为每个数组值打印类。
$objects = [ new Cat(), new Dog(), new Cat(), new Bird(), new Bird(),
new Dog(), new Dog(), new Cat(), new Bird() ];
我们创建这些对象的数组。
shuffle($objects);
我们对数组进行混洗。 在这一点上,我们不知道数组值的类类型。
if ($object instanceof Cat) {
echo "It is a Cat\n";
}
在这里,我们使用instanceof
关键字找出类的类型。
$ php instanceof.php
It is a Bird
It is a Cat
It is a Cat
It is a Dog
It is a Dog
It is a Cat
It is a Dog
It is a Bird
It is a Bird
我们可能会得到此输出。
PHP __toString
方法
当我们在对象实例中使用print
或echo
关键字时,将调用__toString()
特殊方法。 我们将在下面的示例中对此进行演示。
tostring.php
<?php
class Cat {
public $name;
public $age;
function __construct($name, $age) {
$this->age = $age;
$this->name = $name;
}
function __toString() {
return "Cat: $this->name, Age: $this->age \n";
}
}
$missy = new Cat("Missy", 6);
$lucky = new Cat("Lucky", 4);
print $missy;
echo $lucky;
我们有一个Cat
类,其中定义了__toString()
特殊方法。
function __toString() {
return "Cat: $this->name, Age: $this->age \n";
}
该方法显示有关对象的基本信息。
$missy = new Cat("Missy", 6);
$lucky = new Cat("Lucky", 4);
我们创建Cat
类的两个对象。
print $missy;
echo $lucky;
我们在它们上使用print
或echo
关键字。
$ php tostring.php
Cat: Missy, Age: 6
Cat: Lucky, Age: 4
这是我们运行脚本时得到的。
PHP 继承
继承是使用已经定义的类形成新类的方法。 新形成的类称为派生的类,我们派生的类称为基类。 继承的重要好处是代码重用和降低程序的复杂性。 派生类(后代)将覆盖或扩展基类(祖先)的功能。
derived.php
<?php
class Base {
function __construct() {
echo "Construction of Base class \n";
}
}
class Derived extends Base {
function __construct() {
parent::__construct();
echo "Construction of Derived class \n";
}
}
$obj1 = new Base();
$obj2 = new Derived();
在此 PHP 脚本中,我们有两个类:Base
类和Derived
类。 Derived
类继承自Base
类。
class Derived extends Base {
在 PHP 中,我们使用extends
关键字创建继承关系。
function __construct() {
parent::__construct();
echo "Construction of Derived class \n";
}
在Derived
类的构造器中,我们称为父构造器。 我们使用parent
关键字,后接两个冒号和__construct()
方法。 父类的构造器必须显式调用。
$obj1 = new Base();
$obj2 = new Derived();
我们实例化了Base
和Derived
类。
$ php derived.php
Construction of Base class
Construction of Base class
Construction of Derived class
这是 PHP 脚本的输出。
接下来是一个更复杂的示例。
inheritance.php
<?php
abstract class Being {
protected $isAlive = true;
public function isAlive() {
if ($this->isAlive) {
echo "Being is alive\n";
} else {
echo "Being is not alive\n";
}
}
public function kill() {
$this->isAlive = false;
}
}
abstract class Animal extends Being {
protected $age;
public function __construct($age) {
$this->age = $age;
}
protected function setAge($age) {
$this->age = $age;
}
public function getAge() {
return $this->age;
}
}
class Cat extends Animal {
private $name;
public function __construct($name, $age) {
$this->name = $name;
parent::__construct($age);
}
public function getName() {
return $this->name;
}
}
$cat = new Cat("Cici", 4);
$cat->isAlive();
echo $cat->getName() . " is " . $cat->getAge() . " years old\n";
$cat->kill();
$cat->isAlive();
我们在这里使用了几个新概念。 在代码示例中,我们有三个类:Being
,Animal
和Cat
。 Animal
类继承自Being
类。 Cat
类继承自Animal
类。 类继承未声明为私有的方法和数据成员。
abstract class Being {
Being
类声明为abstract
。 abstract
关键字禁止类的实例化。 创建类Being
的实例没有多大意义。
protected $isAlive = true;
声明$isAlive
数据成员为protected
。 此类成员只能由定义它们的类及其子孙访问。
abstract class Animal extends Being {
Animal
类也被声明为抽象的。 它继承自Being
类。 为此,我们使用extends
关键字。 Animal
是后代。 它继承了Being
基类的方法和变量。
class Cat extends Animal {
Cat
类继承自Animal
类。 它继承自Animal
类,也间接继承自Being
类。 它没有声明为抽象,这意味着我们可以实例化它。
parent::__construct($age);
在Cat
类的构造器中,我们使用parent
关键字,后跟两个冒号和__construct()
方法来调用父构造器。 父类的构造器必须显式调用。
$cat = new Cat("Cici", 4);
$cat->isAlive();
echo $cat->getName() . " is " . $cat->getAge() . " years old\n";
$cat->kill();
$cat->isAlive();
我们创建了 4 岁的新猫:Cici。 然后,我们在 cici 对象上调用函数。 请注意,不是在Cat
类中创建而是从父类继承的方法的用法。
$ php inheritance.php
Being is alive
Cici is 4 years old
Being is not alive
脚本的输出。
PHP 抽象类和方法
PHP 5 引入了抽象类和方法。 抽象类无法实例化。 如果一个类至少包含一个抽象方法,则也必须将其声明为抽象方法。 抽象方法无法实现,它们仅声明方法的签名。 当我们从抽象类继承时,所有抽象方法都必须由派生类实现。 此外,必须以相同或较少受限制的可见性声明这些方法。
与接口不同,抽象类可能具有完全实现的方法,也可能具有定义的成员字段。 因此,抽象类可以提供部分实现。 程序员经常将一些通用功能放入抽象类中。 这些抽象类随后会被子类化以提供更具体的实现。 例如,Qt 图形库具有QAbstractButton
,它是按钮小部件的抽象基类,提供按钮所共有的功能。 按钮Q3Button
,QCheckBox
,QPushButton
,QRadioButton
和QToolButton
都从此基本抽象类继承。
正式地说,抽象类用于强制执行协议。 协议是所有实现对象都必须支持的一组操作。
abstract.php
<?php
abstract class Drawing {
protected $x = 0;
protected $y = 0;
public abstract function area();
public function getCoordinates() {
echo "\$x is $this->x\n";
echo "\$y is $this->y\n";
}
}
class Circle extends Drawing {
private $radius;
public function __construct($x, $y, $r) {
$this->radius = $r;
$this->x = $x;
$this->y = $y;
}
public function area() {
return $this->radius * $this->radius * pi();
}
public function __toString() {
return "Circle, at x: $this->x, y: $this->y, radius: $this->radius";
}
}
$o = new Circle(12, 45, 22);
echo "$o \n";
echo "Area of the circle: " . $o->area() . "\n";
echo $o->getCoordinates();
在我们的 PHP 脚本中,我们有一个抽象基Drawing
类。 该类定义两个成员字段,定义一个方法并声明一个方法。 一种方法是抽象的,另一种是完全实现的。 Drawing
类是抽象的,因为我们无法绘制它。 我们可以画一个圆,一个点或一个正方形。 Drawing
类对我们可以绘制的对象具有一些通用功能。
class Circle extends Drawing {
Circle
是Drawing
类的子类。 它必须实现抽象区域方法。
$ php abstract.php
Circle, at x: 12, y: 45, radius: 22
Area of the circle: 1520.53084434
$x is 12
$y is 45
Output of the script.
PHP 接口
遥控器是观众和电视之间的接口。 它是此电子设备的接口。 外交礼仪指导外交领域的所有活动。 道路规则是驾车者,骑自行车者和行人必须遵守的规则。 编程中的接口类似于前面的示例。
接口是:
- API
- 合约
对象通过其公开的方法与外界交互。 实际的实现对程序员而言并不重要,或者也可能是秘密的。 公司可能会出售图书馆,但它不想透露实际的实现情况。 程序员可能会在 GUI 工具箱的窗口上调用maximize()
方法,但对如何实现此方法一无所知。 从这个角度来看,接口是对象与外界交互而不暴露其内部工作过多的方法。
从第二个角度来看,接口就是契约。 如果达成协议,则必须遵循。 它们用于设计应用的架构,并有助于组织代码。
接口是完全抽象的类型。 它们使用interface
关键字声明。 接口只能具有方法签名和常量。 接口中声明的所有方法签名必须是公共的。 他们不能具有完全实现的方法,也不能具有成员字段。 一个 PHP 类可以实现任何数量的接口。 一个接口还可以扩展任何数量的接口。 实现接口的类必须实现接口的所有方法签名。
接口用于模拟多重继承。 一个 PHP 类只能扩展一个类。 一个 PHP 类可以实现多个接口。 使用接口的多重继承与继承方法和变量无关。 它是关于继承想法或合同的,这些想法或合同由接口描述。
接口和抽象类之间有一个重要的区别。 抽象类为继承层次结构中相关的类提供部分实现。 另一方面,可以通过彼此不相关的类来实现接口。 例如,我们有两个按钮:经典按钮和圆形按钮。 两者都继承自抽象按钮类,该类为所有按钮提供了一些通用功能。 实现类是相关的,因为它们都是按钮。 另一个示例可能具有类Database
和SignIn
。 它们彼此无关。 我们可以应用ILoggable
接口,该接口将迫使他们创建执行日志记录的方法。
simpleinterface.php
<?php
interface IInfo {
public function do_inform();
}
class Some implements IInfo {
public function do_inform() {
echo "This is a Some class\n";
}
}
$sm = new Some();
$sm->do_inform();
这是演示接口的简单 PHP 脚本。
interface IInfo {
public function do_inform();
}
这是接口IInfo
。 它具有do_inform()
方法签名。
class Some implements IInfo {
我们使用implements
从接口实现。
public function do_inform() {
echo "This is a Some class\n";
}
该类提供了do_inform()
方法的实现。
下一个示例显示了一个类如何实现多个接口。
interface.php
<?php
interface Device {
public function switch_on();
public function switch_off();
}
interface Volume {
public function volume_up();
public function volume_down();
}
interface Pluggable {
public function plug_in();
public function plug_off();
}
class CellPhone implements Device, Volume, Pluggable {
public function switch_on() { echo "Switching on\n"; }
public function switch_off() { echo "Switching off\n"; }
public function volume_up() { echo "Volume up\n"; }
public function volume_down() { echo "Volume down\n"; }
public function plug_in() { echo "Plugging in\n"; }
public function plug_off() { echo "Plugging off\n"; }
}
$o = new CellPhone();
$o->switch_on();
$o->volume_up();
$o->plug_in();
我们有一个CellPhone
类,它从三个接口继承。
class CellPhone implements Device, Volume, Pluggable {
该类实现所有三个接口,并用逗号分隔。 CellPhone
类必须实现来自所有三个接口的所有方法签名。
$ php interface.php
Switching on
Volume up
Plugging in
运行 PHP 脚本。
下一个示例显示接口如何从多个其他接口扩展。
extendinginterfaces.php
<?php
interface IInfo {
public function do_inform();
}
interface IVersion {
public function get_version();
}
interface ILog extends IInfo, IVersion {
public function do_log();
}
class DBConnect implements ILog {
public function do_inform() {
echo "This is a DBConnect class\n";
}
public function get_version() {
echo "Version 1.02\n";
}
public function do_log() {
echo "Logging\n";
}
public function connect() {
echo "Connecting to the database\n";
}
}
$db = new DBConnect();
$db->do_inform();
$db->get_version();
$db->do_log();
$db->connect();
在此 PHP 脚本中,我们定义了三个接口。 扩展接口使我们可以组织它们。
interface ILog extends IInfo, IVersion {
public function do_log();
}
ILog
接口扩展了其他两个接口。
public function do_inform() {
echo "This is a DBConnect class\n";
}
DBConnect
类实现do_inform()
方法。 该方法由该类实现的ILog
接口继承。
PHP 多态
多态是以不同方式将运算符或函数用于不同数据输入的过程。 实际上,多态意味着如果类 B 从类 A 继承,那么它不必继承关于类 A 的所有内容。 它可以完成 A 类所做的某些事情。
通常,多态是以不同形式出现的能力。 从技术上讲,它是重新定义派生类的方法的能力。 多态与将特定实现应用于接口或更通用的基类有关。
polymorphism.php
<?php
abstract class Shape {
private $x = 0;
private $y = 0;
public abstract function area();
}
class Rectangle extends Shape {
function __construct($x, $y) {
$this->x = $x;
$this->y = $y;
}
function area() {
return $this->x * $this->y;
}
}
class Square extends Shape {
function __construct($x) {
$this->x = $x;
}
function area() {
return $this->x * $this->x;
}
}
$shapes = [ new Square(5), new Rectangle(12, 4), new Square(8) ];
foreach ($shapes as $shape) {
echo $shape->area() . "\n";
}
在上面的 PHP 脚本中,我们有一个抽象的Shape
类。 此类演变为两个后代类别:Rectangle
和Square
。 两者都提供了自己的area()
方法实现。 多态为 OOP 系统带来了灵活性和可伸缩性。
这是 PHP 中 OOP 描述的第一部分。
PHP 中的面向对象编程 II
在 PHP 教程的这一章中,我们将继续描述 PHP 中的 OOP。
PHP static
关键字
我们可以将类属性和方法声明为static
。 static
属性和方法不属于该类的实例。 他们属于阶级本身。 可通过范围解析运算符::
访问它们。
staticmethod.php
<?php
class Sys {
public static function println($string) {
echo "$string\n";
}
}
Sys::println("PHP");
Sys::println("PERL");
Sys::println("Python");
Sys::println("Pike");
在上面的 PHP 脚本中,我们有一个静态的println()
方法。 它打印一个字符串并开始新的一行。 此示例受 Java 语言启发。
Sys::println("PHP");
我们不需要对象来调用println()
方法。 我们通过指定类名称,后跟双冒号运算符和方法名称来调用static
方法。
$ php static1.php
PHP
PERL
Python
Pike
这是脚本的输出。
staticvariable.php
<?php
class Math {
public static $PI = 3.14159265359;
}
echo Math::$PI . "\n";
现在,我们有一个带有static
变量的示例。
echo Math::$PI . "\n";
我们通过指定类名,范围解析运算符和变量名来访问变量。
PHP final
关键字
最终方法不能被覆盖,最终类不能被扩展。 final
关键字取决于应用的设计。 某些类不应扩展,某些方法不应重写。 此行为由final
关键字强制执行。
finalmethod.php
<?php
class Base {
final function say() {
echo "Base class";
}
}
class Derived extends Base {
function say() {
echo "Derived class";
}
}
该 PHP 脚本无法编译。 我们收到一个错误“无法覆盖最终方法Base::say()
”。
finalclass.php
<?php
final class Math {
static function getPI() {
return 3.141592;
}
}
class DerivedMath extends Math {
function say() {
echo "DerivedMath class";
}
}
在先前的 PHP 脚本中,我们有一个原型基础Math
类。 该类的唯一目的是为程序员提供一些有用的方法和常量。 (出于简单起见,在我们的例子中,我们只有一种方法。)它不是为了扩展而创建的。 为了防止不知情的其他程序员从此类中派生,创建者创建了final
类。 如果您尝试运行此 PHP 脚本,则会出现以下错误:“致命错误:类DerivedMath
可能不会从最终类(Math
)继承”。
PHP 深拷贝与浅拷贝
数据复制是编程中的重要任务。 对象是 OOP 中的复合数据类型。 对象中的成员字段可以按值或按引用存储。 可以以两种方式执行复制。
浅表副本将所有值和引用复制到新实例中。 引用所指向的数据不会被复制; 仅指针被复制。 新的引用指向原始对象。 对引用成员的任何更改都会影响两个对象。
深拷贝将所有值复制到新实例中。 如果成员存储为引用,则深层副本将对正在引用的数据执行深层副本。 创建引用对象的新副本,并存储指向新创建的对象的指针。 对这些引用对象的任何更改都不会影响该对象的其他副本。 深拷贝是完全复制的对象。
在 PHP 中,我们有一个copy
关键字,默认情况下会执行浅表复制。 它调用对象的__clone()
方法。 我们可以实现创建自定义深层副本的方法。 在 PHP 中,所有对象都是通过引用分配的。
接下来的两个示例对对象执行浅复制和深复制。
shallowcopy.php
<?php
class Object {
public $id;
public $size;
public $color;
function __construct($id, $size, $color) {
$this->id = $id;
$this->size = $size;
$this->color = $color;
}
}
class Color {
public $red;
public $green;
public $blue;
function __construct($red, $green, $blue) {
$this->red = $red;
$this->green = $green;
$this->blue = $blue;
}
}
$color = new Color(23, 42, 223);
$object1 = new Object(23, "small", $color);
$object2 = clone $object1;
$object2->id++;
$object2->color->red = 255;
$object2->size = "big";
print_r($object1);
print_r($object2);
在上面的 PHP 脚本中,我们定义了两个自定义对象:Object
和Color
。 Object
对象将具有对Color
对象的引用。
$color = new Color(23, 42, 223);
我们创建Color
对象的实例。
$object1 = new Object(23, "small", $color);
创建对象对象的实例。 它将Color
对象的实例传递给其构造器。
$object2 = clone $object1;
我们执行Object
对象的浅表副本。
$object2->id++;
$object2->color->red = 255;
$object2->size = "big";
在这里,我们修改克隆对象的成员字段。 我们增加 id,更改颜色对象的红色部分,并将大小更改为big
。
print_r($object1);
print_r($object2);
我们使用print_r()
函数比较结果。
$ php shallowcopy.php
Object Object
(
[id] => 23
[size] => small
[color] => Color Object
(
[red] => 255
[green] => 42
[blue] => 223
)
)
Object Object
(
[id] => 24
[size] => big
[color] => Color Object
(
[red] => 255
[green] => 42
[blue] => 223
)
)
我们可以看到 ID 不同:23 与 24。大小不同:small
与big
。 但是,这两个实例的颜色对象的红色部分相同:255。更改克隆对象的成员值不会影响原始对象。 更改引用对象的成员也影响了原始对象。 换句话说,两个对象都引用内存中的同一颜色对象。
要更改此行为,我们接下来将做一个深层复制。
deepcopy.php
<?php
class Object {
public $id;
public $size;
public $color;
function __construct($id, $size, $color) {
$this->id = $id;
$this->size = $size;
$this->color = $color;
}
function __clone() {
$red = $this->color->red;
$green = $this->color->green;
$blue = $this->color->blue;
$this->color = new Color($red, $green, $blue);
}
}
class Color {
public $red;
public $green;
public $blue;
function __construct($red, $green, $blue) {
$this->red = $red;
$this->green = $green;
$this->blue = $blue;
}
}
$color = new Color(23, 42, 223);
$object1 = new Object(23, "small", $color);
$object2 = clone $object1;
$object2->id++;
$object2->color->red = 255;
$object2->size = "big";
print_r($object1);
print_r($object2);
在此 PHP 脚本中,我们实现了__clone()
方法。
function __clone() {
$red = $this->color->red;
$green = $this->color->green;
$blue = $this->color->blue;
$this->color = new Color($red, $green, $blue);
}
在__clone()
方法内部,我们复制红色,绿色和蓝色成员字段并创建一个新的Color
对象。 现在,$color
字段指向另一个Color
对象。
$ php deepcopy.php
Object Object
(
[id] => 23
[size] => small
[color] => Color Object
(
[red] => 23
[green] => 42
[blue] => 223
)
)
Object Object
(
[id] => 24
[size] => big
[color] => Color Object
(
[red] => 255
[green] => 42
[blue] => 223
)
)
现在,引用的Color
对象的红色部分不相同。 原始对象保留了其先前的 23 值。
PHP 异常
异常是为处理异常的发生而设计的,这些特殊情况会改变程序执行的正常流程。 引发或引发异常并引发异常。
在执行应用期间,许多事情可能出错。 磁盘可能已满,我们无法保存文件。 互联网连接可能断开,我们的应用尝试连接到站点。 所有这些都可能导致我们的应用崩溃。 为避免发生这种情况,我们必须应对可能发生的所有可能的错误。 为此,我们可以使用异常处理。
从 PHP 5 开始,可以使用异常。大多数 PHP 错误仍然使用旧的错误报告,而不是异常。 使用set_error_handler()
,我们可以解决此问题。
zerodiv.php
<?php
set_error_handler("error_handler");
function error_handler($errno, $errstring, $errfile, $line, $trace) {
throw new ErrorException($errstring, $errno, 0, $errfile, $line);
}
try {
$a = 0;
$b = 32;
$c = $b / $a;
} catch(ErrorException $e) {
echo "Error occurred\n";
echo $e->getMessage(), "\n";
}
在上面的 PHP 脚本中,我们有意将数字除以零。 这会导致错误。 该错误也不是异常,并且不会被catch
关键字捕获。
set_error_handler("error_handler");
set_error_handler()
函数设置用户定义的错误处理器函数。
function error_handler($errno, $errstring, $errfile, $line, $trace) {
throw new ErrorException($errstring, $errno, 0, $errfile, $line);
}
在set_error_handler()
函数内部,我们抛出了ErrorException
。 稍后,此异常由catch
关键字捕获。
try {
$a = 0;
$b = 32;
$c = $b / $a;
}
我们正在检查错误的代码放在try
关键字之后的块中。
} catch(Exception $e) {
echo $e->getMessage();
}
catch
关键字用于捕获异常。 要了解更多信息,我们在异常对象上调用getMessage()
方法。
$ php zerodiv.php
Error occurred
Division by zero
这是我们的 PHP 脚本的输出。
Exception
是所有异常的基类。 我们可以创建派生自该基类的异常。
myexception.php
<?php
define("LIMIT", 333);
class BigValueException extends Exception {
public function __construct($message) {
parent::__construct($message);
}
}
$a = 34325;
try {
if ($a > LIMIT) {
throw new BigValueException("Exceeded the maximum value allowed\n");
}
} catch (BigValueException $e) {
echo $e->getMessage();
}
假设我们处于无法处理大量数字的情况。
define("LIMIT", 333);
大于此常量的数字在我们的 PHP 脚本中被视为big
。
class BigValueException extends Exception {
我们有一个BigValueException
类。 此类通过extends
关键字从Exception
类派生。
public function __construct($message) {
parent::__construct($message);
}
在构造器内部,我们称为父级的构造器。
if ($a > LIMIT) {
throw new BigValueException("Exceeded the maximum value allowed\n");
}
如果该值大于限制,则抛出自定义异常。 我们给异常消息"Exceeded the maximum value allowed\n"
。
} catch (BigValueException $e) {
echo $e->getMessage();
}
我们捕获到异常并将其消息打印到控制台。
PHP 构造器重载
PHP 不支持直接的构造器重载。 换句话说,每个类只能定义一个构造器。 许多已经知道 Java 或 C# 语言的程序员都在寻找 PHP 中的类似功能。 我们有两种方法可以处理此问题。
第一种解决方案基于func_get_args()
函数。 第二种解决方案使用工厂模式。
constructors.php
<?php
class Book {
private $author = "not specified";
private $title = "not specified";
private $year = "not specified";
public function __construct() {
$args = func_get_args();
foreach(["title", "author", "year"] as $item) {
if(empty($args)) {
break;
}
$this->$item = array_shift($args);
}
}
public function __toString() {
return "Author: $this->author\nTitle: $this->title\nPublished: $this->year\n\n";
}
}
$book1 = new Book("Stephen Prata", "C Primer Plus");
echo $book1;
$book2 = new Book("Joshua Bloch", "Effective Java", 2008);
echo $book2;
在上面的脚本中,我们有一个Book
类。 我们使用 2 和 3 参数实例化该类。
private $author = "not specified";
private $title = "not specified";
private $year = "not specified";
我们定义了三个成员字段。 它们的初始值为"not specified"
。
$args = func_get_args();
func_get_args()
函数返回一个包含函数的参数列表的数组。 这样的想法是:构造器中的代码是动态的; 它取决于传递给它的参数。
foreach(["title", "author", "year"] as $item) {
我们使用foreach
关键字浏览所有成员字段。
$this->$item = array_shift($args);
构造器中最基本的任务之一是初始化类的成员字段。 这是通过上面的代码行完成的。 array_shift()
函数从数组中删除第一项并返回它。
$book1 = new Book("Stephen Prata", "C Primer Plus");
...
$book2 = new Book("Joshua Bloch", "Effective Java", 2008);
我们有两个不同的构造器。 第一个带有 2 个参数,第二个带有 3 个参数。
$ php constructors.php
Author: C Primer Plus
Title: Stephen Prata
Published: not specified
Author: Effective Java
Title: Joshua Bloch
Published: 2008
这是脚本的结果。
下一个代码示例使用工厂模式模拟构造器重载。 它是 OOP 中的创建模式之一。 该模式创建对象时未指定要创建的对象的确切类。 更一般地,术语工厂方法通常用于指代主要目的是创建对象的任何方法。
factory.php
<?php
class Cat {
private $name = "unspecified";
private $age = "unspecified";
public static function withName($name) {
$cat = new Cat();
$cat->name = $name;
return $cat;
}
public static function withAge($age) {
$cat = new Cat();
$cat->age = $age;
return $cat;
}
public static function fullCat($name, $age) {
$cat = new Cat();
$cat->name = $name;
$cat->age = $age;
return $cat;
}
public function __toString() {
return "Name: $this->name, Age: $this->age\n";
}
}
$cici = Cat::withName("Cici");
echo $cici;
$missy = Cat::withAge(6);
echo $missy;
$lucky = Cat::fullCat("Lucky", 4);
echo $lucky;
上面的 PHP 脚本中有一个Cat
工厂类。 它具有三种不同的静态函数。 它们每个都返回一个特定的Cat
对象。
private $name = "unspecified";
private $age = "unspecified";
我们有两个成员字段。 它们的初始值为"not specified"
。
public static function withName($name) {
$cat = new Cat();
$cat->name = $name;
return $cat;
}
这是静态的withName()
函数。 此函数创建Cat
类的实例。 它设置name
成员字段并返回对象。
$cici = Cat::withName("Cici");
echo $cici;
我们使用其中一种工厂方法创建猫的实例。 我们回荡对象。 即调用该类的__toString()
方法。
$ php factory.php
Name: Cici, Age: unspecified
Name: unspecified, Age: 6
Name: Lucky, Age: 4
脚本的输出。
在 PHP 教程的这一部分中,我们继续讨论 PHP 中的面向对象编程。
PHP Carbon 教程
PHP Carbon 教程展示了如何在带有 Carbon 包的 PHP 中使用日期和时间。 我们使用nesbot/carbon
包。
PHP Carbon
Carbon 是一个 PHP 日期时间库。 它是 PHP DateTime
类的扩展。
PHP Carbon 设置
该包随 composer 一起安装。
$ composer req nesbot/carbon
我们安装nesbot/carbon
包。
今天的日期
以下示例显示如何获取今天的日期。
today.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Carbon\Carbon;
$now = Carbon::now();
echo "$now\n";
$today = Carbon::today();
echo "$today\n";
Carbon::now()
返回当前日期和时间,Carbon:today()
返回当前日期。
$ php today.php
2019-05-07 10:20:54
2019-05-07 00:00:00
这是一个示例输出。
Carbon::yesterday()
为昨天创建一个 Carbon 实例,为明天创建Carbon::tomorrow()
。
yes_tom.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Carbon\Carbon;
$yes = Carbon::yesterday();
echo "Yesterday: $yes\n";
$tom = Carbon::tomorrow();
echo "Tomorrow: $tom\n";
该示例显示了昨天和明天的日期。
Carbon 来创建
Carbon 实例可以使用几种创建方法来创建。
create.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Carbon\Carbon;
$d1 = Carbon::create(2018, 8, 25, 22, 48, 00);
echo $d1 . "\n";
$d2 = Carbon::create(2018, 8, 25, 22, 48, 00, 'Europe/Moscow');
echo $d2 . "\n";
$d3 = Carbon::createFromDate(2018, 8, 14, 'America/Chicago');
echo $d3 . "\n";
$d4 = Carbon::createFromTimestamp(1);
echo $d4 . "\n";
该示例使用四种不同的方法创建 Carbon 实例。
$d1 = Carbon::create(2018, 8, 25, 22, 48, 00);
create()
方法根据日期和时间部分生成一个 Carbon 实例。
$d2 = Carbon::create(2018, 8, 25, 22, 48, 00, 'Europe/Moscow');
在第二个示例中,我们还提供了一个时区。
$d3 = Carbon::createFromDate(2018, 8, 14, 'America/Chicago');
使用createFromDate()
,我们创建一个带有日期部分的 Carbon 实例。
$d4 = Carbon::createFromTimestamp(1);
createFromTimestamp()
从 Unix 时间创建一个 Carbon 实例。
$ php create.php
2018-08-25 22:48:00
2018-08-25 22:48:00
2018-08-14 03:33:16
1970-01-01 01:00:01
This is a sample output.
Carbon 相对修饰符
碳实例可以通过相对修饰符来创建,例如下一个星期五或一年之前。
relative_modifiers.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Carbon\Carbon;
echo new Carbon('tomorrow') . "\n";
echo new Carbon('yesterday') . "\n";
echo new Carbon('next wednesday') . "\n";
echo new Carbon('last friday') . "\n";
echo new Carbon('this saturday') . "\n";
echo new Carbon('1 year ago') . "\n";
该示例使用几个修饰符创建 Carbon 实例。
$ php relative_modifiers.php
2019-05-08 00:00:00
2019-05-06 00:00:00
2019-05-08 00:00:00
2019-05-03 00:00:00
2019-05-11 00:00:00
2018-05-07 11:53:03
This is a sample output.
Carbon next()
和previous()
next()
和previous()
方法给出一周中给定日期的下一个/上一个出现。
next_previous.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Carbon\Carbon;
$now = Carbon::now();
echo "$now\n";
$next_monday = $now->next(Carbon::MONDAY);
echo "Next monday: $next_monday\n";
$prev_monday = $now->previous(Carbon::MONDAY);
echo "Previous monday: $prev_monday\n";
该示例显示了下一个和上一个星期一。
$ php next_previous.php
2019-05-07 11:34:32
Next monday: 2019-05-13 00:00:00
Previous monday: 2019-05-06 00:00:00
This is a sample output.
Carbon 日期时间
Carbon 日期时间包括年,月,日或小时。
parts.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Carbon\Carbon;
$now = Carbon::now();
echo $now->year . "\n";
echo $now->month . "\n";
echo $now->day . "\n";
echo $now->hour . "\n";
echo $now->second . "\n";
echo $now->dayOfWeek . "\n";
echo $now->dayOfYear . "\n";
echo $now->weekOfMonth . "\n";
echo $now->daysInMonth . "\n";
该示例显示 Carbon 日期时间实例的各个部分。
$ php parts.php
2019
5
7
10
31
2
126
1
31
This is a sample output.
Carbon 流式 API
Carbon 还提供了方便的流式 API 来处理日期时间。
fluent_api.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Carbon\Carbon;
$dt = Carbon::create();
$dt->year(2019)->month(5)->day(6)->hour(16)->minute(12)->second(53);
echo $dt . "\n";
$dt2 = Carbon::create();
$dt2->setDate(2019, 5, 6)->setTime(16, 12, 53);
echo $dt2 . "\n";
$dt3 = Carbon::create();
$dt3->setDate(2019, 5, 6)->setTime(16, 12, 53);
echo $dt3 . "\n";
该示例使用流畅的 API 创建了三个 Carbon 实例。
$ php fluent_api.php
2019-05-06 16:12:53
2019-05-06 16:12:53
2019-05-06 16:12:53
这是输出。
Carbon 修改方法
Carbon 修改方法修改实例。 我们可以使用copy()
方法来处理副本。
copy_method.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Carbon\Carbon;
echo "Tomorrow: " . Carbon::tomorrow() . "\n";
echo "*************************\n";
$dt = new Carbon('tomorrow');
echo $dt->subDay() . "\n";
echo $dt . "\n";
echo "*************************\n";
$dt2 = new Carbon('tomorrow');
echo $dt2->copy()->subDay() . "\n";
echo $dt2 . "\n";
该示例介绍了copy()
方法。
$ php copy_method.php
Tomorrow: 2019-05-08 00:00:00
*************************
2019-05-07 00:00:00
2019-05-07 00:00:00
*************************
2019-05-07 00:00:00
2019-05-08 00:00:00
在第二种情况下,原始实例是完整的。
碳加减法
碳提供了两种不同的方法来轻松增加和减少时间。
add_sub.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Carbon\Carbon;
$now = Carbon::now();
echo "$now\n";
$d1 = $now->copy()->addDays(3);
echo "$d1\n";
$d2 = $now->copy()->addHours(12);
echo "$d2\n";
$d3 = $now->copy()->subDays(3);
echo "$d3\n";
$d4 = $now->copy()->subHours(12);
echo "$d4\n";
该示例介绍了addDays()
,addHours()
,subDays()
和subHours()
方法。
$ php add_sub.php
2019-05-07 12:27:22
2019-05-10 12:27:22
2019-05-08 00:27:22
2019-05-04 12:27:22
2019-05-07 00:27:22
This is a sample output.
下面的示例显示其他加法和减法。
add_sub.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Carbon\Carbon;
$now = Carbon::now();
$d1 = $now->copy()->addCenturies(2);
echo $d1->toDateString() . "\n";
$d2 = $now->copy()->subCenturies(2);
echo $d2->toDateString() . "\n";
$d3 = $now->copy()->addYears(2);
echo $d3->toDateString() . "\n";
$d4 = $now->copy()->subYears(2);
echo $d4->toDateString() . "\n";
$d5 = $now->copy()->addMonths(2);
echo $d5->toDateString() . "\n";
$d6 = $now->copy()->subMonths(2);
echo $d6->toDateString() . "\n";
我们显示addCenturies()
,subCenturies()
,addYears()
,subYears()
,addMonths()
和subMonths()
。
$ php add_sub2.php
2219-05-07
1819-05-07
2021-05-07
2017-05-07
2019-07-07
2019-03-07
This is a sample output.
Carbon 格式化日期时间
Carbon 提供了几种格式化日期时间的方法。
formatting.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Carbon\Carbon;
$dt = Carbon::now();
echo $dt . "\n";
echo $dt->toDateTimeString(). "\n";
echo "******************************\n";
echo $dt->toDateString(). "\n";
echo $dt->toFormattedDateString(). "\n";
echo $dt->toTimeString(). "\n";
echo $dt->toDayDateTimeString(). "\n";
echo "******************************\n";
echo $dt->format('Y-m-d h:i:s A'). "\n";
该示例提供了基本的格式化方法。 我们还可以使用format()
生成自定义格式。
$ php formatting.php
2019-05-07 10:36:09
2019-05-07 10:36:09
******************************
2019-05-07
May 7, 2019
10:36:09
Tue, May 7, 2019 10:36 AM
******************************
2019-05-07 10:36:09 AM
This is a sample output.
下面的示例显示其他常见的 Carbon 日期时间格式化方法。
common_formats.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Carbon\Carbon;
$dt = Carbon::createFromFormat('Y-m-d H:i:s.u', '2019-05-06 16:45:00.613484');
echo $dt->toAtomString() . "\n";
echo $dt->toCookieString() . "\n";
echo $dt->toIso8601String() . "\n";
echo $dt->toIso8601ZuluString() . "\n";
echo $dt->toRfc822String() . "\n";
echo $dt->toRfc850String() . "\n";
echo $dt->toRfc1036String() . "\n";
echo $dt->toRfc1123String() . "\n";
echo $dt->toRfc3339String() . "\n";
echo $dt->toRfc7231String() . "\n";
echo $dt->toRssString() . "\n";
echo $dt->toW3cString() . "\n";
该示例介绍了其他十二种方法。
$ php common_formats.php
2019-05-06T16:45:00+02:00
Monday, 06-May-2019 16:45:00 CEST
2019-05-06T16:45:00+02:00
2019-05-06T14:45:00Z
Mon, 06 May 19 16:45:00 +0200
Monday, 06-May-19 16:45:00 CEST
Mon, 06 May 19 16:45:00 +0200
Mon, 06 May 2019 16:45:00 +0200
2019-05-06T16:45:00+02:00
Mon, 06 May 2019 14:45:00 GMT
Mon, 06 May 2019 16:45:00 +0200
2019-05-06T16:45:00+02:00
This is the output.
Carbon 比较日期时间
Carbon 具有比较日期时间的方法,例如eq()
和gt()
。
comparing.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Carbon\Carbon;
$first = Carbon::create(2019, 5, 5, 22, 20, 1);
$second = Carbon::create(2019, 5, 5, 20, 20, 1);
echo $first . "\n";
echo $second . "\n";
var_dump($first->eq($second));
var_dump($first->ne($second));
var_dump($first->gt($second));
var_dump($first->gte($second));
var_dump($first->lt($second));
var_dump($first->lte($second));
该示例比较两个日期时间值。
$ php comparison.php
2019-05-05 22:20:01
2019-05-05 20:20:01
bool(false)
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)
This is the output.
Carbon UTC
协调世界时(UTC)是世界各地用来调节时钟和时间的主要时间标准。
utc.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Carbon\Carbon;
$now = Carbon::now();
echo "$now\n";
isUtc($now);
echo "Offset hours: {$now->offsetHours}\n";
echo "******************************\n";
$now->tz('UTC');
echo "$now\n";
isUtc($now);
function isUtc($now): void
{
if ($now->utc)
{
echo "Datetime is in UTC\n";
} else {
echo "Datetime is not in UTC\n";
}
}
该示例计算 UTC 时间(以小时为单位的偏移量),并确定日期时间是否为 UTC 时间。
$ php utc.php
2019-05-07 11:14:18
Datetime is not in UTC
Offset hours: 2
******************************
2019-05-07 09:14:18
Datetime is in UTC
This is a sample output.
Carbon 人性化日期时间差异
应用通常以所谓的人性化格式显示日期时间差异。 例如在一年或三分钟前。
humanized.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Carbon\Carbon;
echo Carbon::now()->addYear()->diffForHumans() . "\n";
Carbon::setLocale('de');
echo Carbon::now()->addYear()->diffForHumans() . "\n";
Carbon::setLocale('sk');
echo Carbon::now()->addYear()->diffForHumans() . "\n";
该示例显示了三种语言环境中的日期时间差异。
$ php humanize.php
1 year from now
in 1 Jahr
za rok
This is the output.
Carbon 修饰符
修饰符方法对当前实例执行有用的修改。 他们可以检索周,月或年的开始/结束。
modifiers.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Carbon\Carbon;
echo "Start/End of day\n";
$dt = Carbon::create(2019, 5, 6, 12, 0, 0);
echo $dt->copy()->startOfDay() . "\n";
echo $dt->copy()->endOfDay() . "\n";
echo "\nStart/End of month\n";
echo $dt->copy()->startOfMonth() . "\n";
echo $dt->copy()->endOfMonth() . "\n";
echo "\nStart/End of year\n";
echo $dt->copy()->startOfYear() . "\n";
echo $dt->copy()->endOfYear() . "\n";
echo "\nStart/End of decade\n";
echo $dt->copy()->startOfDecade() . "\n";
echo $dt->copy()->endOfDecade() . "\n";
echo "\nStart/End of century\n";
echo $dt->copy()->startOfCentury() . "\n";
echo $dt->copy()->endOfCentury() . "\n";
该示例提出了几个修饰符。
$ php modifiers.php
Start/End of day
2019-05-06 00:00:00
2019-05-06 23:59:59
Start/End of month
2019-05-01 00:00:00
2019-05-31 23:59:59
Start/End of year
2019-01-01 00:00:00
2019-12-31 23:59:59
Start/End of decade
2010-01-01 00:00:00
2019-12-31 23:59:59
Start/End of century
2001-01-01 00:00:00
2100-12-31 23:59:59
This is a sample output.
在本教程中,我们使用 PHP Carbon 来处理日期和时间。
您可能也对以下相关教程感兴趣: PHP PDO 教程, Twig 教程和 PHP 教程,或列出所有 PHP 教程 ]。
PHP Monolog 教程
PHP Monolog 教程展示了如何使用 Monolog 在 PHP 中进行日志记录。
记录
日志记录是将信息写入日志文件的过程。 日志文件包含有关在操作系统,软件或通信中发生的各种事件的信息。
记录目的
完成记录是出于以下目的:
- 信息收集
- 故障排除
- 产生统计数据
- 审计
- 性能分析
记录不仅限于识别软件开发中的错误。 它还可用于检测安全事件,监视策略违规,在出现问题时提供信息,查找应用瓶颈或生成使用情况数据。
要记录的事件
应记录的事件包括输入验证失败,认证和授权失败,应用错误,配置更改以及应用启动和关闭。
不记录的事件
不应记录的事件包括应用源代码,会话标识值,访问令牌,敏感的个人数据,密码,数据库连接字符串,加密密钥,银行帐户和持卡人数据。
记录最佳做法
以下是一些日志记录最佳做法:
- 日志记录应该有意义。
- 日志应包含上下文。
- 日志应保持平衡; 它不应包含过多或过多的信息。
- 记录消息应该是人类可以理解的,并且可以被机器解析。
- 日志记录应在不同级别进行结构化和完成。
- 日志应适应开发和生产。
- 记录更复杂的应用应产生几个日志文件。
PHP Monolog
Monolog 是流行的 PHP 日志记录库。 它允许将日志发送到文件,套接字,收件箱,数据库和各种 Web 服务。 它实现了 PSR-3 接口。
$ composer req monolog/monolog
我们用 Composer 安装 Monolog。
Monolog 结构
Monolog 记录器实例具有通道(名称)和处理器的栈。 处理器负责将消息保存到文件,数据库或将其发送到邮件。
记录的消息在处理器栈中传播。 最后一个处理器首先执行。 消息的进一步传播由bubble
变量控制,该变量默认设置为true
。
消息记录是一条将要写入日志的信息。 消息记录包含以下部分:
键 | 类型 | 描述 |
---|---|---|
info |
string |
日志消息。 |
level |
integer |
日志消息的严重性。 |
level_name |
string |
日志级别的字符串表示形式。 |
context |
array |
随消息的构造传递任意数据。 |
channel |
string |
此消息被登录到的频道。 |
datetime |
Monolog /DateTimeImmutable |
消息记录的日期和时间。 |
extra |
array |
处理器可在其中放置其他数据的占位符数组。 |
处理器是可用于处理日志消息的任何 PHP 可调用对象。 它可以向记录中添加一些额外的数据。
context
是数组数据,其中包含的附加信息不太适合主字符串。 上下文是日志记录方法的参数(例如info()
或warn()
)。
格式化程序用于格式化消息记录。
Monolog 日志级别
日志记录级别用于按紧急程度对日志消息进行分类。 Monolog 具有以下日志级别:
DEBUG
- 详细的调试信息INFO
- 有趣的事件NOTICE
- 正常但重要的事件WARNING
- 并非错误的特殊情况ERROR
- 不需要立即采取措施的运行时错误CRITICAL
- 关键条件ALERT
- 必须立即采取措施的事件EMERGENCY
- 紧急事件
日志级别较低的处理器将不处理不太严重的日志。 通过将日志级别设置为ERROR
,我们将获得ERROR
级别及更高级别的消息。
每个处理器都指定了一个日志级别; 默认值为DEBUG
。 为了产生具有特定日志级别的消息,我们有包括info()
,warn()
,error()
和critical()
的方法。 由于 Monolog 早于 PSR-3,因此它包含重复的方法(例如addInfo()
或addWarning()
)。
Monolog 简单示例
在第一个示例中,我们使用Streamhandler
将消息记录到文件中。
simple.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
$logger = new Logger('main');
$logger->pushHandler(new StreamHandler(__DIR__ . '/logs/app.log', Logger::DEBUG));
$logger->info('First message');
该示例将信息消息写入logs/app.log
文件。
$logger = new Logger('main');
创建了一个名为main
的新记录器。
$logger->pushHandler(new StreamHandler(__DIR__ . '/logs/app.log', Logger::DEBUG));
我们使用pushHandler()
将StreamHandler
添加到记录器。 处理器以DEBUG
严重性将消息写入指定的文件。
$logger->info('First message');
我们使用info()
方法记录一条信息消息。
$ cat logs\app.log
[2019-05-15 15:49:48] main.INFO: First message [] []
这是书面信息。 日志消息以当前日期时间开头。 后面是日志通道名称和级别。 然后是消息记录。 两对方括号是我们可以指定上下文和额外数据的位置。 我们可以使用 Monolog 格式化程序自定义此输出。
Monolog 控制台日志记录
我们可以将日志消息写入终端。
console_log.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$logger = new Logger('stderr');
$logger->pushHandler(new StreamHandler('php://stderr', Logger::WARNING));
$logger->warn('A warning message');
我们通过向StreamHandler
指定php://stderr
来写入控制台。
Monolog 上下文数组
Monolog 上下文数组允许在用户级级别将信息添加到消息记录中。
context_array.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
$logger = new Logger('main');
$logger->pushHandler(new StreamHandler('php://stderr'));
$logger->info('Information message', ['user' => get_current_user()]);
info()
方法的第二个参数是上下文数组。 我们将当前用户添加到消息中。
$ php context_array.php
[2019-05-15 15:37:56] main.INFO: Information message {"user":"Jano"} []
这是输出。
Monolog 记录器处理器栈
我们可以将多个处理器添加到栈中。 最后添加的处理器将首先执行。
handler_stack.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
$main = new Logger('main');
$main->pushHandler(new StreamHandler(__DIR__ . '/logs/app.log'));
$main->pushHandler(new StreamHandler('php://stdout', $level = Logger::DEBUG,
$bubble = true));
$main->info('Information message');
在示例中,我们有两个记录器处理器:一个文件和一个控制台处理器。 如果将$bubble
更改为false
,则消息将不会写入logs/app.log
文件。
Monolog 定制处理器
可以向pushProcessor()
添加自定义处理器。
custom_processor.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
$logger = new Logger('main');
$logger->pushHandler(new StreamHandler('php://stderr'));
$logger->pushProcessor(function ($record) {
$record['extra']['user'] = get_current_user();
return $record;
});
$logger->info('Information message');
在示例中,我们向处理器中的消息记录添加了一些额外的信息。 根据文档,上下文和额外数据之间的区别在于上下文是在用户区域中提供的,而额外数据仅是内部的,可以由处理器填充。
$ php custom_processor.php
[2019-05-15 17:24:48] main.INFO: Information message [] {"user":"Jano"}
额外的信息将添加到输出的末尾。
Monolog JsonFormatter
JsonFormatter
以 JSON 格式写入记录。
json_formatter.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Monolog\Formatter\JsonFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
$logger = new Logger('main');
$formatter = new JsonFormatter();
$stream = new StreamHandler(__DIR__ . '/logs/app-json.log');
$stream->setFormatter($formatter);
$logger->pushHandler($stream);
$logger->info('Information message', ['user' => get_current_user()]);
该示例使用JsonFormatter
将信息消息以 JSON 格式写入文件。
$ cat logs\app-json.log
{"message":"Information message","context":{"user":"Jano"},"level":200,"level_name":"INFO",
"channel":"main","datetime":{"date":"2019-05-15 17:37:40.433222","timezone_type":3,
"timezone":"Europe/Berlin"},"extra":[]}
这是记录的消息。
Monolog LineFormatter
LineFormatter
将日志记录格式化为单行字符串。
line_format.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\LineFormatter;
use Monolog\Processor\ProcessIdProcessor;
$output = "[%datetime%] %channel%.%level_name%: %message% %context.user%\n";
$formatter = new LineFormatter($output);
$streamHandler = new StreamHandler('php://stdout');
$streamHandler->setFormatter($formatter);
$logger = new Logger('main');
$logger->pushHandler($streamHandler);
$logger->info('Information message from', ['user' => get_current_user()]);
在示例中,我们使用LineFormatter
自定义消息记录。
$output = "[%datetime%] %channel%.%level_name%: %message% %context.user%\n";
$formatter = new LineFormatter($output);
我们创建一个自定义记录消息。 它包含日期时间,频道名称,级别名称,消息和上下文数据。
$streamHandler->setFormatter($formatter);
我们使用setFormatter()
将格式化程序添加到处理器中。
$ php line_format.php
[2019-05-15 17:43:36] main.INFO: Information message from Jano
这是一个示例输出。
Monolog 邮件日志消息
可以使用SwiftMailerHandler
发送电子邮件
$ composer req swiftmailer/swiftmailer
对于此示例,我们需要安装swiftmailer/swiftmailer
包。
注意:Gmail 不是理想的测试应用。 我们应该使用诸如 Mailtrap 或 Mailgun 之类的在线服务,或者使用由网络托管公司提供的 SMTP 服务器。
在我们的示例中,我们使用 Mailtrap 服务。
mail_log.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Monolog\Handler\SwiftMailerHandler;
$transporter = new Swift_SmtpTransport('smtp.mailtrap.io', 2525, 'tls');
$transporter->setUsername('3178491df14b6d');
$transporter->setPassword('7c1d6fa59a5v08');
$mailer = new Swift_Mailer($transporter);
$message = new Swift_Message('Critical message');
$message->setFrom(['[email protected]' => 'App root']);
$message->setTo(['[email protected]' => 'Support']);
$logger = new Logger('main');
$logger->pushHandler(new SwiftMailerHandler($mailer, $message, Logger::CRITICAL));
$logger->critical('Could not connect to the database');
在示例中,我们使用SwiftMailerHandler
将消息记录发送到邮件收件箱。
$transporter = new Swift_SmtpTransport('smtp.mailtrap.io', 2525, 'tls');
$transporter->setUsername('3178491df14b6d');
$transporter->setPassword('7c1d6fa59a5v08');
使用 Mailtrap 连接详细信息,我们构建了传输器。
$mailer = new Swift_Mailer($transporter);
创建了Swinf_Mailer
。
$message = new Swift_Message('Critical message');
$message->setFrom(['[email protected]' => 'App root']);
$message->setTo(['[email protected]' => 'Support']);
创建了Swift_Message
。 它包含从到字段。
$logger = new Logger('main');
$logger->pushHandler(new SwiftMailerHandler($mailer, $message, Logger::CRITICAL));
$logger->critical('Could not connect to the database');
我们将SwiftMailerHandler
添加到记录器,并使用critical()
创建关键消息。
您可能也对以下相关教程感兴趣: PHP Rakit 验证教程, PHP PDO 教程, PHP 教程或列出所有 PHP 教程。
在本教程中,我们使用 Monolog 在 PHP 中进行日志记录。
PHP 配置教程
PHP 配置教程显示了如何在 PHP 中创建配置文件。 它使用hassankhan/config
包。
hassankhan/config
是一种轻量级的配置文件加载器,支持 PHP,INI,XML,JSON 和 YAML 文件。 如果使用 YAML 文件,则需要安装symfony/yaml
包。
安装 PHP 配置
首先,我们安装必要的包。
$ composer req hassankhan/config symfony/yaml
我们使用 composer 安装了两个包。
composer.json
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"require": {
"hassankhan/config": "^2.0",
"symfony/yaml": "^4.2"
}
}
这是composer.json
文件。 我们还启用了自动加载功能。
PHP 配置 JSON 示例
在第一个示例中,我们从 JSON 文件读取配置数据。
config/db.json
{
"app": {
"port": 3000
},
"db": {
"host": "localhost",
"port": 27017,
"name": "ydb"
}
}
我们在config
目录中有db.json
。
read_json_cfg.php
<?php
use Noodlehaus\Config;
require('vendor/autoload.php');
// $conf = Config::load('config/db.json');
$conf = new Config('config/db.json');
echo $conf->get('app.port') . "\n";
echo $conf->get('db.host') . "\n";
echo $conf->get('db.port') . "\n";
echo $conf->get('db.name') . "\n";
我们使用Config::load()
或Config()
加载配置文件。 使用get()
方法检索这些值。 点字符用于遍历属性的层次结构。
$ php read_json_cfg.php
3000
localhost
27017
ydb
这是输出。
PHP YAML 示例
在第二个示例中,我们从 YAML 文件读取配置数据。
config/db.yaml
app:
port: 3000
db:
host: localhost
port: 27017
name: ydb
这是db.yaml
文件。
read_yaml_cfg.php
<?php
use Noodlehaus\Config;
use Noodlehaus\Parser\Yaml;
require('vendor/autoload.php');
$conf = new Config('config/db.yaml', new Yaml);
echo $conf->get('app.port') . "\n";
echo $conf->get('db.host') . "\n";
echo $conf->get('db.port') . "\n";
echo $conf->get('db.name') . "\n";
该示例从db.yaml
文件读取配置文件。
$conf = new Config('config/db.yaml', new Yaml);
在第二个参数中,我们提供配置解析器。
$ php read_yaml_cfg.php
3000
localhost
27017
ydb
This is the output.
合并配置文件
merge()
方法对配置文件进行分组。
config/db.yaml
app:
port: 3000
db:
host: localhost
port: 27017
name: ydb
这是第一个配置文件。
config/app.yaml
version: 2.0-dev
这是第二个配置文件。
merging.php
<?php
use Noodlehaus\Config;
use Noodlehaus\Parser\Yaml;
require('vendor/autoload.php');
$conf = Config::load('config/db.yaml', new Yaml);
$conf2 = Config::load('config/app.yaml', new Yaml);
$conf->merge($conf2);
echo $conf->get('db.port') . "\n";
echo $conf->get('db.name') . "\n";
echo $conf->get('version') . "\n";
在示例中,我们合并了两个配置文件。 我们可以使用一个对象访问两个文件的属性。
使用AbstractConfig
进行代码配置
我们可以使用AbstractConfig
在代码中指定配置详细信息。
src/Config/AbstractConfig.php
<?php
namespace App\Config;
use Noodlehaus\AbstractConfig;
class AppConfig extends AbstractConfig
{
protected function getDefaults()
{
return [
'host' => 'localhost',
'port' => 80,
'servers' => [
'host1',
'host2',
'host3'
]
];
}
}
该配置在AbstractConfig
的getDefaults()
文件中指定。
code_config.php
<?php
require('vendor/autoload.php');
use Noodlehaus\Config;
use App\Config\AppConfig;
$conf = new AppConfig([]);
echo $conf->get('host') . "\n";
echo $conf->get('port') . "\n";
echo $conf->get('servers')[0] . "\n";
该示例从代码读取配置。
在本教程中,我们展示了如何使用hassankhan/config
包读取 PHP 中的配置文件。
列出所有 PHP 教程。
{% raw %}
PHP Faker 教程
PHP Faker 教程展示了如何使用 Faker 包在 PHP 中生成伪造数据。 我们使用fzaninotto/Faker
包。
PHP Faker
Faker 是一个生成假数据的 PHP 库。 Faka 数据通常用于测试或用一些伪数据填充数据库。 Faker 受到 Perl 的 Data::Faker 和 Ruby 的 Faker 的极大启发。
PHP Faker 设置
该包随 composer 一起安装。
$ composer req fzaninotto/faker
我们安装fzaninotto/faker
包。
$ composer req symfony/var-dumper
另外,我们安装了 Symfony Dumper,它在转储变量时提供更好的控制台输出。
Faker 工厂
使用Faker\Factory::create()
,我们创建并初始化一个伪造者生成器。 在生成器上,我们访问生成器属性(称为格式化程序)以生成伪数据。 在内部,Faker 将数据生成委托给供应器。
默认供应器使用英语语言环境。 Faker 支持其他语言环境; 他们的完成水平不同。
简单的 Faker 示例
以下示例是 Faker 的简单演示。
simple.php
<?php
require('vendor/autoload.php');
$faker = Faker\Factory::create();
echo $faker->name . "\n";
echo $faker->address . "\n";
该示例输出伪造的名称和地址。
$ php simple.php
Antonia Hahn
355 Mills Light Apt. 722
Krajcikburgh, RI 36330
这是一个示例输出。
伪造名称
在第二个示例中,我们伪造与用户名有关的数据。
names.php
<?php
require('vendor/autoload.php');
$faker = Faker\Factory::create();
echo $faker->name() . "\n";
echo $faker->name('male') . "\n";
echo $faker->name('female') . "\n";
echo $faker->firstName() . "\n";
echo $faker->firstName($gender='male') . "\n";
echo $faker->firstName($gender='female') . "\n";
echo $faker->firstNameMale('female') . "\n";
echo $faker->firstNameFemale('female') . "\n";
echo $faker->lastName() . "\n";
该示例创建假的全名,男性的姓氏和姓氏。
$ php names.php
Darion Walker
Prof. Chet Kessler
Prof. Jaida Greenholt PhD
Cristopher
Reid
Gilda
Wiley
Juanita
Jones
This is a sample output.
伪造语言环境数据
Faker 在某种程度上支持本地化数据。 语言环境已传递给工厂create()
方法。 请注意,语言环境已完成各种级别。
localized.php
<?php
require('vendor/autoload.php');
$faker = Faker\Factory::create('sk_SK');
for ($i = 0; $i < 3; $i++) {
$name = $faker->name;
$city = $faker->cityName;
$phone = $faker->phoneNumber;
echo "$name, $city, $phone\n";
}
该示例使用斯洛伐克语生成伪造数据。
$ php localized.php
RNDr. Kvetoslava Zelenayová DSc., Malé Dvorníky, 00421 742 587 664
Agáta Molnárová, Čabalovce, +421 857 627 309
PhDr. Igor Truben, Mokrá Lúka, 00421577302978
这是一个示例输出。 请注意,斯洛伐克语带有重音。
伪造标题
以下示例为标题创建伪造数据。 Faker 产生学术和个人头衔。
titles.php
<?php
require('vendor/autoload.php');
$faker = Faker\Factory::create();
echo $faker->title() . "\n";
echo $faker->title('male'). "\n";
echo $faker->title('female'). "\n";
echo $faker->titleMale . "\n";
echo $faker->titleFemale . "\n";
echo $faker->suffix . "\n";
该程序会为男性和女性生成假标题。
$ php titles.php
Ms.
Dr.
Miss
Prof.
Mrs.
DDS
This is a sample output.
伪造颜色
Faker 可以创建颜色名称或不同的颜色格式,例如十六进制和 RGB。
colours.php
<?php
require('vendor/autoload.php');
$faker = Faker\Factory::create();
echo $faker->hexcolor . "\n";
echo $faker->rgbcolor . "\n";
dump($faker->rgbColorAsArray);
echo $faker->rgbCssColor . "\n";
echo $faker->safeColorName . "\n";
echo $faker->colorName . "\n";
该示例显示了如何使用 Faker 创建颜色。
$ php colours.php
#662d69
180,149,135
array:3 [
0 => 190
1 => 115
2 => 170
]
rgb(119,164,223)
aqua
LightGreen
DarkGray
This is a sample output.
伪造号码
Faker 允许生成随机数字,整数或浮点值。
numbers.php
<?php
require('vendor/autoload.php');
$faker = Faker\Factory::create();
echo $faker->randomDigit . "\n";
echo $faker->randomDigitNotNull . "\n";
echo $faker->randomNumber() . "\n";
echo $faker->randomNumber($nbDigits = 3, $strict = true) . "\n";
echo $faker->randomFloat() . "\n";
echo $faker->randomFloat($nbMaxDecimals = 5, $min = 0, $max = 20) . "\n";
echo $faker->numberBetween($min = 1500, $max = 6000) . "\n";
dump($faker->shuffle([1, 2, 3, 4, 5, 6]));
该示例生成随机数字,整数和浮点数。 它还会随机地对数组值进行混洗。
$ php numbers.php
6
6
3654715
614
4164
12.29093
2347
array:6 [
0 => 3
1 => 6
2 => 2
3 => 5
4 => 1
5 => 4
]
This is a sample output.
伪造唯一值
使用unique()
修饰符,我们可以产生唯一的假值。
unique_values.php
<?php
require('vendor/autoload.php');
$faker = Faker\Factory::create();
$vals = [];
for ($i = 0; $i < 6; $i++) {
$vals[] = $faker->unique()->randomDigit;
}
dump($vals);
该示例生成一个包含六个唯一数字的数组。
$ php unique_values.php
array:6 [
0 => 0
1 => 6
2 => 9
3 => 1
4 => 5
5 => 3
]
This is a sample output.
伪造可选值
使用optional()
修饰符,我们可以生成可选的假值。 可选值可以为null
。
optional_values.php
<?php
require('vendor/autoload.php');
$faker = Faker\Factory::create();
$vals = [];
for ($i = 0; $i < 6; $i++) {
$vals[] = $faker->unique()->randomDigit;
}
dump($vals);
该示例生成一个包含六个可选数字的数组。
$ php optional_values.php
array:6 [
0 => 7
1 => 4
2 => null
3 => null
4 => null
5 => 8
]
This is a sample output.
伪造互联网相关数据
Faker 有多个用于伪造与互联网相关的数据的访问器。
internet.php
<?php
require('vendor/autoload.php');
$faker = Faker\Factory::create();
echo $faker->email . "\n";
echo $faker->safeEmail . "\n";
echo $faker->freeEmail . "\n";
echo $faker->companyEmail . "\n";
echo $faker->freeEmailDomain . "\n";
echo $faker->safeEmailDomain . "\n";
echo $faker->userName . "\n";
echo $faker->password . "\n";
echo $faker->domainName . "\n";
echo $faker->domainWord . "\n";
echo $faker->tld . "\n";
echo $faker->url . "\n";
echo $faker->slug . "\n";
echo $faker->ipv4 . "\n";
echo $faker->localIpv4 . "\n";
echo $faker->ipv6 . "\n";
echo $faker->macAddress . "\n";
该示例显示了各种与互联网相关的数据,包括电子邮件,域名,信息,IP 地址和 URL。
$ php internet.php
[email protected]
[email protected]
[email protected]
[email protected]
gmail.com
example.net
bartoletti.ena
}#)W+OVU<Lgaa.Atp5^
metz.com
blanda
org
http://www.kling.com/
optio-magnam-provident-pariatur-dolores-consequatur-beatae
127.131.186.145
10.135.68.26
ccf1:64a7:d145:98eb:742d:dc60:cf9e:5d4a
C8:31:FD:24:15:06
This is a sample output.
用 Faker 生成 XML 数据
在以下示例中,我们使用 Faker 和 Twig 模板生成 XML 数据。 XML 文件将包含用户。
$ mkdir fakexml
$ cd fakexml
$ mkdir templates
$ composer req fzaninotto/faker
$ composer req twig/twig
我们创建一个新的项目目录,并安装 Faker 和 Twig 模板引擎。
User.php
<?php
class User
{
public $firstName;
public $lastName;
public $occupation;
function __construct(string $first, string $last, string $occupation)
{
$this->firstName = $first;
$this->lastName = $last;
$this->occupation = $occupation;
}
}
这是User.php
,具有以下属性:$firstName
,$lastName
和$occupation
;
fake_xml.php
<?php
require __DIR__ . '/vendor/autoload.php';
require __DIR__ . '/User.php';
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Faker\Factory;
$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);
$faker = Factory::create();
$users = [];
for ($i = 0; $i < 20; $i++)
{
$firstName = $faker->firstName;
$lastName = $faker->lastName;
$occupation = $faker->jobTitle;
$user = new User($firstName, $lastName, $occupation);
array_push($users, $user);
}
$content = $twig->render('users.xml.twig', ['users' => $users]);
file_put_contents('users.xml', $content);
该程序将生成一个包含二十个用户的数组。 数组将传递到 Twig 模板进行处理。 模板位于templates
目录中。 生成的内容被写入users.xml
文件。
templates/users.xml.twig
<?xml version="1.0" encoding="UTF-8"?>
<users>
{% for user in users %}
<user id="{{ loop.index }}">
<firstname>{{ user.firstName }}</firstname>
<lastname>{{ user.lastName }}</lastname>
<occupation>{{ user.occupation }}</occupation>
</user>
{% endfor %}
</users>
在模板中,我们使用for
指令来处理用户数组。
在本教程中,我们使用 PHP Faker 在 PHP 中生成伪数据。
您可能也对以下相关教程感兴趣: PHP PDO 教程, Twig 教程和 PHP 教程。
{% endraw %}
{% raw %}
Twig 教程
Twig 教程展示了如何在 PHP 应用中使用 Twig 模板引擎来生成文档。
枝条
Twig 是一个 PHP 模板引擎。 它是由 Symfony 开发者创建的。 Twig 文件的扩展名为.html.twig
; 它们是静态数据(例如 HTML 和 Twig 构造)的混合。
Twig 使用双大括号分隔符{{ }}
进行输出,并使用大括号百分比定界符{% %}
进行逻辑运算。 {# #}
用于注释。
<ul>
{% for word in words %}
<li>{{ word }}</li>
{% endfor %}
</ul>
此代码是示例 Twig 语法。 在此代码中,我们使用for
标签创建一个循环。
Twig 语法由标签,过滤器,函数,运算符和测试组成。
安装 Twig
首先,我们设置了 Twig。
$ composer require twig/twig
我们用 Composer 安装 Twig。
$ mkdir templates
我们将模板文件放入template
目录。
require __DIR__ . '/vendor/autoload.php';
我们需要将autoload.php
文件添加到脚本中。
模板引擎
模板引擎或模板处理器是一个旨在将模板与数据模型结合以生成文档的库。 模板引擎通常用于在源代码预处理或生成动态 HTML 页面中生成大量电子邮件。
我们创建一个模板引擎,在其中定义静态零件和动态零件。 动态部分随后将替换为数据。 渲染函数随后将模板与数据结合在一起。
Twig 第一个例子
以下是 Twig 模板系统的简单演示。
first.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);
echo $twig->render('first.html.twig', ['name' => 'John Doe',
'occupation' => 'gardener']);
我们使用FilesystemLoader
从指定目录加载模板。
echo $twig->render('first.html.twig', ['name' => 'John Doe',
'occupation' => 'gardener']);
输出通过render()
生成。 它带有两个参数:模板文件和数据。
templates/first.html.twig
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>
{{ name }} is a {{ occupation }}
</p>
</body>
</html>
这是模板文件。 变量以{{}}
语法输出。
$ php first.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>
John Doe is a gardener
</p>
</body>
</html>
这是输出。
Twig 过滤器
过滤器使我们能够以各种方式修改数据。
filters.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);
$words = ['sky', 'mountain', 'falcon', 'forest', 'rock', 'blue'];
$sentence = 'today is a windy day';
echo $twig->render('filters.html.twig',
['words' => $words, 'sentence' => $sentence]);
在示例中,我们有一个数组和一个字符串作为模板数据。
templates/filters.html.twig
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Filters</title>
</head>
<body>
<p>
The array has {{ words | length }} elements
</p>
<p>
Joined array elements: {{ words | join(',') }}
</p>
<p>
{{ sentence | title }}
</p>
</body>
</html>
过滤器应用|
字符。 该示例使用length
对单词进行计数,使用join
连接数组元素,并使用title
修改字符。
Twig 自定义过滤器
我们可以使用Twig_Filter
创建自定义过滤器。
customfilter.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);
$twig->addFilter(new Twig_Filter('accFirst', 'accFirst'));
$sentence = 'šumivé víno';
echo $twig->render('customfilter.html.twig',
['sentence' => $sentence]);
function accFirst($value, $encoding = 'UTF8')
{
$strlen = mb_strlen($value, $encoding);
$firstChar = mb_substr($value, 0, 1, $encoding);
$rest = mb_substr($value, 1, $strlen - 1, $encoding);
return mb_strtoupper($firstChar, $encoding) . $rest;
}
我们添加了一个名为accFirst
的新过滤器。 它仅修改第一个字母,也可以处理重音。
templates/customfilter.html.twig
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Custom filter</title>
</head>
<body>
<p>
{{ sentence | accFirst }}
</p>
</body>
</html>
这是模板文件,使用自定义accFirst
过滤器。
Twig 循环
要创建循环,我们使用for
标签。
looping.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);
$words = ['sky', 'mountain', 'falcon', 'forest',
'rock', 'blue', 'solid', 'book', 'tree'];
echo $twig->render('words.html.twig', ['words' => $words]);
我们将循环一个单词数组。
templates/words.html.twig
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Words</title>
</head>
<body>
<ul>
{% for word in words %}
<li>{{ word }}</li>
{% endfor %}
</ul>
<ul>
{% for word in words|slice(2, 4) %}
<li>{{ word }}</li>
{% endfor %}
</ul>
</body>
</html>
在模板文件中,我们遍历words
数组并生成 HTML 列表。 使用slice()
过滤器,我们可以遍历数组的一部分。
Twig 循环和if else
我们可以将for
标签与if
标签和else
标签结合在一起。
looping2.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);
$users = [
['name' => 'John Doe', 'active' => false],
['name' => 'Lucy Smith', 'active' => false],
['name' => 'Peter Holcombe', 'active' => false],
['name' => 'Barry Collins', 'active' => false]
];
echo $twig->render('activeusers.html.twig', ['users' => $users]);
我们向模板文件发送用户数组。
templates/activeusers.html.twig
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>Active users</p>
<ul>
{% for user in users if user.active %}
<li>{{ user.name }}</li>
{% else %}
<li>No users found</li>
{% endfor %}
</ul>
</body>
</html>
我们输出的用户名称user.active
属性为true
。 当没有活动用户时,将显示else
标记的输出。
Twig set
标签
set
标签允许将值设置为模板内的变量。
$words = ['sky', 'mountain', 'falcon', 'forest',
'rock', 'blue', 'solid', 'book', 'tree'];
echo $twig->render('test.html.twig', ['words' => $words]);
我们有一个单词表。
{% set sorted = words | sort %}
<ul>
{% for word in sorted %}
<li>{{ word }}</li>
{% endfor %}
</ul>
我们使用sort
过滤器对数组进行排序,并使用set
将排序后的数组分配给sorted
变量。
Twig verbatim
标签
verbatim
将部分标记为不应该分析的原始文本。
{% verbatim %}
<ul>
{% for word in words %}
<li>{{ word }}</li>
{% endfor %}
</ul>
{% endverbatim %}
例如,如果我们有一个讲解 Twig 标签的教程,则无需分析一部分演示。
Twig 格式过滤器
format
过滤器通过替换占位符来格式化给定的字符串。 它的作用类似于sprintf()
函数。
$name = "John Doe";
$age = 34;
echo $twig->render('formatfil.html.twig', ['name' => $name, 'age' => $age]);
我们向模板发送两个变量。
{{ "%s is %d years old" | format(name, age) }}
我们使用format
构建字符串。
Twig 日期函数
date()
函数将参数转换为日期以允许进行日期比较。
$user = ['name' => 'John Doe', 'created_at' => '2011/11/10'];
echo $twig->render('datefun.html.twig', ['user' => $user]);
用户数组具有created_at
键。
{% if date(user.created_at) < date('-5years') %}
<p>{{ user.name }} is a senior user</p>
{% endif %}
在模板中,我们比较两个日期。
Twig 自动转义
Twig 自动转义某些字符,例如<
或>
。
$twig = new Environment($loader, [
'autoescape' => false
]);
可以使用autoescape
选项关闭自动转义。
$data = "<script src='http::/example.com/nastyscript.js'></script>";
echo $twig->render('autoescape.html.twig', ['data' => $data]);
用户可能会有意向应用添加危险的输入。 通过自动转义可以防止包含未知的 JS 文件。
<p>
The data is {{ data }}
</p>
<p>
The data is {{ data | raw }}
</p>
如果启用了自动转义,我们可以使用raw
过滤器显示原始输入。
<p>
The data is <script src="http:/example.com/nastyscript.js"></script>
</p>
<p>
The data is <script src='http:/example.com/nastyscript.js'></script>
</p>
此部分输出显示字符如何转义。
Twig 测试
Twig 测试允许测试数据。 使用is
运算符进行测试。
$words = ['', null, 'rock', ' ', 'forest'];
echo $twig->render('tests.html.twig', ['words' => $words]);
我们有一个包含空,空和空白元素的单词数组。
<ul>
{% for word in words %}
{% if word is null %}
<p>null element</p>
{% elseif word | trim is empty %}
<p>Empty element</p>
{% else %}
<li>{{ word }}</li>
{% endif %}
{% endfor %}
</ul>
为了处理空,空和空元素,Twig 进行了empty
和null
测试。
Twig 继承
Twig 的模板继承是一项强大的函数,可消除重复并促进维护。
inheritance.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);
echo $twig->render('derived.html.twig');
这是inheritance.php
文件。 它呈现derived.html.twig
,它从base.html.twig
扩展。
templates/base.html.twig
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
基本布局定义了两个由子代替换的块:title
和body
。
templates/derived.html.twig
{% extends 'base.html.twig' %}
{% block title %}Some title{% endblock %}
{% block body %}
The body contents
{% endblock %}
派生的子模板使用extends
关键字从基本模板继承。 这两个块定义了自定义文本。
$ php inheritance.php
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Some title</title>
</head>
<body>
The body contents
</body>
</html>
This is the output.
Symfony 的例子
Twig 是 Symfony 框架的组成部分。 下一个示例显示在 Symfony 骨架应用中使用 Twig 的步骤。
$ composer create-project symfony/skeleton simple
$ cd simple
我们创建一个新的 Symfony 框架应用,然后移至项目目录。
$ composer require server --dev
我们包括开发服务器。
$ composer require maker annotations twig
我们包括一些基本的 Symfony 组件,包括 Twig。
$ php bin/console make:controller HomeController
我们创建一个家庭控制器。
src/Controller/HomeController.php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
class HomeController extends AbstractController
{
/**
* @Route("/home", name="home")
*/
public function index()
{
$words = ['sky', 'blue', 'cloud', 'symfony', 'forest'];
return $this->render('home/index.html.twig', [
'words' => $words
]);
}
}
在家庭控制器中,我们渲染index.html.twig
模板,并将其传递给$words
数组进行处理。
templates/base.html.twig
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
{% block javascripts %}{% endblock %}
</body>
</html>
这是基本布局页面。
templates/home/index.html.twig
{% extends 'base.html.twig' %}
{% block title %}Home page{% endblock %}
{% block body %}
<h2>List of words</h2>
<ul>
{% for word in words %}
<li>{{ word }}</li>
{% endfor %}
</ul>
{% endblock %}
这是主页模板。 它使用for
标记遍历单词,然后将它们输出到无序列表中。
$ php bin/console server:run
我们启动服务器。
我们导航到http://localhost:8000/home
以查看结果。
在本教程中,我们使用了 Twig 从模板和数据生成文档。 我们介绍了 Twig 标签,过滤器,测试和继承。 我们在 Symfony 应用中显示了 Twing。
您可能也对以下相关教程感兴趣: PHP Faker 教程,Respect 验证教程, Symfony 入门, Rakit 验证教程 , PHP PDO 教程和 PHP 教程。
{% endraw %}
Valitron 教程
PHP Valitron 教程展示了如何使用 Valitron 验证包验证 PHP 值。
Valitron
Valitron 是一个简单,最小且优雅的独立验证库,没有依赖项。
安装
$ composer require vlucas/valitron
$ composer require tightenco/collect
我们安装了 Valitron 套件和 Laravel 的集合套件。
简单的例子
在第一个示例中,我们展示了如何进行非常简单的验证。
simple.php
<?php
require('vendor/autoload.php');
use Valitron\Validator;
$validator = new Validator(['name' => 'John Doe']);
$validator->rule('required', 'name');
if($validator->validate()) {
echo "Validation passed";
} else {
$coll = collect($validator->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
}
该示例验证一个必需值。
use Valitron\Validator;
我们包括验证器。
$validator = new Validator(['name' => 'John Doe']);
我们创建Validator
的实例,并将其传递给要验证的值。
$validator->rule('required', 'name');
我们用rule()
方法指定required
规则。
if($validator->validate()) {
验证通过validate()
执行。
$coll = collect($validator->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
如果验证失败,我们将得到错误并显示。
$ php simple.php
Validation passed
这是输出。
验证规则
Valitron 包含一组预定义规则,例如required
,email
,min
,max
或url
。
规则可以与|
字符结合使用。
multiple_rules.php
<?php
require('vendor/autoload.php');
use Valitron\Validator;
$rules = [
'required' => ['name', 'email'],
'alphaNum' => 'name',
'integer' => 'age',
'min' => [['age', 1]],
'email' => 'email'
];
$validator = new Validator(['name' => 'John Doe', 'age' => 34]);
$validator->rules($rules);
if ($validator->validate()) {
echo "Validation passed";
} else {
$errors = $validator->errors();
foreach ($errors as $arr) {
foreach ($arr as $error) {
echo $error . "\n";
}
};
}
该示例使用了多个验证规则。
$rules = [
'required' => ['name', 'email'],
'alphaNum' => 'name',
'integer' => 'age',
'min' => [['age', 1]],
'email' => 'email'
];
我们有四个验证规则。 需要name
和email
。 name
必须为字母数字值,age
必须为整数,最小值为 1。最后,email
必须为有效的电子邮件地址。
$ php multiple_rules.php
Email is required
Email is not a valid email address
Name must contain only letters a-z and/or numbers 0-9
该示例以三个验证失败结束。
Valitron 链接规则
可以通过链接rule()
方法来添加规则。
chaining.php
<?php
require('vendor/autoload.php');
use Valitron\Validator;
$validator = new Validator(['name' => 'John Doe', 'email' => 'johndoe#gmail.com']);
$validator->rule('required', 'name')->rule('email', 'email');
if($validator->validate()) {
echo "Validation passed";
} else {
$coll = collect($validator->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
}
该示例链接了两个规则。
$validator->rule('required', 'name')->rule('email', 'email');
我们通过链接rule()
方法添加了两个验证规则。
验证日期
日期有四个验证规则:date
,dateFormat
,dateBefore
和dateAfter
。
date_before.php
<?php
require('vendor/autoload.php');
use Valitron\Validator;
$validator = new Validator(['created_at' => '2019-03-01']);
$validator->rule('dateBefore', 'created_at', '2018-10-13');
if ($validator->validate()) {
echo "Validation passed";
} else {
$coll = collect($validator->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
}
该示例使用dateBefore
规则验证两个日期。
$validator = new Validator(['created_at' => '2019-03-01']);
$validator->rule('dateBefore', 'created_at', '2018-10-13');
使用dateBefore
规则,我们验证给定日期早于其他日期。
$ php date_before.php
Created At must be date before '2018-10-13'
This is the output.
验证 IP 地址
IP 地址使用ip
规则进行验证。
ipaddress.php
<?php
require 'vendor/autoload.php';
use Valitron\Validator;
$vals = ['ip1' => '127.0.0.1', 'ip2' => 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329',
'ip3' => 'FE80::0202:B3FF:FE1E:8329', 'ip4' => '0.0.1'];
$coll = collect($vals);
$coll->each(function ($value, $key) {
$validator = new Validator([$key => $value]);
$validator->rule('ip', $key);
if ($validator->validate()) {
echo "Validation passed for $key with $value" . "\n";
} else {
$errs = collect($validator->errors());
$messages = $errs->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
}
});
该示例验证 IP v4 IP v6 地址。
$ php ipaddress.php
Validation passed for ip1 with 127.0.0.1
Validation passed for ip2 with FE80:0000:0000:0000:0202:B3FF:FE1E:8329
Validation passed for ip3 with FE80::0202:B3FF:FE1E:8329
Ip4 is not a valid IP address
This is the output.
自定义消息
我们可以提供自定义验证消息。 消息通过message()
传递。
custom_message.php
<?php
require('vendor/autoload.php');
use Valitron\Validator;
$validator = new Validator(['name' => '']);
$validator->rule('required', 'name')->message('{field} is compulsory')->label("name");
$validator->rule('lengthMin', 'name', 2)->message('{field} must have at least 2 characters')
->label("name");
if($validator->validate()) {
echo "Validation passed";
} else {
$coll = collect($validator->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
}
该示例添加了自定义消息。
$validator->rule('required', 'name')->message('{field} is compulsory')->label("name");
使用链接的方法调用,我们添加了自定义验证消息。
$ php custom_message.php
name is compulsory
name must have at least 2 characters
This is the output.
值的验证子集
值的子集使用subset
规则进行验证。
subsets.php
<?php
require('vendor/autoload.php');
use Valitron\Validator;
$vals = ['colors' => ['green', 'blue', 'black']];
$validator = new Validator($vals);
$validator->rule('subset', 'colors', ['red', 'green', 'blue', 'orange', 'yellow']);
if ($validator->validate()) {
echo "Validation passed";
} else {
$coll = collect($validator->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
}
该示例检查$vals
变量是否包含来自定义的颜色值子集的颜色。
验证 GET 数据
在以下示例中,我们验证 GET 数据。
get_data.php
<?php
require('vendor/autoload.php');
use Valitron\Validator;
$validator = new Validator($_GET);
$validator->rule('required', ['name', 'email']);
$validator->rule('email', 'email');
if ($validator->validate()) {
echo "Validation passed";
} else {
$coll = collect($validator->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
}
该示例验证来自 GET 请求的名称和电子邮件参数。
$validator = new Validator($_GET);
全局$_GET
变量传递给Validator
。
$ php -S localhost:8000
PHP 7.2.11 Development Server started at Sat Feb 23 17:24:05 2019
Listening on http://localhost:8000
Document root is C:\Users\Jano\Documents\php-progs\valitron
Press Ctrl-C to quit.
我们启动内置的 Web 服务器。
$ curl "localhost:8000/get_data.php?name=John%20Doe&email=john.doe#gmail.com"
Email is not a valid email address
我们使用curl
工具创建带有两个参数的 GET 请求。
您可能也对以下相关教程感兴趣: PHP Respect 验证教程, PHP Rakit 验证教程, PHP PDO 教程, PHP 文件系统函数 , PHP 教程。
在本教程中,我们使用了 Valitron 来验证 PHP 值。
Doctrine DBAL QueryBuilder
教程
Doctrine DBAL QueryBuilder
教程显示了如何使用 Doctrine 的QueryBuilder
在 PHP 中编程数据库。
Doctrine
Doctrine 是一组 PHP 库,主要致力于在 PHP 中提供持久性服务。 它的主要项目是对象关系映射器(ORM)和数据库抽象层(DBAL)。 Doctrine 是根据 MIT 许可免费提供的一个开源项目。
Doctrine QueryBuilder
Doctrine QueryBuilder
为创建和运行数据库查询提供了方便,流畅的接口。 它是对运行 SQL 语句的低级详细信息的抽象。 它可以使程序员避免过程的复杂性。
Doctrine 有两种查询构建器; 一个用于 ORM,一个用于 DBAL。 在本教程中,我们介绍了 DBAL 的QueryBuilder
。
Doctrine 数据库抽象层(DBAL)是位于 PDO 之上的抽象层,并提供了一种直观且灵活的 API,可以与最受欢迎的关系数据库进行通信。
PostgreSQL 数据库
在本教程中,我们使用 PostgreSQL 数据库。
cars_postgre.sql
-- cars.sql for PostgreSQL database
DROP TABLE IF EXISTS cars;
CREATE TABLE cars(id SERIAL PRIMARY KEY, name VARCHAR(255), price INT);
INSERT INTO cars(name, price) VALUES('Audi',52642);
INSERT INTO cars(name, price) VALUES('Mercedes',57127);
INSERT INTO cars(name, price) VALUES('Skoda',9000);
INSERT INTO cars(name, price) VALUES('Volvo',29000);
INSERT INTO cars(name, price) VALUES('Bentley',350000);
INSERT INTO cars(name, price) VALUES('Citroen',21000);
INSERT INTO cars(name, price) VALUES('Hummer',41400);
INSERT INTO cars(name, price) VALUES('Volkswagen',21600);
这些 SQL 命令创建一个cars
表。
Doctrine 安装
我们安装了 Doctrine 和一些辅助工具。
$ composer req doctrine/dbal
我们安装 Doctrine。 请注意,DBAL 层包含在doctrine/dbal
包中。
$ composer req symfony/var-dumper
$ composer req tightenco/collect
我们安装了 Symfony 的 dumper 和 Laravel 集合。 我们将在示例中使用它们。
$ composer dumpautoload
我们生成项目中需要包含的所有类的列表。 composer
重新读取composer.json
文件以建立要自动加载的文件列表。
引导 Doctrine CLI 示例
我们创建一个引导文件,该文件将包含在所有示例中。
bootstrap.php
<?php
require_once "vendor/autoload.php";
use Doctrine\DBAL\DriverManager;
$attrs = ['driver' => 'pdo_pgsql', 'host' => 'localhost', 'dbname' => 'testdb',
'port' => 5432, 'user' => 'postgres', 'password' => 's$cret'];
$conn = DriverManager::getConnection($attrs);
在引导文件中,我们包括自动加载文件并建立与 PostgreSQL 数据库的连接。
获取 PostgreSQL 版本
在第一个示例中,我们获得 PostgreSQL 的版本。
version.php
<?php
require_once "bootstrap.php";
$queryBuilder = $conn->createQueryBuilder();
$queryBuilder = $queryBuilder->select('version()');
$version = $queryBuilder->execute()->fetchColumn(0);
echo $version . "\n";
该示例显示 PostgreSQL 数据库的版本。
$queryBuilder = $conn->createQueryBuilder();
在连接对象中,我们使用createQueryBuilder()
创建查询生成器。
$queryBuilder = $queryBuilder->select('version()');
我们用select()
执行version()
函数。
$version = $queryBuilder->execute()->fetchColumn(0);
我们执行查询并使用fetchColumn()
获取结果。 注意方法调用的链接; 这称为流利的 API。
$ php version.php
PostgreSQL 11.1, compiled by Visual C++ build 1914, 64-bit
这是输出。
Doctrine QueryBuilder
fetchall
fetchall()
方法返回表中的所有行。
featch_all.php
<?php
require_once "bootstrap.php";
$queryBuilder = $conn->createQueryBuilder();
$queryBuilder->select('*')->from('cars');
$stm = $queryBuilder->execute();
$data = $stm->fetchAll();
$coll = collect($data);
$sorted = $coll->sortBy('price');
$sorted->each(function($item, $key) {
echo sprintf("Id: %d Name: %s Price: %d\n", $item['id'], $item['name'], $item['price']);
});
该示例从cars
表中检索所有行。
$queryBuilder->select('*')->from('cars');
我们从cars
表中选择所有行。 select()
将列名显示为参数。
$stm = $queryBuilder->execute();
$data = $stm->fetchAll();
我们执行查询并使用fetchAll()
获取所有行。
$coll = collect($data);
$sorted = $coll->sortBy('price');
我们使用 Laravel 集合对数据进行排序。
$sorted->each(function($item, $key) {
echo sprintf("Id: %d Name: %s Price: %d\n", $item['id'], $item['name'], $item['price']);
});
排序后的数据将打印到控制台。
$ php fetch_all.php
Id: 3 Name: Skoda Price: 9000
Id: 6 Name: Citroen Price: 21000
Id: 8 Name: Volkswagen Price: 21600
Id: 4 Name: Volvo Price: 29000
Id: 7 Name: Hummer Price: 41400
Id: 1 Name: Audi Price: 52642
Id: 2 Name: Mercedes Price: 57127
Id: 5 Name: Bentley Price: 350000
这是输出。 数据按price
列排序。
DocQuery QueryBuilder
表别名
我们可以给数据库表起别名。 当表名很长并且我们使用多个表时,这很有用。
table_alias.php
<?php
require_once "bootstrap.php";
$queryBuilder = $conn->createQueryBuilder();
$queryBuilder = $queryBuilder->select('*')->from('cars', 'c')
->where('c.price < 30000');
$selected = $queryBuilder->execute()->fetchAll();
dump($selected);
该示例打印价格低于 30000 的所有汽车。
$queryBuilder = $queryBuilder->select('*')->from('cars', 'c')
->where('c.price < 30000');
我们给cars
表别名c
。 稍后,我们通过别名引用该表。
dump($selected);
我们用dump()
输出数据。
$ php table_alias.php
array:4 [
0 => array:3 [
"id" => 3
"name" => "Skoda"
"price" => 9000
]
1 => array:3 [
"id" => 4
"name" => "Volvo"
"price" => 29000
]
2 => array:3 [
"id" => 6
"name" => "Citroen"
"price" => 21000
]
3 => array:3 [
"id" => 8
"name" => "Volkswagen"
"price" => 21600
]
]
有四辆价格低于 30000 的汽车。输出使用 Symfony 的自卸车很好地格式化。 输出也会在端子上着色。
Doctrine QueryBuilder
setParameter
setParameter()
用于将参数设置为查询占位符。 原则支持位置参数和命名参数。
参数化查询用于保护代码免遭 SQL 注入并提高查询效率。
fetch_column.php
<?php
require_once "bootstrap.php";
$id = 6;
$queryBuilder = $conn->createQueryBuilder();
$queryBuilder = $queryBuilder->select('name')->from('cars')
->where('id = ?')->setParameter(0, $id);
$car_name = $queryBuilder->execute()->fetchColumn(0);
echo $car_name . "\n";
在示例中,我们获得的行具有 ID6。我们使用参数化查询来获取列。
$queryBuilder = $queryBuilder->select('name')->from('cars')
->where('id = ?')->setParameter(0, $id);
占位符用?
字符标识。 此类型称为位置参数。 使用setParameter()
,我们将值映射到占位符。
$ php fetch_column.php
Citroen
This is the output.
Doctrine QueryBuilder
orderBy
数据可以通过orderBy()
进行排序。 有时我们无法控制数据发送给我们的方式; 在这种情况下,我们可以使用 Laravel 集合对数据进行排序,就像在获取所有示例中所做的那样。
order_by.php
<?php
require_once "bootstrap.php";
$queryBuilder = $conn->createQueryBuilder();
$queryBuilder
->select('*')
->from('cars')
->orderBy('name', 'desc');
$stm = $queryBuilder->execute();
$data = $stm->fetchAll();
$coll = collect($data);
$coll->each(function($item, $key) {
echo sprintf("id: %d name: %s price: %d\n", $item['id'], $item['name'], $item['price']);
});
该示例从cars
表中检索所有行,并按汽车名称降序对其进行排序。
$queryBuilder
->select('*')
->from('cars')
->orderBy('name', 'desc');
数据已选择并排序。
$ php order_by.php
id: 4 name: Volvo price: 29000
id: 8 name: Volkswagen price: 21600
id: 3 name: Skoda price: 9000
id: 2 name: Mercedes price: 57127
id: 7 name: Hummer price: 41400
id: 6 name: Citroen price: 21000
id: 5 name: Bentley price: 350000
id: 1 name: Audi price: 52642
This is the output.
Doctrine QueryBuilder
WHERE
下面的示例演示如何使用WHERE IN
子句构建查询。
where_in.php
<?php
require_once "bootstrap.php";
use Doctrine\DBAL\Connection;
$ids = [2, 4, 6];
$queryBuilder = $conn->createQueryBuilder();
$queryBuilder->select('*')->from('cars')
->where('id IN (?)')->setParameter(0, $ids, Connection::PARAM_INT_ARRAY);
$cars = $queryBuilder->execute()->fetchAll();
$data = collect($cars);
$data->each(function ($e) {
dump($e);
});
该示例打印具有指定 ID:2、4 和 6 的汽车。
$queryBuilder->select('*')->from('cars')
->where('id IN (?)')->setParameter(0, $ids, Connection::PARAM_INT_ARRAY);
我们需要告诉 Doctrine 我们使用带有Connection::PARAM_INT_ARRAY
标志的数组作为参数。
$ php where_in.php
array:3 [
"id" => 2
"name" => "Mercedes"
"price" => 57127
]
array:3 [
"id" => 4
"name" => "Volvo"
"price" => 29000
]
array:3 [
"id" => 6
"name" => "Citroen"
"price" => 21000
]
This is the output.
Doctrine QueryBuilder
andWhere
我们可以通过添加andWhere()
来合并WHERE
子句。
and_where.php
<?php
require_once "bootstrap.php";
$minPrice = 10000;
$maxPrice = 50000;
$queryBuilder = $conn->createQueryBuilder();
$queryBuilder
->select('*')
->from('cars')
->where('price > ?')
->andWhere('price < ?')
->setParameter(0, $minPrice)
->setParameter(1, $maxPrice);
$stm = $queryBuilder->execute();
$data = $stm->fetchAll();
$coll = collect($data);
$coll->each(function($item, $key) {
echo sprintf("id: %d name: %s price: %d\n", $item['id'], $item['name'], $item['price']);
});
该示例显示了价格在给定的最低和最高价格之间的所有汽车。
$ php and_where.php
id: 4 name: Volvo price: 29000
id: 6 name: Citroen price: 21000
id: 7 name: Hummer price: 41400
id: 8 name: Volkswagen price: 21600
有四辆满足条件的汽车。
Doctrine QueryBuilder
插入行
用insert()
和values()
插入新行。
insert_row.php
<?php
require_once "bootstrap.php";
$name = 'Oldsmobile';
$price = 28800;
$queryBuilder = $conn->createQueryBuilder();
$queryBuilder = $queryBuilder->insert('cars')
->values(['name' => '?', 'price' => '?'])
->setParameters([0 => $name, 1 => $price]);
$queryBuilder->execute();
$sql = $queryBuilder->getSQL();
echo "Executed: $sql\n";
该示例将新车插入cars
表。
$queryBuilder = $queryBuilder->insert('cars')
->values(['name' => '?', 'price' => '?'])
->setParameters([0 => $name, 1 => $price]);
可以使用setParameters()
指定多个参数。
$sql = $queryBuilder->getSQL();
getSQL()
获取由 Doctrine 生成的 SQL 语句。
$ php insert_row.php
Executed: INSERT INTO cars (name, price) VALUES(?, ?)
输出显示生成的 SQL 语句。
Doctrine QueryBuilder
删除
用delete()
删除数据。
delete_rows.php
<?php
require_once "bootstrap.php";
$name = 'Oldsmobile';
$price = 26600;
$queryBuilder = $conn->createQueryBuilder();
$queryBuilder = $queryBuilder->delete('cars')
->where('id IN (1, 2, 3)');
$n = $queryBuilder->execute();
echo "The query deleted $n rows\n";
该示例删除 ID 为 1、2 和 3 的行。
$n = $queryBuilder->execute();
execute()
方法返回已删除的行数。
$ php delete_rows.php
The query deleted 3 rows
This is the output.
Doctrine QueryBuilder
更新行
用udpate()
和set()
更新一行。
udpate_row.php
createQueryBuilder();
$queryBuilder = $queryBuilder->update('cars')
->set('price', $queryBuilder->createNamedParameter($price))
->where('id = 9');
$queryBuilder->execute();
$sql = $queryBuilder->getSQL();
echo "Executed: $sql\n";
该示例使用 ID 9 更新汽车的价格。
Symfony Doctrine 的例子
以下示例是一个简单的 Symfony Web 应用。 Symfony 使用 Doctrine 进行持久化。
$ composer create-project symfony/skeleton symfapp
$ cd symfapp
我们创建一个新的 Symfony 骨架应用。
$ composer require symfony/orm-pack
我们安装 Doctrine。
$ composer require maker --dev
$ composer require server --dev
我们安装maker
和server
组件。
config/packages/doctrine.yaml
doctrine:
dbal:
# configure these for your database server
driver: pdo_pgsql
charset: utf8
我们将 Doctrine 配置为使用 PostgreSQL。 默认情况下,Symfony 具有 MySQL 的配置。
.env
...
DATABASE_URL=pgsql://postgres:[email protected]:5432/testdb
在.env
文件中,设置DATABASE_URL
。
$ php bin/console doctrine:query:sql "select version()"
array(1) {
[0]=>
array(1) {
["version"]=>
string(58) "PostgreSQL 11.1, compiled by Visual C++ build 1914, 64-bit"
}
}
我们验证 PostgreSQL 设置。
$ php bin/console make:controller HomeController
与制造商一起,我们创建一个新的控制器。
src/Controller/HomeController.php
<?php
namespace App\Controller;
use Doctrine\DBAL\Connection;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class HomeController extends AbstractController
{
/**
* @Route("/home", name="home")
*/
public function index(Connection $conn)
{
$queryBuilder = $conn->createQueryBuilder();
$data = $queryBuilder->select('*')->from('cars')->execute()->fetchAll();
return $this->json($data);
}
}
index()
方法返回数据库表中的所有行。 请注意,出于简单原因,我们已将查询生成器放入控制器中。 在生产应用中,还应该有一个服务层和一个存储库。
return $this->json($data);
数据以 JSON 格式发送回客户端。
$ php bin/console server:run
我们运行开发服务器。
$ curl localhost:8000/home
[{"id":4,"name":"Volvo","price":29000},{"id":5,"name":"Bentley","price":350000},
{"id":6,"name":"Citroen","price":21000},{"id":7,"name":"Hummer","price":41400},
{"id":8,"name":"Volkswagen","price":21600},{"id":9,"name":"Oldsmobile","price":26600}]
使用curl
,我们生成一个对应用的请求。
您可能也对以下相关教程感兴趣: PHP PDO 教程, Symfony 简介, PHP 教程或列出所有 PHP 教程。
在本教程中,我们使用了 Doctrine QueryBuilder
和 PostgreSQL 数据库。
{% raw %}
PHP Respect 验证教程
PHP Respect 验证教程展示了如何使用 Respect 验证包来验证 PHP 值。
Respect 验证
Respect 验证是一个 PHP 独立验证库。
安装
$ composer require respect/validation
$ composer require tightenco/collect
我们安装了 Respect 验证包和 Laravel 的集合包。
Respect 验证简单示例
在第一个示例中,我们展示了如何进行非常简单的验证。
simple.php
<?php
require('vendor/autoload.php');
use Respect\Validation\Validator as v;
$name = "John Doe";
$r = v::alnum()->validate($name);
if ($r) {
echo "Validation passed";
} else {
echo "Validation failed";
}
该示例验证一个值。
use Respect\Validation\Validator as v;
我们包括验证器。
$r = v::alnum()->validate($name);
alnum
是一个允许字母数字值的验证规则。 它还允许有空间。 validate()
方法将验证规则,并返回指示失败或成功的布尔值。
if ($r) {
echo "Validation passed";
} else {
echo "Validation failed";
}
基于返回的值,我们显示验证消息。
$ php simple.php
Validation passed
这是输出。
新增字符
我们可以在规则中添加一个字符。
add_character.php
<?php
require('vendor/autoload.php');
use Respect\Validation\Validator as v;
$name = "Vane-Tempest-Stewart";
$r = v::alnum('-')->validate($name);
if ($r) {
echo "Validation passed";
} else {
echo "Validation failed";
}
在示例中,我们在alnum
规则中添加了破折号。
$name = "Vane-Tempest-Stewart";
一些名称可能包含破折号。
$r = v::alnum('-')->validate($name);
我们在alnum
规则中添加破折号。
Respect 验证链接规则
规则可以链接在一起。
chaining.php
<?php
require('vendor/autoload.php');
use Respect\Validation\Validator as v;
$name = "John";
$r = v::alnum()->length(4, null)->validate($name);
if ($r) {
echo "Validation passed";
} else {
echo "Validation failed";
}
在示例中,我们有两个规则:alnum
和length
。
$r = v::alnum()->length(4, null)->validate($name);
该名称只能包含字母数字字符,并且必须至少包含四个字符。
Respect 验证合并规则
规则的组合类似于链接技术。 Rules\AllOf
用于组合多个规则。
combine_rules.php
<?php
require('vendor/autoload.php');
use Respect\Validation\Validator as v;
use Respect\Validation\Rules;
$name = "John";
$nameValidator = new Rules\AllOf(
new Rules\Alnum(),
new Rules\Length(5, 40)
);
$r = $nameValidator->validate($name);
if ($r) {
echo "Validation passed";
} else {
echo "Validation failed";
}
该示例将两个验证规则与Rules\AllOf
结合在一起。
Respect 验证断言函数
validate()
方法返回一个布尔值。 assert()
方法返回完整的验证报告。
assert_fun.php
<?php
require('vendor/autoload.php');
use Respect\Validation\Validator as v;
use Respect\Validation\Exceptions\NestedValidationException;
$name = "";
$validator = v::alnum()->notempty();
try {
$validator->assert($name);
} catch(NestedValidationException $ex) {
$coll = collect($ex->getMessages());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
}
该示例对验证规则使用assert()
方法,并显示错误消息。
$validator->assert($name);
我们使用assert()
验证名称值。
$coll = collect($ex->getMessages());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
借助 Laravel 的集合,我们显示了错误消息。
$ php assert_fun.php
"" must contain only letters (a-z) and digits (0-9)
"" must not be empty
This is the output.
Respect 验证范围
between
规则验证范围,包括整数,字符和日期。
between_rule.php
<?php
require('vendor/autoload.php');
use Respect\Validation\Validator as v;
$age = 34;
$r = v::intVal()->between(18, 99)->validate($age);
if ($r) {
echo "Age validation passed\n";
} else {
echo "Age validation failed\n";
}
$char = 'g';
$r = v::stringType()->between('a', 'c')->validate($char);
if ($r) {
echo "Letter validation passed\n";
} else {
echo "Letter validation failed\n";
}
$myDate = '2013-01-01';
$r = v::date()->between('2009-01-01', '2019-01-01')->validate($myDate);
if ($r) {
echo "Date validation passed\n";
} else {
echo "Date validation failed\n";
}
该示例使用between
规则。
$r = v::intVal()->between(18, 99)->validate($age);
此规则检查$age
变量是否在 18 到 99 之间。
$r = v::stringType()->between('a', 'c')->validate($char);
此规则检查$char
变量是否在'a'和'c'字符之间。
$r = v::date()->between('2009-01-01', '2019-01-01')->validate($myDate);
该规则检查$myDate
变量是否在两个指定的日期之间。
Respect 验证对象
对象属性使用attribute()
进行验证。
user.php
<?php
class User {
private $name;
private $email;
public function getName() : string {
return $this->name;
}
public function setName($name) : void {
$this->name = $name;
}
public function getEmail() : string {
return $this->email;
}
public function setEmail($email) : void {
$this->email = $email;
}
}
这是user.php
。
validate_object.php
<?php
require('vendor/autoload.php');
require_once('user.php');
use Respect\Validation\Validator as v;
use Respect\Validation\Exceptions\NestedValidationException;
$user = new User();
$user->setName('Jo');
$user->setEmail('johndoe#gmail.com');
$userValidator = v::attribute('name', v::alnum()->length(4, null))
->attribute('email', v::email());
try {
$userValidator->assert($user);
} catch(NestedValidationException $ex) {
$coll = collect($ex->getMessages());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
}
该示例验证User
类的属性。
$userValidator = v::attribute('name', v::alnum()->length(4, null))
->attribute('email', v::email());
这些是用户对象属性的规则。
$ php validate_object.php
name must have a length greater than 4
email must be valid email
This is the output.
自定义消息
我们可以提供自定义验证消息。
custom_message.php
<?php
require('vendor/autoload.php');
use Respect\Validation\Validator as v;
use Respect\Validation\Exceptions\NestedValidationException;
$name = "";
$validator = v::alnum()->notEmpty()->setName('name');
try {
$validator->assert($name);
} catch(NestedValidationException $ex) {
$errors = $ex->findMessages([
'alnum' => '{{name}} must contain only letters and digits',
'notEmpty' => '{{name}} must not be empty'
]);
$coll = collect($errors);
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
}
该示例添加了两个自定义消息。
$validator = v::alnum()->notEmpty()->setName('name');
使用setName()
方法,我们为模板占位符设置了一个值。
$errors = $ex->findMessages([
'alnum' => '{{name}} must contain only letters and digits',
'notEmpty' => '{{name}} must not be empty'
]);
在这里,我们提供自定义错误消息。
$ php custom_message.php
name must contain only letters and digits
name must not be empty
This is the output.
您可能也对以下相关教程感兴趣: PHP Rakit 验证教程, Valitron 教程, PHP PDO 教程, Twig 教程, PHP 文件系统函数, PHP 教程。
在本教程中,我们使用了 PHP Respect 验证库来验证值。
{% endraw %}
PHP Rakit 验证教程
PHP Rakit 验证教程展示了如何使用 Rakit 验证包来验证 PHP 值。
Rakit 验证
Rakit 验证是一个 PHP 独立验证库。 它是受 Laravel 的Illuminate\Validation
启发的。
安装
$ composer require rakit/validation
$ composer require tightenco/collect
我们安装了 Rakit 验证包和 Laravel 的集合包。
简单的例子
在第一个示例中,我们展示了如何进行非常简单的验证。
simple.php
<?php
require('vendor/autoload.php');
use Rakit\Validation\Validator;
$validator = new Validator;
$vals = ['name' => ''];
$rules = ['name' => 'required'];
$validation = $validator->make($vals, $rules);
$validation->validate();
if ($validation->fails()) {
$coll = collect($validation->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
} else {
echo "Validation passed";
}
该示例验证一个必需值。
use Rakit\Validation\Validator;
我们包括验证器。
$validator = new Validator;
我们创建Validator
的实例。
$vals = ['name' => ''];
$rules = ['name' => 'required'];
$vals
包含要验证的值。 $rules
包含验证规则。 在我们的情况下,需要name
值。
$validation = $validator->make($vals, $rules);
使用make()
方法,我们准备验证; 我们通过值和规则。
$validation->validate();
我们使用validate()
进行验证。
if ($validation->fails()) {
使用fails()
,我们检查验证是否失败。
$coll = collect($validation->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
我们使用 Laravel 的集合来分析错误。
$ php simple.php
The Name is required
这是输出。
验证规则
Rakit 验证包含一组预定义规则,例如required
,email
,min
,max
或url
。
规则可以与|
字符结合使用。
rules.php
<?php
require 'vendor/autoload.php';
use Rakit\Validation\Validator;
$validator = new Validator;
$vals = ['name' => 'John Doe', 'email' => 'johndoe#gmail.com',
'password' => '12345', 'confirm_password' => '23456'];
$rules = ['name' => 'required',
'email' => 'required|email',
'password' => 'required|min:6',
'confirm_password' => 'required|same:password'];
$validation = $validator->make($vals, $rules);
$validation->validate();
if ($validation->fails()) {
$coll = collect($validation->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
} else {
echo "Validation passed";
}
该示例使用了多个验证规则。
$rules = ['name' => 'required',
'email' => 'required|email',
'password' => 'required|min:6',
'confirm_password' => 'required|same:password'];
我们有四个验证规则。 必须输入email
,必须是有效的电子邮件地址。 password
是必需的,并且必须至少包含六个字符。 confirm_password
必须与password
相同。
$ php rules.php
The Email is not valid email
The Password minimum is 6
The Confirm password must be same with password
该示例以三个验证失败结束。
验证日期
下一个示例显示如何验证日期。
dates.php
<?php
require('vendor/autoload.php');
use Rakit\Validation\Validator;
$validator = new Validator;
$vals = ['born' => '2000-03-30', 'meetingDate' => '2010-12-31'];
$rules = ['born' => 'before:2018-12-31', 'meetingDate' => 'after:2019-02-02'];
$validation = $validator->make($vals, $rules);
$validation->validate();
if ($validation->fails()) {
$coll = collect($validation->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
} else {
echo "Validation passed";
}
该示例验证两个日期。
$vals = ['born' => '2000-03-30', 'meetingDate' => '2010-12-31'];
$rules = ['born' => 'before:2018-12-31', 'meetingDate' => 'after:2019-02-02'];
使用before
规则,我们验证给定的日期在某个日期之前,并且使用after
规则,我们验证给定的日期在某个日期之后。
$ php dates.php
The MeetingDate must be a date after 2019-02-02.
This is the output.
自定义消息
我们可以提供自定义验证消息。 消息作为第三个参数传递给make()
方法。
custom_message.php
<?php
require('vendor/autoload.php');
use Rakit\Validation\Validator;
$validator = new Validator;
$vals = ['name' => ''];
$rules = ['name' => 'required'];
$msgs = ['name' => 'The name is compulsory'];
$validation = $validator->make($vals, $rules, $msgs);
$validation->validate();
if ($validation->fails()) {
$coll = collect($validation->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
} else {
echo "Validation passed";
}
该示例添加了一条自定义消息。
$msgs = ['name' => 'The name is compulsory'];
这是我们的自定义消息。
$validation = $validator->make($vals, $rules, $msgs);
消息将传递到make()
方法。
$ php custom_message.php
The name is compulsory
This is the output.
验证 GET 数据
在以下示例中,我们验证 GET 数据。
get_data.php
<?php
require('vendor/autoload.php');
use Rakit\Validation\Validator;
$validator = new Validator;
$rules = ['name' => 'required', 'email' => 'required|email'];
$validation = $validator->make($_GET, $rules);
$validation->validate();
if ($validation->fails()) {
$coll = collect($validation->errors());
$messages = $coll->flatten();
foreach ($messages as $message) {
echo $message . "\n";
}
} else {
echo "Validation passed";
}
该示例验证来自 GET 请求的名称和电子邮件参数。
$rules = ['name' => 'required', 'email' => 'required|email'];
$validation = $validator->make($_GET, $rules);
make()
方法将全局$_GET
变量作为第一个参数。
$ php -S localhost:8000
PHP 7.2.11 Development Server started at Sat Feb 2 21:22:23 2019
Listening on http://localhost:8000
Document root is C:\Users\Jano\Documents\php-progs\rakit-val
Press Ctrl-C to quit.
我们启动内置的 Web 服务器。
$ curl "localhost:8000/get_data.php?name=John%20Doe&email=john.doe#gmail.com"
The Email is not valid email
我们使用curl
工具创建带有两个参数的 GET 请求。
您可能也对以下相关教程感兴趣: PHP Respect 验证教程, Valitron 教程, PHP PDO 教程, PHP 文件系统函数 , PHP 教程。
在本教程中,我们使用 Rakit 验证来验证 PHP 值。
PHP PDO 教程
在本教程中,我们展示了如何在 PHP PDO 中对数据库进行编程。
PHP PDO
PHP 数据对象(PDO)定义了用于访问 PHP 中数据库的轻量级接口。 它提供了一个数据访问抽象层,用于在 PHP 中使用数据库。 它定义了用于各种数据库系统的一致 API。
PHP PDO 类
PDO
表示 PHP 与数据库服务器之间的连接。 PDOStatement
代表准备好的语句,在执行该语句后,代表关联的结果集。 PDOException
表示 PDO 引发的错误。
MySQL 数据库
在本教程中,我们将使用 MySQL 数据库。
countries_mysql.sql
DROP TABLE IF EXISTS countries;
CREATE TABLE countries(id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255), population INT);
INSERT INTO countries(name, population) VALUES('China', 1382050000);
INSERT INTO countries(name, population) VALUES('India', 1313210000);
INSERT INTO countries(name, population) VALUES('USA', 324666000);
INSERT INTO countries(name, population) VALUES('Indonesia', 260581000);
INSERT INTO countries(name, population) VALUES('Brazil', 207221000);
INSERT INTO countries(name, population) VALUES('Pakistan', 196626000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Bangladesh', 162099000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Russia', 146838000);
INSERT INTO countries(name, population) VALUES('Japan', 126830000);
这些 SQL 命令创建一个countries
表。
PHP PDO 查询
PDO query()
在单个函数调用中执行一条 SQL 语句,返回该语句返回的结果集(如果有)。
version.php
<?php
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";
$pdo = new PDO($dsn, $user, $passwd);
$stm = $pdo->query("SELECT VERSION()");
$version = $stm->fetch();
echo $version[0] . PHP_EOL;
该示例返回 MySQL 的版本。
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";
这些变量用于创建到数据库的连接字符串。 dsn
是数据源名称,其中包含连接到数据库所需的信息。
$pdo = new PDO($dsn, $user, $passwd);
创建一个新的PDO
对象。 我们向构造器传递数据源名称以及用户名和密码。 PDO
类表示 PHP 与数据库服务器之间的连接。
$stm = $pdo->query("SELECT VERSION()");
query()
方法在单个函数调用中执行一条 SQL 语句。 它返回结果集。
$version = $stm->fetch();
PDO 语句的fetch()
方法从结果集中获取下一行。 在我们的例子中,它是 MySQL 的一个版本。
echo $version[0] . PHP_EOL;
$version
是一个数组; 我们得到它的第一个值。
$ php version.php
5.7.22-0ubuntu0.16.04.1
这是输出。
PHP PDO 执行
PDO exec()
执行一条 SQL 语句并返回受影响的行数。
affected_rows.php
<?php
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";
$pdo = new PDO($dsn, $user, $passwd);
$id = 12;
$nrows = $pdo->exec("DELETE FROM countries WHERE id IN (1, 2, 3)");
echo "The statement affected $nrows rows\n";
该代码示例将删除三行。 它打印受影响的行数。
$nrows = $pdo->exec("DELETE FROM countries WHERE id IN (1, 2, 3)");
在此 SQL 语句中,我们删除 ID 为 1、2 和 3 的行。已删除的行数存储在$nrows
变量中。
echo "The statement deleted $nrows rows\n";
我们打印已删除的行数。
PHP PDO 提取样式
提取样式参数控制如何将下一行返回给调用方。 例如,PDO::FETCH_ASSOC
返回按列名索引的数组,PDO::FETCH_NUM
返回按列号索引的数组,PDO::FETCH_BOTH
返回按列名和索引列号索引的数组。 默认的获取样式为PDO::FETCH_BOTH
。
fetch_style_num.php
<?php
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";
$pdo = new PDO($dsn, $user, $passwd);
$stm = $pdo->query("SELECT * FROM countries");
$rows = $stm->fetchAll(PDO::FETCH_NUM);
foreach($rows as $row) {
printf("$row[0] $row[1] $row[2]\n");
}
在此代码示例中,我们在索引数组中获取数据。
$stm = $pdo->query("SELECT * FROM countries");
我们从countries
表中选择所有数据。
$rows = $stm->fetchAll(PDO::FETCH_NUM);
我们将PDO:FETCH_NUM
样式传递给fetchAll()
方法。
foreach($rows as $row) {
printf("$row[0] $row[1] $row[2]\n");
}
我们遍历$rows
数组并打印字段。 通过数组索引访问这些字段。
fetch_style_assoc.php
<?php
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";
$pdo = new PDO($dsn, $user, $passwd);
$stm = $pdo->query("SELECT * FROM countries");
$rows = $stm->fetchAll(PDO::FETCH_ASSOC);
foreach($rows as $row) {
printf("{$row['id']} {$row['name']} {$row['population']}\n");
}
在此示例中,我们以关联数组的形式获取数据。
$rows = $stm->fetchAll(PDO::FETCH_ASSOC);
在fetchAll()
方法中,我们使用PDO::FETCH_ASSOC
样式。
PHP PDO 参数绑定
SQL 语句通常是动态构建的。 用户提供一些输入,并且此输入已内置到语句中。 每当我们处理来自用户的输入时,我们都必须谨慎。 它具有一些严重的安全隐患。 动态构建 SQL 语句的推荐方法是使用参数绑定。
PDO 包含bindParam()
和bindValue()
方法来创建参数化查询。
PDO 允许将数据绑定到问号或命名的占位符。
parameterized_query.php
<?php
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "root";
$passwd = "andrea";
$pdo = new PDO($dsn, $user, $passwd);
$id = 12;
$stm = $pdo->prepare("SELECT * FROM countries WHERE id = ?");
$stm->bindValue(1, $id);
$stm->execute();
$row = $stm->fetch(PDO::FETCH_ASSOC);
echo "Id: " . $row['id'] . PHP_EOL;
echo "Name: " . $row['name'] . PHP_EOL;
echo "Population: " . $row['population'] . PHP_EOL;
在示例中,我们使用bindValue()
创建参数化查询。 我们使用问号占位符。
$id = 12;
说此输入来自用户。
$stm = $pdo->prepare("SELECT * FROM countries WHERE id = ?");
$stm->bindValue(1, $id);
$stm->execute();
select
语句从表中获取特定行。 我们将带有bindValue()
的值绑定到问号占位符。
在第二种情况下,我们使用bindParam()
。
parameterized_query2.php
<?php
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";
$pdo = new PDO($dsn, $user, $passwd);
$id = 12;
$stm = $pdo->prepare("SELECT * FROM countries WHERE id = :id");
$stm->bindParam(":id", $id, PDO::PARAM_INT);
$stm->execute();
$row = $stm->fetch(PDO::FETCH_ASSOC);
echo "Id: " . $row['id'] . PHP_EOL;
echo "Name: " . $row['name'] . PHP_EOL;
echo "Population: " . $row['population'] . PHP_EOL;
该示例选择并打印特定的行。
$stm = $pdo->prepare("SELECT * FROM countries WHERE id = :id");
$stm->bindParam(":id", $id, PDO::PARAM_INT);
$stm->execute();
这次我们使用命名占位符(:id
)和bindParam()
。
PHP PDO 最后插入的行 ID
PDO lastInsertId()
方法返回最后插入的行 ID。
create_table.php
<?php
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";
$pdo = new PDO($dsn, $user, $passwd);
$sql = "CREATE TABLE words(id INT PRIMARY KEY AUTO_INCREMENT,
word VARCHAR(255))";
$ret = $pdo->exec($sql);
$pdo->exec("INSERT INTO words(word) VALUES ('pen')");
$pdo->exec("INSERT INTO words(word) VALUES ('bum')");
$pdo->exec("INSERT INTO words(word) VALUES ('hum')");
$pdo->exec("INSERT INTO words(word) VALUES ('den')");
$rowid = $pdo->lastInsertId();
echo "The last inserted row id is: $rowid\n";
在示例中,我们创建一个新表。 创建表后,我们用lastInsertId()
找出最后插入的 ID。
$ php create_table.php
The last inserted row id is: 4
This is the output.
mysql> select * from words;
+----+------+
| id | word |
+----+------+
| 1 | pen |
| 2 | bum |
| 3 | hum |
| 4 | den |
+----+------+
4 rows in set (0.01 sec)
我们验证数据。
PHP PDO 事务
事务是针对一个或多个数据库中数据的数据库操作的基本单位。 事务中所有 SQL 语句的影响可以全部提交给数据库,也可以全部回滚。
PDO beginTransaction()
启动新事务。 PDO commit()
提交事务。 PDO rollback()
将回滚事务。
transaction.php
<?php
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";
$pdo = new PDO($dsn, $user, $passwd);
try {
$pdo->beginTransaction();
$stm = $pdo->exec("INSERT INTO countries(name, population) VALUES ('Iraq', 38274000)");
$stm = $pdo->exec("INSERT INTO countries(name, population) VALUES ('Uganda', 37673800)");
$pdo->commit();
} catch(Exception $e) {
$pdo->rollback();
throw $e;
}
在示例中,我们将两个新的国家/地区添加到数据库表中。 将insert
语句放置在事务中:要么执行两个插入,要么都不执行。
} catch(Exception $e) {
$pdo->rollback();
throw $e;
}
如果发生异常,我们回滚事务:没有数据写入数据库。 我们抛出异常,以便异常处理继续按常规方式进行。
PHP PDO 获取元数据
元数据是有关数据库中数据的信息。 元数据包含有关我们存储数据的表和列的信息。 SQL 语句影响的行数是元数据。 结果集中返回的行数和列数也是元数据。
column_count.php
<?php
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";
$pdo = new PDO($dsn, $user, $passwd);
$stm = $pdo->query("SELECT name, population FROM countries WHERE id=1");
$ncols = $stm->columnCount();
echo "The result set contains $ncols columns\n";
在示例中,我们使用columnCount()
方法打印结果集中的列数。
getAttribute()
方法检索数据库连接属性。
connection_attributes.php
<?php
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";
$pdo = new PDO($dsn, $user, $passwd);
$driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
$server_version = $pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
$autocommit_mode = $pdo->getAttribute(PDO::ATTR_AUTOCOMMIT);
echo "Driver: $driver\n";
echo "Server version: $server_version\n";
echo "Autocommit mode: $autocommit_mode\n";
在示例中,我们使用getAttribute()
方法获取驱动程序名称,服务器版本和自动提交模式。
$ php connection_attributes.php
Driver: mysql
Server version: 5.7.22-0ubuntu0.16.04.1
Autocommit mode: 1
这是一个示例输出。
在以下示例中,我们打印列元数据。 列元数据通过getColumnMeta()
方法检索。
column_metadata.php
<?php
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";
$pdo = new PDO($dsn, $user, $passwd);
$stm = $pdo->query("SELECT * FROM countries WHERE id=1");
$col_meta = $stm->getColumnMeta(0);
echo "Table name: {$col_meta["table"]}\n";
echo "Column name: {$col_meta["name"]}\n";
echo "Column length: {$col_meta["len"]}\n";
echo "Column flags: {$col_meta["flags"][0]} {$col_meta["flags"][1]} \n";
在示例中,我们获取列表,名称,长度和标志。
$ php column_metadata.php
Table name: countries
Column name: id
Column length: 20
Column flags: not_null primary_key
This is a sample output.
您可能也对以下相关教程感兴趣: PHP SQLite3 教程, CakePHP 数据库教程, Doctrine QueryBuilder
教程, PHP 文件系统函数 , Twig 教程, PHP Faker 教程, PHP 教程或列出所有 PHP 教程。
在本教程中,我们使用 PHP PDO 处理 MySQL 数据库。
CakePHP 数据库教程
CakePHP 数据库教程展示了如何使用 CakePHP 的数据库包在 PHP 中编程数据库。
CakePHP 数据库
CakePHP 数据库是一个灵活而强大的数据库抽象库,它具有类似 PDO 的 API。 该库可帮助程序员构建查询,防止 SQL 注入,检查和更改模式,以及将调试和配置文件查询发送到数据库。
CakePHP 数据库支持 MySQL/MariaDB,PostgresSQL,SQLite 和 Microsoft SQL Server。
MariaDB 数据库
在本教程中,我们将使用 MariaDB 数据库
countries_mariadb.sql
DROP TABLE IF EXISTS countries;
CREATE TABLE countries(id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255), population INT);
INSERT INTO countries(name, population) VALUES('China', 1382050000);
INSERT INTO countries(name, population) VALUES('India', 1313210000);
INSERT INTO countries(name, population) VALUES('USA', 324666000);
INSERT INTO countries(name, population) VALUES('Indonesia', 260581000);
INSERT INTO countries(name, population) VALUES('Brazil', 207221000);
INSERT INTO countries(name, population) VALUES('Pakistan', 196626000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Bangladesh', 162099000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Russia', 146838000);
INSERT INTO countries(name, population) VALUES('Japan', 126830000);
这些 SQL 命令创建一个countries
表。
安装 CakePHP 数据库
$ composer require cakephp/database
CakePHP 数据库是使用上述命令安装的。
CakePHP 执行
execute()
执行查询。
version.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Cake\Database\Connection;
use Cake\Database\Driver\Mysql;
$driver = new Mysql([
'database' => 'mydb',
'username' => 'root',
'password' => 's$cret',
]);
$conn = new Connection([
'driver' => $driver,
]);
$stm = $conn->execute('SELECT VERSION()');
$version = $stm->fetch()[0];
echo $version . "\n";
该示例打印 MariaDB 数据库的版本。
$driver = new Mysql([
'database' => 'mydb',
'username' => 'root',
'password' => 's$cret',
]);
创建一个新的 MySQL 驱动程序。 我们提供数据库名称,用户名和密码。
$conn = new Connection([
'driver' => $driver,
]);
创建一个连接对象。
$ php version.php
10.1.36-MariaDB
这是输出。
CakePHP 获取
fetch()
方法在执行 SQL 语句后返回结果集的下一行。 可以提取行以包含列作为名称或位置。 如果结果集中没有剩余行,则返回false
。
fetch_rows.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Cake\Database\Connection;
use Cake\Database\Driver\Mysql;
$driver = new Mysql([
'database' => 'mydb',
'username' => 'root',
'password' => 's$cret',
]);
$conn = new Connection([
'driver' => $driver,
]);
$stm = $conn->execute('SELECT * FROM countries');
while ($row = $stm->fetch('assoc')) {
echo "{$row['id']} {$row['name']} {$row['population']}\n";
}
该示例从countries
表中提取所有行。
$stm = $conn->execute('SELECT * FROM countries');
使用execute()
执行查询。
while ($row = $stm->fetch('assoc')) {
echo "{$row['id']} {$row['name']} {$row['population']}\n";
}
我们在while
循环中使用fetch()
获取所有行。
$ php fetch_rows.php
1 China 1382050000
2 India 1313210000
3 USA 324666000
4 Indonesia 260581000
5 Brazil 207221000
6 Pakistan 196626000
7 Nigeria 186988000
8 Bangladesh 162099000
9 Nigeria 186988000
10 Russia 146838000
11 Japan 126830000
This is the output.
CakePHP 插入
使用insert()
将新行添加到数据库。
insert_row.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Cake\Database\Connection;
use Cake\Database\Driver\Mysql;
$driver = new Mysql([
'database' => 'mydb',
'username' => 'root',
'password' => 's$cret',
]);
$conn = new Connection([
'driver' => $driver,
]);
$conn->insert('countries', ['name' => 'Ethiopia', 'population' => 102403196]);
该示例在countries
表中插入新行。
参数化查询
参数化查询可防止 SQL 注入攻击。 execute()
方法采用第二个参数中要绑定的值和第三个参数中的值的类型。
parametrized.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Cake\Database\Connection;
use Cake\Database\Driver\Mysql;
$driver = new Mysql([
'database' => 'mydb',
'username' => 'root',
'password' => 's$cret',
]);
$conn = new Connection([
'driver' => $driver,
]);
$stm = $conn->execute('SELECT * FROM countries WHERE id = :id',
['id' => 1], ['id' => 'integer']);
$row = $stm->fetch();
echo "$row[0] $row[1] $row[2]\n";
该示例使用参数化查询选择特定行。
$stm = $conn->execute('SELECT * FROM countries WHERE id = :id',
['id' => 1], ['id' => 'integer']);
:id
是一个占位符,与第二个参数中指定的值绑定。 要绑定的参数的类型在第三个参数中给出。
$ php parametrized.php
1 China 1382050000
This is the output.
CakePHP 查询构建器
查询构建器为创建和运行数据库查询提供了方便,流畅的接口。 它是对运行 SQL 语句的低级详细信息的抽象。 它可以使程序员避免过程的复杂性。
query_builder.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Cake\Database\Connection;
use Cake\Database\Driver\Mysql;
$driver = new Mysql([
'database' => 'mydb',
'username' => 'root',
'password' => 's$cret',
]);
$conn = new Connection([
'driver' => $driver,
]);
$query = $conn->newQuery();
$query->select(['id', 'name']);
$query->from('countries');
$query->where(['id >' => 4])->andWhere(['id <' => 10]);
$rows = $query->execute();
foreach ($rows as $row) {
echo "{$row[0]} {$row[1]}\n";
}
该示例从countries
表中检索 ID 大于 4 且小于 10 的行。
$query = $conn->newQuery();
使用newQuery()
创建查询构建器。
$query->select(['id', 'name']);
$query->from('countries');
$query->where(['id >' => 4])->andWhere(['id <' => 10]);
该查询是使用流利的方法调用构建的。
$ php query_builder.php
5 Brazil
6 Pakistan
7 Nigeria
8 Bangladesh
9 Nigeria
This is the output.
计数行
可以使用func()
方法创建许多常用功能。
count_rows.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Cake\Database\Connection;
use Cake\Database\Driver\Mysql;
$driver = new Mysql([
'database' => 'mydb',
'username' => 'root',
'password' => 's$cret',
]);
$conn = new Connection([
'driver' => $driver,
]);
$query = $conn->newQuery();
$query->select(['count' => $query->func()->count('*')]);
$query->from('countries');
$stm = $query->execute();
$n = $stm->fetch()[0];
echo "There are {$n} countries in the table\n";
该示例计算表中的行数。
$ php count_rows.php
There are 12 countries in the table
This is the output.
CakePHP 的表达方式
in()
表达式允许创建IN
SQL 子句。
in_expr.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Cake\Database\Connection;
use Cake\Database\Driver\Mysql;
$driver = new Mysql([
'database' => 'mydb',
'username' => 'root',
'password' => 's$cret',
]);
$conn = new Connection([
'driver' => $driver,
]);
$query = $conn->newQuery();
$query->select(['id', 'name', 'population']);
$query->from('countries');
$query->where(function ($exp) {
return $exp
->in('id', [2, 4, 6, 8, 10]);
});
$rows = $query->execute();
foreach ($rows as $row) {
echo "{$row[0]} {$row[1]} {$row[2]}\n";
}
该示例使用in()
表达式从给定的 ID 数组中选择行。
$ php in_expr.php
2 India 1313210000
4 Indonesia 260581000
6 Pakistan 196626000
8 Bangladesh 162099000
10 Russia 146838000
This is the output.
您可能也对以下相关教程感兴趣: PHP PDO 教程, Symfony 简介, PHP 教程或列出所有 PHP 教程。
在本教程中,我们使用了 Doctrine QueryBuilder 和 PostgreSQL 数据库。
PHP SQLite3 教程
这是针对 SQLite 版本 3 数据库的 PHP 编程教程。 它涵盖了使用 PHP 语言进行 SQLite 编程的基础。
要使用本教程,我们必须在系统上安装 PHP CLI。
为了使用 SQLite 数据库,我们可以安装sqlite3
命令行工具或 SQLite 浏览器 GUI。
$ php -v
PHP 7.2.11 (cli) (built: Oct 10 2018 02:39:52) ( ZTS MSVC15 (Visual C++ 2017) x86 )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
在本教程中,我们使用 PHP 7.2.11。
...
;extension=sockets
extension=sqlite3
;extension=tidy
...
SQLite 随 PHP 一起提供; 我们不需要安装它。 我们必须在php.ini
文件中启用 sqlite3 扩展。
SQLite
SQLite 是嵌入式关系数据库引擎。 该文档称其为自包含,无服务器,零配置和事务型 SQL 数据库引擎。 如今,它在全球使用着数亿册,非常受欢迎。 几种编程语言都内置了对 SQLite 的支持,包括 PHP 和 Python。
创建 SQLite 数据库
我们使用sqlite3
命令行工具创建一个新数据库。
$ sqlite3 test.db
SQLite version 3.27.2 2019-02-25 16:06:06
Enter ".help" for usage hints.
sqlite>
我们为sqlite3
工具提供了一个参数; test.db
是数据库名称。 这是我们磁盘上的文件。 如果存在,则将其打开。 如果不是,则创建它。
sqlite> .tables
sqlite> .exit
$ ls
test.db
.tables
命令提供test.db
数据库中的表的列表。 当前没有表格。 .exit
命令终止sqlite3
命令行工具的交互式会话。 ls
命令显示当前工作目录的内容。 我们可以看到test.db
文件。 所有数据将存储在该单个文件中。
PHP SQLite3 版本示例
在以下示例中,我们获得了 SQLite 数据库的版本。
version.php
<?php
$ver = SQLite3::version();
echo $ver['versionString'] . "\n";
echo $ver['versionNumber'] . "\n";
var_dump($ver);
SQLite3::version()
返回 SQLite 数据库的版本。
$ php version.php
3.20.1
3020001
array(2) {
["versionString"]=>
string(6) "3.20.1"
["versionNumber"]=>
int(3020001)
}
这是输出。
version2.php
<?php
$db = new SQLite3('test.db');
$version = $db->querySingle('SELECT SQLITE_VERSION()');
echo $version . "\n";
程序返回 SQLite 数据库的当前版本。 这次我们执行了SELECT SQLITE_VERSION()
语句。
$db = new SQLite3('test.db');
我们创建一个 SQLite3 对象并打开一个 SQLite3 数据库连接。
$version = $db->querySingle('SELECT SQLITE_VERSION()');
querySingle()
执行查询并返回单个结果。
$ php version2.php
3.20.1
This is the output.
PHP SQLite3 执行
exec()
对给定的数据库执行无结果查询。
create_table.php
<?php
$db = new SQLite3('test.db');
$db->exec("CREATE TABLE cars(id INTEGER PRIMARY KEY, name TEXT, price INT)");
$db->exec("INSERT INTO cars(name, price) VALUES('Audi', 52642)");
$db->exec("INSERT INTO cars(name, price) VALUES('Mercedes', 57127)");
$db->exec("INSERT INTO cars(name, price) VALUES('Skoda', 9000)");
$db->exec("INSERT INTO cars(name, price) VALUES('Volvo', 29000)");
$db->exec("INSERT INTO cars(name, price) VALUES('Bentley', 350000)");
$db->exec("INSERT INTO cars(name, price) VALUES('Citroen', 21000)");
$db->exec("INSERT INTO cars(name, price) VALUES('Hummer', 41400)");
$db->exec("INSERT INTO cars(name, price) VALUES('Volkswagen', 21600)");
该程序将创建一个cars
表,并将八行插入该表中。
$db->exec("CREATE TABLE cars(id INTEGER PRIMARY KEY, name TEXT, price INT)");
该 SQL 语句创建一个新的cars
表。 该表有三列。 请注意,在 SQLite 数据库中,INTEGER PRIMARY KEY
列是自动增加的。
$db->exec("INSERT INTO cars(name, price) VALUES('Audi', 52642)");
$db->exec("INSERT INTO cars(name, price) VALUES('Mercedes', 57127)");
这两行将两辆车插入表。
sqlite> .mode column
sqlite> .headers on
我们使用sqlite3
工具验证写入的数据。 首先,我们修改数据在控制台中的显示方式。 我们使用列模式并打开标题。
sqlite> select * from cars;
id name price
---------- ---------- ----------
1 Audi 52642
2 Mercedes 57127
3 Skoda 9000
4 Volvo 29000
5 Bentley 350000
6 Citroen 21000
7 Hummer 41400
8 Volkswagen 21600
这是我们已写入cars
表的数据。
PHP SQLite3 lastInsertRowID
有时,我们需要确定最后插入的行的 ID。 在 PHP SQLite3 中,我们使用lastInsertRowID()
方法。
last_rowid.php
<?php
$db = new SQLite3(':memory:');
$db->exec("CREATE TABLE friends(id INTEGER PRIMARY KEY, name TEXT)");
$db->exec("INSERT INTO friends(name) VALUES ('Tom')");
$db->exec("INSERT INTO friends(name) VALUES ('Rebecca')");
$db->exec("INSERT INTO friends(name) VALUES ('Jim')");
$db->exec("INSERT INTO friends(name) VALUES ('Robert')");
$last_row_id = $db->lastInsertRowID();
echo "The last inserted row Id is $last_row_id";
我们在内存中创建一个friends
表。 ID 会自动递增。
$db->exec("CREATE TABLE friends(id INTEGER PRIMARY KEY, name TEXT)");
在 SQLite3 中,INTEGER PRIMARY KEY
列自动增加。 还有一个AUTOINCREMENT
关键字。 在INTEGER PRIMARY KEY AUTOINCREMENT
中使用时,会使用稍微不同的 ID 创建算法。
$db->exec("CREATE TABLE friends(id INTEGER PRIMARY KEY, name TEXT)");
$db->exec("INSERT INTO friends(name) VALUES ('Tom')");
$db->exec("INSERT INTO friends(name) VALUES ('Rebecca')");
$db->exec("INSERT INTO friends(name) VALUES ('Jim')");
$db->exec("INSERT INTO friends(name) VALUES ('Robert')");
使用自动增量时,我们必须明确声明列名,而忽略自动增量的列名。 这四个语句在friends
表中插入四行。
$last_row_id = $db->lastInsertRowID();
使用lastInsertRowID()
获得最后插入的行 ID。
$ php last_rowid.php
The last inserted row Id is 4
我们看到了程序的输出。
PHP SQLite3 查询
query()
方法执行 SQL 查询并返回结果对象。
fetch_all.php
<?php
$db = new SQLite3('test.db');
$res = $db->query('SELECT * FROM cars');
while ($row = $res->fetchArray()) {
echo "{$row['id']} {$row['name']} {$row['price']} \n";
}
该示例从cars
表中检索所有数据。
$res = $db->query('SELECT * FROM cars');
该 SQL 语句从cars
表中选择所有数据。
while ($row = $res->fetchArray()) {
fetchall()
检索结果行作为关联数组或数字索引数组,或两者都检索(默认为两者)。 如果没有更多行,则返回false
。
$ php fetch_all.php
1 Audi 52642
2 Mercedes 57127
3 Skoda 9000
4 Volvo 29000
5 Bentley 350000
6 Citroen 21000
7 Hummer 41400
8 Volkswagen 21600
这是示例的输出。
PHP SQLite3 escapeString
escapeString()
返回已正确转义的字符串。
escape_string.php
<?php
$db = new SQLite3('test.db');
$sql = "SELECT name FROM cars WHERE name = 'Audi'";
$escaped = SQLite3::escapeString($sql);
var_dump($sql);
var_dump($escaped);
该示例对查询中的字符串进行转义。
$ php escape_string.php
string(41) "SELECT name FROM cars WHERE name = 'Audi'"
string(43) "SELECT name FROM cars WHERE name = ''Audi''"
This is the output of the example.
PHP SQLite3 参数化语句
SQL 语句通常是动态构建的。 用户提供一些输入,并且此输入已内置到语句中。 每当我们处理来自用户的输入时,我们都必须谨慎。 它具有一些严重的安全隐患。 动态构建 SQL 语句的推荐方法是使用参数绑定。
使用prepare()
创建参数化查询; 它准备要执行的 SQL 语句并返回一个语句对象。
PHP SQLite3 具有bindParam()
和bindValue()
方法来将值绑定到占位符。 它允许将数据绑定到问号或命名的占位符。
带问号的参数化语句
在第一个示例中,我们使用问号的语法。
prepared.php
<?php
$db = new SQLite3('test.db');
$stm = $db->prepare('SELECT * FROM cars WHERE id = ?');
$stm->bindValue(1, 3, SQLITE3_INTEGER);
$res = $stm->execute();
$row = $res->fetchArray(SQLITE3_NUM);
echo "{$row[0]} {$row[1]} {$row[2]}";
我们选择使用问号占位符的汽车。
$stm = $db->prepare('SELECT * FROM cars WHERE id = ?');
问号?
是值的占位符。 稍后将这些值添加(绑定)到占位符。
$stm->bindValue(1, 3, SQLITE3_INTEGER);
使用bindValue()
,将值 3 绑定到问号占位符。 第一个参数是位置参数,用于标识占位符(可以有多个问号占位符)。
$ php prepared.php
3 Skoda 9000
This is the output.
具有命名占位符的参数化语句
第二个示例使用带有命名占位符的参数化语句。
prepared2.php
<?php
$db = new SQLite3('test.db');
$stm = $db->prepare('SELECT * FROM cars WHERE id = :id');
$stm->bindValue(':id', 1, SQLITE3_INTEGER);
$res = $stm->execute();
$row = $res->fetchArray(SQLITE3_NUM);
echo "{$row[0]} {$row[1]} {$row[2]}";
我们使用命名的占位符选择特定的汽车。
$stm = $db->prepare('SELECT * FROM cars WHERE id = :id');
命名的占位符以冒号开头。
PHP SQLite3 bind_param
bind_param()
将参数绑定到语句变量。 它可以用于处理多行。
bind_param.php
≪?php
$db = new SQLite3(':memory:');
$db->exec("CREATE TABLE friends(id INTEGER PRIMARY KEY, firstname TEXT, lastname TEXT)");
$stm = $db->prepare("INSERT INTO friends(firstname, lastname) VALUES (?, ?)");
$stm->bindParam(1, $firstName);
$stm->bindParam(2, $lastName);
$firstName = 'Peter';
$lastName = 'Novak';
$stm->execute();
$firstName = 'Lucy';
$lastName = 'Brown';
$stm->execute();
$res = $db->query('SELECT * FROM friends');
while ($row = $res->fetchArray()) {
echo "{$row[0]} {$row[1]} {$row[2]}\n";
}
在示例中,我们将两行插入到带有参数化语句的表中。 要绑定占位符,我们使用bind_param()
方法。
$ php bind_param.php
1 Peter Novak
2 Lucy Brown
This is the output.
PHP SQLite3 元数据
元数据是有关数据库中数据的信息。 SQLite 中的元数据包含有关表和列的信息,我们在其中存储数据。 受 SQL 语句影响的行数是元数据。 结果集中返回的行数和列数也属于元数据。
可以使用特定的 PHP SQLite3 方法,PRAGMA
命令或通过查询 SQLite 系统sqlite_master
表来获取 SQLite 中的元数据。
num_of_columns.php
<?php
$db = new SQLite3('test.db');
$res = $db->query("SELECT * FROM cars WHERE id = 1");
$cols = $res->numColumns();
echo "There are {$cols} columns in the result set\n";
numColumns()
返回结果集中的列数。
$ php num_of_columns.php
There are 3 columns in the result set
This is the output.
column_names.php
<?php
$db = new SQLite3('test.db');
$res = $db->query("PRAGMA table_info(cars)");
while ($row = $res->fetchArray(SQLITE3_NUM)) {
echo "{$row[0]} {$row[1]} {$row[2]}\n";
}
在此示例中,我们发出PRAGMA table_info(tableName)
命令以获取有关cars
表的一些元数据信息。
$res = $db->query("PRAGMA table_info(cars)");
PRAGMA table_info(tableName)
命令为cars
表中的每一列返回一行。 结果集中的列包括列顺序号,列名称,数据类型,该列是否可以为NULL
以及该列的默认值。
while ($row = $res->fetchArray(SQLITE3_NUM)) {
echo "{$row[0]} {$row[1]} {$row[2]}\n";
}
根据提供的信息,我们打印列顺序号,列名称和列数据类型。
$ php column_names.php
0 id INTEGER
1 name TEXT
2 price INT
This is the output of the example.
在下面的示例中,我们打印cars
表中的所有行及其列名。
column_names2.php
<?php
$db = new SQLite3('test.db');
$res = $db->query("SELECT * FROM cars");
$col1 = $res->columnName(1);
$col2 = $res->columnName(2);
$header = sprintf("%-10s %s\n", $col1, $col2);
echo $header;
while ($row = $res->fetchArray()) {
$line = sprintf("%-10s %s\n", $row[1], $row[2]);
echo $line;
}
我们还将cars
表的内容与列名一起打印到控制台。 记录与列名对齐。
$col1 = $res->columnName(1);
columnName()
返回第 n 列的名称。
$header = sprintf("%-10s %s\n", $col1, $col2);
echo $header;
这些行打印cars
表的两个列名。
while ($row = $res->fetchArray()) {
$line = sprintf("%-10s %s\n", $row[1], $row[2]);
echo $line;
}
我们使用while
循环打印行。 数据与列名对齐。
$ php column_names2.php
name price
Audi 52642
Mercedes 57127
Skoda 9000
Volvo 29000
Bentley 350000
Citroen 21000
Hummer 41400
Volkswagen 21600
This is the output.
在下一个示例中,我们列出test.db
数据库中的所有表。
list_tables.php
<?php
$db = new SQLite3('test.db');
$res = $db->query("SELECT name FROM sqlite_master WHERE type='table'");
while ($row = $res->fetchArray(SQLITE3_NUM)) {
echo "{$row[0]}\n";
}
该代码示例将指定数据库中的所有可用表打印到终端。
$res = $db->query("SELECT name FROM sqlite_master WHERE type='table'");
表名存储在系统sqlite_master
表中。
$ php list_tables.php
cars
images
这些是我们系统上的表。
changes()
返回由最新 SQL 语句修改,插入或删除的数据库行数。
changes.php
<?php
$db = new SQLite3(':memory:');
$db->exec("CREATE TABLE friends(id INTEGER PRIMARY KEY, name TEXT)");
$db->exec("INSERT INTO friends(name) VALUES ('Tom')");
$db->exec("INSERT INTO friends(name) VALUES ('Rebecca')");
$db->exec("INSERT INTO friends(name) VALUES ('Jim')");
$db->exec("INSERT INTO friends(name) VALUES ('Robert')");
$db->exec('DELETE FROM friends');
$changes = $db->changes();
echo "The DELETE statement removed $changes rows";
该示例返回已删除的行数。
$ php changes.php
The DELETE statement removed 4 rows
This is the output.
PHP SQLite3 PDO 示例
PHP 数据对象(PDO)定义了用于访问 PHP 中的数据库的轻量级接口。 它提供了一个数据访问抽象层,用于在 PHP 中使用数据库。 它定义了用于各种数据库系统的一致 API。
PHP PDO 是一个内置库; 我们不需要安装它。
list_tables.php
<?php
$pdo = new PDO('sqlite:test.db');
$stm = $pdo->query("SELECT * FROM cars");
$rows = $stm->fetchAll(PDO::FETCH_NUM);
foreach($rows as $row) {
printf("$row[0] $row[1] $row[2]\n");
}
该示例使用 PHP PDO 获取所有表行。
Dibi 的例子
PHP Dibi 是用于 PHP 的小型智能数据库层。
$ composer req dibi/dibi
我们安装库。
fetch_cars.php
<?php
require('vendor/autoload.php');
$db = dibi::connect([
'driver' => 'sqlite',
'database' => 'test.db',
]);
$rows = $db->query('SELECT * FROM cars');
foreach ($rows as $row) {
$id = $row->id;
$name = $row->name;
$price = $row->price;
echo "$id $name $price \n";
}
该示例从cars
表中提取所有行。
Doctrine DBAL 示例
Doctrine 是一组 PHP 库,主要致力于在 PHP 中提供持久性服务。 它的主要项目是对象关系映射器(ORM)和数据库抽象层(DBAL)。
$ composer req doctrine/dbal
我们安装 Doctrine DBAL 包。
fetch_cars.php
<?php
require_once "vendor/autoload.php";
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\FetchMode;
$attrs = ['driver' => 'pdo_sqlite', 'path' => 'test.db'];
$conn = DriverManager::getConnection($attrs);
$queryBuilder = $conn->createQueryBuilder();
$queryBuilder->select('*')->from('cars');
$stm = $queryBuilder->execute();
$rows = $stm->fetchAll(FetchMode::NUMERIC);
foreach ($rows as $row) {
echo "{$row[0]} {$row[1]} {$row[2]}\n";
}
该示例使用 Doctrine DBAL QueryBuilder
从cars
表中检索所有行。
这是 PHP SQLite3 教程。 您可能也对以下相关教程感兴趣: Doctrine QueryBuilder
教程, PHP PDO 教程和 PHP 教程,或列出所有 PHP 教程。
PHP 文件系统函数
在本文中,我们介绍了 PHP 中的文件系统函数。 我们处理文件和目录,确定文件许可权和可用磁盘空间,以及读写文件。 对于我们的示例,我们使用 PHP CLI。 PHP 教程是有关 ZetCode 的 PHP 语言的简要教程。
PHP 具有用于处理文件和目录的丰富函数集。 PHP 包含低级和高级文件系统函数。 fopen()
函数是一个低级函数的示例; 它是类似 C 函数的薄包装。 file()
函数是高级 PHP 文件系统函数的示例。
文件大小和类型
filesize()
函数返回给定文件的大小。 大小以字节为单位指定。
get_filesize.php
<?php
$filename = "fruits.txt";
$fsize = filesize($filename);
echo "The file size is: $fsize bytes\n";
?>
在示例中,我们确定fruits.txt
文件的大小。 该文件位于当前工作目录中,即与 PHP 脚本位于同一目录中。
$ php get_filesize.php
The file size is: 40 bytes
fruits.txt
文件的大小为 40 个字节。
filetype()
函数获取文件的类型。 可能的返回值是:fifo
,char
,dir
,block
,link
,file
,socket
和unknown
。
file_types.php
<?php
echo filetype("myfile") . PHP_EOL;
echo filetype(".") . PHP_EOL;
echo filetype("/dev/tty1") . PHP_EOL;
echo filetype("/var/run/cups/cups.sock") . PHP_EOL;
?>
该脚本确定四个文件的类型。
$ php file_types.php
file
dir
char
socket
这四个文件是常规文件,目录,字符设备和套接字。
文件存在
我们可能想使用一个不存在的文件,这可能发生。 file_exists()
函数可用于防止这种情况。
file_existence.php
<?php
if ($argc != 2) {
exit("Usage: file_existence.php filename\n");
}
$filename = $argv[1];
$r = file_exists($filename);
if (!$r) {
exit("Cannot determine the size of the file; the file does not exist\n");
}
$fsize = filesize($filename);
echo "The file size is: $fsize bytes\n";
?>
该脚本在计算给定文件的大小之前会检查其是否存在。
if ($argc != 2) {
exit("Usage: file_existence.php filename\n");
}
$argc
是一个特殊变量,其中包含传递给脚本的参数数量。 我们需要两个参数:一个脚本名称和另一个作为参数传递的文件名。
$filename = $argv[1];
$argv
是传递给脚本的参数数组。 我们得到第二个要素。
$r = file_exists($filename);
if (!$r) {
exit("Cannot determine the size of the file; the file does not exist\n");
}
我们使用file_exists()
函数检查文件是否存在。 如果它不存在,我们将以一条消息终止脚本。
$ php file_existence.php fruits.txt
The file size is: 40 bytes
这是file_existence.php
脚本的示例输出。
在下面的示例中,我们创建一个新文件,将其删除,然后检查其是否存在。 touch()
函数设置文件的访问和修改时间。 如果该文件不存在,则会创建它。 unlink()
函数删除文件。
file_existence2.php
<?php
$filename = "newfile.txt";
if (file_exists($filename)) {
echo "The file $filename exists\n";
} else {
echo "The file $filename does not exist\n";
$r = touch($filename);
if (!$r) {
exit("Failed to touch $filename file\n");
} else {
echo "The file $filename has been created\n";
}
}
$r = unlink($filename);
if ($r) {
echo "The file $filename was deleted\n";
} else {
exit("Failed to delete $filename file\n");
}
if (file_exists($filename)) {
echo "The file $filename exists\n";
} else {
echo "The file $filename does not exist\n";
}
?>
在代码示例中,我们利用了所有三个函数:file_exists()
,touch()
和unlink()
。
$r = touch($filename);
touch()
函数用于创建一个名为newfile.txt
的新文件。
if (!$r) {
exit("Failed to touch $filename file\n");
} else {
echo "The file $filename has been created\n";
}
如果touch()
函数失败,则会打印一条错误消息。 许多 PHP 函数在失败时会返回false
值。
$r = unlink($filename);
unlink()
函数删除文件。
$ php file_existence2.php
The file newfile.txt does not exist
The file newfile.txt has been created
The file newfile.txt was deleted
The file newfile.txt does not exist
这是file_existence2.php
的输出。
复制和重命名文件
copy()
函数复制文件,rename()
重命名文件。 如果目标文件已经存在,它将被覆盖。
copy_file.php
<?php
$r = copy("myfile.txt", "myfile2.txt");
if ($r) {
echo "Successfully copied file\n";
} else {
exit("Failed to copy file\n");
}
?>
该脚本将复制文件。
rename_file.php
<?php
$r = rename("myfile2.txt", "myfile_back.txt");
if ($r) {
echo "Successfully renamed file\n";
} else {
exit("Failed to rename file\n");
}
?>
在此脚本中,我们使用rename()
函数将myfile2
文件重命名为myfile_back
。
E_WARNING
一些文件系统函数在失败时发出E_WARNING
。 这是运行时警告(非致命错误)。 脚本的执行不会停止。
PHP 在这方面不一致。 并非所有文件系统函数都发出此警告-大多数函数仅在失败时才返回错误值。
custom_error_handler.php
<?php
set_error_handler("mywarning_handler", E_WARNING);
$r = unlink('image1.png');
if ($r) {
echo "File successfully deleted\n";
}
function mywarning_handler($errno, $errstr) {
echo "Failed to delete file\n";
echo "$errstr: $errno\n";
}
?>
在脚本中,我们删除文件并提供自定义错误处理器。
set_error_handler("mywarning_handler", E_WARNING);
使用set_error_handler()
函数设置自定义错误处理器。
function mywarning_handler($errno, $errstr) {
echo "Failed to delete file\n";
echo "$errstr: $errno\n";
}
处理器将收到错误号和错误字符串作为参数。
$ php custom_error_handler.php
Failed to delete file
unlink(image1.png): No such file or directory: 2
当没有image1.png
要删除时,custom_error_handler.php
提供此输出。
目录
dirname()
函数返回父目录的路径。 从 PHP 7 开始,我们可以提供一个可选的levels
参数,该参数指示要上升的父目录的数量。
parent_directories.php
<?php
$home_dir = getenv("HOME");
echo dirname($home_dir). PHP_EOL;
echo dirname("/etc/") . PHP_EOL;
echo dirname(".") . PHP_EOL;
echo dirname("/usr/local/lib", 2) . PHP_EOL;
?>
在脚本中,我们打印四个目录的父目录。
$home_dir = getenv("HOME");
我们使用getenv()
函数来获取当前用户的主目录。
echo dirname($home_dir). PHP_EOL;
此行显示用户主目录的父目录。
echo dirname(".") . PHP_EOL;
在这里,我们打印当前工作目录的父目录。
echo dirname("/usr/local/lib", 2) . PHP_EOL;
在这一行中,我们打印/usr/local/lib
目录的第二个父目录。
$ php parent_directories.php
/home
/
.
/usr
这是parent_directories.php
的输出。
getcwd()
函数返回当前工作目录,chdir()
函数将当前工作目录更改为新目录。
current_directory.php
<?php
$cd = getcwd();
echo "Current directory:" . $cd . PHP_EOL;
chdir("..");
$cd2 = getcwd();
echo "Current directory:" . $cd2 . PHP_EOL;
?>
该脚本可与getcmd()
和chdir()
函数一起使用。
$ php current_directory.php
Current directory:/home/janbodnar/prog/phpfiles
Current directory:/home/janbodnar/prog
这是脚本的示例输出。
列出目录
在以下五个示例中,我们列出了目录的内容。 有几种方法可以完成此任务。
list_dir1.php
<?php
$folder = '/home/janbodnar/prog';
$fh = opendir($folder);
if ($fh === false) {
exit("Cannot open directory\n");
}
while (false !== ($entry = readdir($fh))) {
echo "$entry\n";
}
closedir($fh);
?>
opendir()
函数打开目录句柄。 readdir()
函数从目录句柄读取条目。 在脚本末尾使用closedir()
函数关闭目录的句柄。
is_dir()
函数判断文件名是否为目录,is_file()
函数判断文件名是否为文件。
list_dir2.php
<?php
$folder = '/home/janbodnar/prog/';
$fh = opendir($folder);
if ($fh === false) {
exit("Cannot open directory\n");
}
$dirs = [];
$files = [];
while (false !== ($entry = readdir($fh))) {
if (is_dir($folder . '/' . $entry)) {
array_push($dirs, $entry);
}
if (is_file($folder . '/' . $entry)) {
array_push($files, $entry);
}
}
echo "Directories:\n";
foreach ($dirs as $dr) {
echo "$dr\n";
}
echo "Files:\n";
foreach ($files as $myfile) {
echo "$myfile\n";
}
closedir($fh);
?>
在第二个示例中,我们将条目分为子目录和文件。 该脚本首先打印子目录,然后打印所检查目录的文件。
if (is_dir($folder . '/' . $entry)) {
array_push($dirs, $entry);
}
必须提供is_dir()
函数的目录的完整路径。
glob()
函数查找与模式匹配的路径名。
list_dir3.php
<?php
foreach (glob('/home/janbodnar/*', GLOB_ONLYDIR) as $dir) {
echo "$dir\n";
}
?>
使用GLOB_ONLYDIR
标志,glob()
函数仅返回与模式匹配的目录条目。
scandir()
是高级函数,用于列出指定路径内的文件和目录。 该函数从目录返回文件和目录的数组。
list_dir4.php
<?php
$files = scandir('.', SCANDIR_SORT_DESCENDING);
print_r($files);
?>
该脚本打印当前工作目录的文件和子目录的数组。 SCANDIR_SORT_DESCENDING
标志以字母降序对条目进行排序。
在前面的示例中,我们仅列出了一个目录的内容; 我们没有包括子目录的元素。 使用RecursiveDirectoryIterator
和RecursiveIteratorIterator
类,我们可以轻松地使用递归遍历文件系统目录。 换句话说,我们遍历所有子目录,直到列出目录树中的所有项目。
list_dir5.php
<?php
$folder = '/home/janbodnar/prog/';
$rdi = new RecursiveDirectoryIterator($folder);
$rii = new RecursiveIteratorIterator($rdi);
foreach ($rii as $filename) {
echo "$filename\n";
}
?>
该脚本将打印所有深度级别的给定目录的所有项目。
路径
路径是计算机文件的完整指定名称,包括文件在文件系统目录结构中的位置。 realpath()
函数返回规范的绝对路径名,basename()
函数返回路径的尾随名称部分。
paths.php
<?php
echo realpath("myfile.txt") . PHP_EOL;
echo basename("/home/janbodnar/prog/phpfiles/myfile.txt") . PHP_EOL;
echo basename("/home/janbodnar/prog/phpfiles/myfile.txt", ".txt") . PHP_EOL;
?>
该脚本使用realpath()
和basename()
函数。
echo basename("/home/janbodnar/prog/phpfiles/myfile.txt", ".txt") . PHP_EOL;
如果我们指定第二个参数,即后缀名,则它也会从路径名中删除。
$ php paths.php
/home/janbodnar/prog/phpfiles/myfile.txt
myfile.txt
myfile
这是paths.php
示例的输出。
pathinfo()
函数返回有关文件路径的信息。
path_info.php
<?php
$path_parts = pathinfo('myfile.txt');
echo $path_parts['dirname'] . PHP_EOL;
echo $path_parts['basename'] . PHP_EOL;
echo $path_parts['extension'] . PHP_EOL;
echo $path_parts['filename'] . PHP_EOL;
?>
该函数返回一个包含以下元素的关联数组:目录名称,基础名称,扩展名(如果有)和文件名。
$ php path_info.php
.
myfile.txt
txt
myfile
这是输出。
创建文件
fopen()
函数打开文件或 URL。 函数的第一个参数是文件名,第二个是打开窗口的模式。 例如,'r'
模式打开仅用于读取,'w'
模式仅用于写入。 如果我们以'w'
模式打开文件,但该文件不存在,则会创建该文件。 可以在 PHP 手册中的fopen()
中找到模式列表。
fopen()
返回文件的句柄。 这是一个用于操作文件的对象。 例如,我们将其传递给fwrite()
函数以写入文件。
create_file.php
<?php
$filename = "names.txt";
if (file_exists($filename)) {
exit("The file already exists\n");
}
$fh = fopen($filename, 'w');
if ($fh === false) {
exit("Cannot create file\n");
}
echo "Successfully created file\n";
fclose($fh);
?>
该示例创建一个名为names.txt
的新文件。
if (file_exists($filename)) {
exit("The file already exists\n");
}
首先,我们检查文件是否存在。
$fh = fopen('names.txt', 'w');
创建names.txt
文件,并返回该文件的句柄。
fclose($fh);
我们使用fclose()
函数关闭文件句柄。
读取文件
在下一个示例中,我们将读取文件内容。
fread()
从句柄引用的文件指针中读取最多length
个字节。 读取length
字节或到达 EOF(文件末尾)后,读取停止。
read_file.php
<?php
$fh = fopen('balzac.txt', 'r');
if ($fh === false) {
exit("Cannot open file for reading\n");
}
while (!feof($fh)) {
$chunk = fread($fh, 1024);
if ($chunk === false) {
exit("Cannot read from file\n");
}
echo $chunk;
}
fclose($fh);
?>
该示例使用fread()
函数读取整个文件,并将其输出到控制台。
while (!feof($fh)) {
$chunk = fread($fh, 1024);
if ($chunk === false) {
exit("Cannot read from file\n");
}
echo $chunk;
}
feof()
测试文件指针上的文件结尾。 fread()
每 1 KB 的块读取文件,直到达到 EOF。
$ php read_file.php balzac.txt
Honoré de Balzac, (born Honoré Balzac, 20 May 1799 – 18 August 1850)
was a French novelist and playwright. His magnum opus was a sequence
of short stories and novels collectively entitled La Comédie Humaine,
which presents a panorama of French life in the years after the 1815
Fall of Napoleon Bonaparte.
这是read_file.php
示例的输出。
在第二个示例中,我们利用fgets()
函数从文件句柄读取一行。
read_file2.php
<?php
$fh = fopen('balzac.txt', 'r');
if ($fh === false) {
exit("Cannot open file for reading\n");
}
while (!feof($fh)) {
$line = fgets($fh);
if ($line === false) {
exit("Cannot read from file\n");
}
echo $line;
}
fclose($fh);
?>
该示例逐行读取balzac.txt
文件的内容。
file()
是将整个文件读入数组的高级函数。
read_file3.php
<?php
$lines = file('balzac.txt');
if ($lines === false) {
exit("Cannot read file\n");
}
foreach ($lines as $line) {
echo $line;
}
?>
在此示例中,我们使用file()
函数一次读取了整个文件。 我们使用foreach
循环遍历返回的数组。
file_get_contents()
是另一个高级函数,它将整个文件读取为字符串。
read_file4.php
<?php
$content = file_get_contents('balzac.txt');
if ($content === false) {
exit("Cannot read file\n");
}
echo "$content";
?>
该示例使用file_get_contents()
函数一次读取了整个文件。 它以字符串形式返回数据。
读取格式化的数据
fscanf()
函数根据格式分析文件的输入。 每次对fscanf()
的调用都会从文件中读取一行。
$ cat items.txt
coins 5
pens 6
chairs 12
books 20
我们将解析items.txt
文件。
read_formatted_data.php
<?php
$fh = fopen("items.txt", "r");
if ($fh === false) {
exit("Cannot read file\n");
}
while ($data = fscanf($fh, "%s %d")) {
list($item, $quantity) = $data;
echo "$item: $quantity\n";
}
fclose($fh);
?>
fscanf()
函数使用格式说明符来读取字符串和数字。
读取网页
PHP 文件系统函数还可用于读取网页。
read_page.php
<?php
$ph = fopen("http://www.something.com", "r");
if ($ph === false) {
exit("Failed to open stream to URL\n");
}
while (!feof($ph)) {
$buf = fread($ph, 1024);
if ($buf === false) {
exit("Cannot read page\n");
}
echo $buf;
}
fclose($ph);
?>
我们从一个名为www.something.com
的小型网站上阅读了一个页面。
$ph = fopen("http://www.something.com", "r");
使用fopen()
函数,我们打开网页的句柄。
while (!feof($ph)) {
$buf = fread($ph, 1024);
if ($buf === false) {
exit("Cannot read page\n");
}
echo $buf;
}
我们阅读网页直至结束。 feof()
用于测试网页的结尾。 使用fread()
函数以 1KB 的块读取页面。
$ php read_page.php
<html><head><title>Something.</title></head>
<body>Something.</body>
</html>
这是read_page.php
脚本的输出。
以下示例使用高级函数来读取同一网页。
read_page2.php
<?php
$page = file_get_contents('http://www.something.com');
if ($page === false) {
exit("Cannot read page\n");
}
echo $page;
?>
file_get_contents()
一次读取整个网页。
fgetss()
函数从文件句柄读取一行并剥离 HTML 标签。
read_page3.php
<?php
$ph = fopen("http://www.something.com", "r");
if ($ph === false) {
exit("Failed to open stream to URL\n");
}
while (!feof($ph)) {
$buf = fgetss($ph, 1024);
if ($buf === false) {
exit("Cannot read from page\n");
}
echo $buf;
}
fclose($ph);
?>
我们阅读www.something.com
网页的内容并剥离其 HTML 标签。
$ php read_page3.php
Something.
Something.
这是示例的输出; 输出包含页面正文中的标题和文本。
写入文件
fwrite()
函数将字符串写入文件句柄引用的文件。
write_file.php
<?php
$fh = fopen('names.txt', 'w');
if ($fh === false) {
exit("Cannot open file\n");
}
$r = fwrite($fh, 'Jane' . PHP_EOL);
check_retval($r);
$r = fwrite($fh, 'Lucy' . PHP_EOL);
check_retval($r);
$r = fwrite($fh, 'Mark' . PHP_EOL);
check_retval($r);
$r = fwrite($fh, 'Lubos' . PHP_EOL);
check_retval($r);
fclose($fh);
function check_retval($val) {
if ($val === false) {
exit("Cannot write to file\n");
}
}
?>
我们在写入模式下打开names.txt
并向其中写入四行。
$fh = fopen('names.txt', 'w');
fopen()
函数以写入模式打开文件。 如果文件不存在,则会自动创建。
$r = fwrite($fh, 'Jane' . PHP_EOL);
使用fwrite()
函数,我们在文件中写入一行。 该函数将文件句柄作为其第一个参数。
$ php write_file.php
$ cat names.txt
Jane
Lucy
Mark
Lubos
我们写入names.txt
文件并检查其内容。
我们可以使用高级file_put_contents()
方法将字符串一次性写入文件。
write_file2.php
<?php
$filename = "names.txt";
$buf = file_get_contents($filename);
if ($buf === false) {
exit("Cannot get file contents\n");
}
$buf .= "John\nPaul\nRobert\n";
$r = file_put_contents($filename, $buf);
if ($r === false) {
exit("Cannot write to file\n");
}
?>
在示例中,我们使用file_get_contents()
函数读取names.txt
文件的内容,并使用file_put_contents()
函数附加新字符串。
可读,可写,可执行文件
is_readable()
,is_writable()
和is_executable()
函数检查文件是否可读,可写和可执行。
rwe.php
<?php
$filename = "myfile.txt";
echo get_current_user() . PHP_EOL;
if (is_readable($filename)) {
echo "The file can be read\n";
} else {
echo "Cannot read file\n";
}
if (is_writable($filename)) {
echo "The file can be written to\n";
} else {
echo "Cannot write to file\n";
}
if (is_executable($filename)) {
echo "The file can be executed\n";
} else {
echo "Cannot execute file\n";
}
?>
我们在myfile.txt
文件上运行三个函数。 该脚本检查当前用户的这些属性。
$ php rwe.php
janbodnar
The file can be read
The file can be written to
Cannot execute file
janbodnar
用户可以读写该文件,但不能执行。
文件时间
Linux 上有三种文件时间:上次访问时间,上次更改时间和上次修改时间。 以下 PHP 函数确定这些时间:fileatime()
,filectime()
和filemtime()
。
file_times..php
<?php
$filename = "myfile.txt";
$atime = fileatime($filename);
$ctime = filectime($filename);
$mtime = filemtime($filename);
echo date("F d, Y H:i:s\n", $atime);
echo date("F d, Y H:i:s\n", $ctime);
echo date("F d, Y H:i:s\n", $mtime);
?>
该脚本打印myfile.txt
文件的文件时间。
$ php file_times.php
April 20, 2016 17:52:54
April 20, 2016 17:53:33
April 20, 2016 17:52:29
这是file_times.php
脚本的示例输出。
文件权限
文件系统对不同的用户和用户组强制执行文件权限。 fileperms()
函数获得文件许可; 它以数字方式返回文件的权限。
file_permissions.php
<?php
$perms = fileperms("myfile.txt");
echo decoct($perms & 0777) . PHP_EOL;
$info .= (($perms & 0x0100) ? 'r' : '-');
$info .= (($perms & 0x0080) ? 'w' : '-');
$info .= (($perms & 0x0040) ?
(($perms & 0x0800) ? 's' : 'x' ) :
(($perms & 0x0800) ? 'S' : '-'));
$info .= (($perms & 0x0020) ? 'r' : '-');
$info .= (($perms & 0x0010) ? 'w' : '-');
$info .= (($perms & 0x0008) ?
(($perms & 0x0400) ? 's' : 'x' ) :
(($perms & 0x0400) ? 'S' : '-'));
$info .= (($perms & 0x0004) ? 'r' : '-');
$info .= (($perms & 0x0002) ? 'w' : '-');
$info .= (($perms & 0x0001) ?
(($perms & 0x0200) ? 't' : 'x' ) :
(($perms & 0x0200) ? 'T' : '-'));
echo "$info\n";
?>
该脚本确定myfile.txt
的文件许可权。 权限以 Unix 样式打印到控制台。
echo decoct($perms & 0777) . PHP_EOL;
Unix 上的权限传统上以八进制表示形式编写。 decoct()
函数将十进制表示形式转换为八进制形式。
$info .= (($perms & 0x0100) ? 'r' : '-');
在这一行中,我们检查文件权限是否允许文件所有者读取它。
$ php file_permissions.php
660
rw-rw----
这是file_permissions.php
脚本的示例输出。
可以使用chmod()
函数更改文件权限。
.php
<?php
$perms1 = fileperms("myfile.txt");
echo decoct($perms1 & 0777) . PHP_EOL;
$r = chmod("myfile", 0660);
if ($r) {
echo "File mode successfully changed\n";
} else {
exit("Failed to change file mode\n");
}
$perms2 = fileperms("myfile");
echo decoct($perms2 & 0777) . PHP_EOL;
?>
该脚本更改myfile.txt
文件的权限。
$r = chmod("myfile", 0660);
chmod
函数在其第二个参数中接受权限作为八进制值。 八进制值以 0 开头。
$ php file_permissions2.php
664
File mode successfully changed
660
文件的权限从 664 更改为 660。
CSV 文件格式
fgetcsv()
函数从 CSV(逗号分隔值)文件中读取一行; 它返回一个包含读取字段的索引数组。 fputcsv()
函数将一行格式设置为 CSV 并将其写入文件。
csv_output.php
<?php
$nums = [1, 2, 5, 3, 2, 6, 4, 2, 4,
8, 7, 3, 8, 5, 4, 3];
$fh = fopen('numbers.csv', 'w');
if ($fh === false) {
exit("Failed to open file\n");
}
$r = fputcsv($fh, $nums);
if ($r === false) {
exit("Failed to write values\n");
}
echo "The values have been successfully written\n";
fclose($fh);
?>
该脚本将数组中的数字写入 CSV 文件。
$ php csv_output.php
The values have been successfully written
$ cat numbers.csv
1,2,5,3,2,6,4,2,4,8,7,3,8,5,4,3
我们运行脚本并检查文件内容。
在以下示例中,我们从 CSV 文件读取数据。
csv_input.php
<?php
$fh = fopen('numbers.csv', 'r');
if ($fh === false) {
exit("Failed to open file\n");
}
while (($data = fgetcsv($fh)) !== false) {
$num = count($data);
for ($i=0; $i < $num; $i++) {
echo "$data[$i] ";
}
}
echo "\n";
fclose($fh);
?>
该脚本使用fgetcsv()
从numbers.csv
文件中读取值,并将其打印到控制台中。
$ php csv_input.php
1 2 5 3 2 6 4 2 4 8 7 3 8 5 4 3
这是csv_input.php
脚本的输出。
磁盘空间
disk_total_space()
函数以字节为单位返回文件系统或磁盘分区的总大小,disk_total_space()
函数以字节为单位返回文件系统或磁盘分区上的可用空间。
disk_space.php
<?php
const BYTES_IN_GIGABYTE = 1073741824;
$total_space_bytes = disk_total_space("/");
if ($total_space_bytes === false) {
exit("The disk_total_space() failed\n");
}
$free_space_bytes = disk_free_space("/");
if ($free_space_bytes === false) {
exit("The disk_free_space() failed\n");
}
$total_space_gb = floor($total_space_bytes / BYTES_IN_GIGABYTE);
$free_space_gb = floor($free_space_bytes / BYTES_IN_GIGABYTE);
echo "Total space: $total_space_gb GB\n";
echo "Free space: $free_space_gb GB\n";
?>
该脚本计算根分区上的总空间和可用空间。 该空间被转换为千兆字节。
$ php disk_space.php
Total space: 289 GB
Free space: 50 GB
This is a sample output of the script.
您可能也对以下相关教程感兴趣: PHP PDO 教程, PHP 教程。
数据来源
在本文中,我们介绍了 PHP 文件系统函数。
标签:教程,php,name,示例,echo,PHP,我们,ZetCode From: https://www.cnblogs.com/apachecn/p/18500148