ZetCode-PHP-教程-一-

ZetCode PHP 教程(一)

原文:ZetCode

协议:CC BY-NC-SA 4.0

PHP 教程

原文: https://zetcode.com/lang/php/

这是 PHP 教程。 本教程涵盖了 PHP 编程语言的核心。 它使用 PHP CLI。 PHP 教程适合初学者。

目录

PHP

PHP 是一种专为 Web 开发而设计的脚本语言。 它用于产生动态网页。 当前,PHP 是使用最广泛的编程语言之一。 它的大部分语法是从 C,Java 和 Perl 借来的,它们具有几个特定于 PHP 的独特功能。 PHP 可以嵌入 HTML 代码中,并且通常在 Web 服务器上运行。

Tweet

相关教程

您可能还会对以下教程感兴趣: PHP 文件系统函数MongoDB PHP 教程PHP SQLite3 教程, [PHP 7 中的新语言功能MySQL PHP 教程PostgreSQL PHP 教程

PHP

原文: https://zetcode.com/lang/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 语法结构

原文: https://zetcode.com/lang/php/lexis/

像人类语言一样,计算机语言也具有词汇结构。 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 基础

原文: https://zetcode.com/lang/php/basics/

在 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 是一种弱类型语言。 它适用于类型,但是程序员在声明变量时不指定它们。 数据类型是多种类型的数据之一,如doubleintegerboolean。 某种数据类型的值来自特定范围的值,这些值说明该类型的可能值,对该类型可以执行的操作以及该类型的值的存储方式。 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 数据类型

原文: https://zetcode.com/lang/php/datatypes/

在 PHP 教程的这一部分中,我们将讨论数据类型。

计算机程序可以处理数据。 用于各种数据类型的工具是现代计算机语言的基本组成部分。 data type是一组值以及对这些值的允许操作。

PHP 数据类型列表

PHP 具有八种数据类型:

标量类型

  • bool
  • int
  • float
  • string

复合类型

  • array
  • object

特殊类型

  • resources
  • null

与 Java,C 或 Visual Basic 等语言不同,PHP 中没有提供变量的显式类型定义。 变量的类型在运行时由 PHP 确定。 如果我们将字符串分配给变量,它将变成字符串变量。 稍后,如果我们分配一个整数值,该变量将成为一个整数变量。

PHP 布尔值

我们的世界建立了双重性。 有天与地,水与火,阴与阳,男人与女人,爱与恨。 在 PHP 中,布尔数据类型是具有以下两个值之一的原始数据类型:TrueFalse。 这是基本的数据类型。

快乐的父母正在等待孩子的出生。 他们为两种可能性都选择了名称。 如果要成为男孩,他们选择了约翰。 如果要成为女孩,他们会选择维多利亚。

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命令适用于布尔值。 如果变量$maleTrue,则将"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

该脚本运行了几次。

以下脚本显示了一些视为TrueFalse的常见值。 例如,空字符串,空数组,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/elsewhile关键字时。

$ 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 字符串

原文: https://zetcode.com/lang/php/strings/

在 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 运算符

原文: https://zetcode.com/lang/php/operators/

在 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 中,我们有andor和否定!布尔运算符。 使用布尔运算符,我们可以执行逻辑运算。 这些常与ifwhile关键字一起使用。

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 FalseFalse 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";

在内部,ab字符是数字。 因此,当我们比较两个字符时,我们将比较它们的存储数字。 内置的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 运算符组合FalseTrue,最后得到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 中的控制流

原文: https://zetcode.com/lang/php/flowcontrol/

在 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 > 0true,因此将执行下一条语句。 如果只有一条语句要执行,则花括号是可选的。

$ 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语句是选择控制流语句。 它允许变量或表达式的值通过多路分支控制程序执行的流程。 与使用ifelseif语句相比,它以更简单的方式创建多个分支。

switch语句与其他两个关键字一起使用:casebreakcase关键字用于根据圆括号中的值测试标签。 如果标签等于该值,则执行案例后面的语句。 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 breakcontinue语句

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 数组

原文: https://zetcode.com/lang/php/arrays/

在 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 数组函数

原文: https://zetcode.com/lang/php/arrayfunctions/

在上一章中,我们讨论了数组的初始化和细读。 在本章中,我们将介绍各种 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 中的函数

原文: https://zetcode.com/lang/php/functions/

在 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 正则表达式

原文: https://zetcode.com/lang/php/regex/

在 PHP 教程的这一部分中,我们介绍了 PHP 中的正则表达式。

正则表达式用于文本搜索和更高级的文本操作。 正则表达式是内置工具,如grepsed,文本编辑器(如 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'字符。 该类代表从az的所有字符。 成功返回 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模式适合单词mothermotherboardmotherland。 说,我们只想查找完全匹配的单词。 我们将使用前面提到的锚点^$字符。

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

现在该模式匹配三个单词:SevenevenLeven

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 次。 这里的$字符用于字符串的精确末尾匹配。 没有它,诸如bookstorebookmania之类的词也将匹配。

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 = [ "luke@gmail.com", "andy@yahoocom", "34234sdfa#2345", 
    "f344@gmail.com"];

# 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 
luke@gmail.com matches 
andy@yahoocom does not match
34234sdfa#2345 does not match
f344@gmail.com 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 中的面向对象编程

原文: https://zetcode.com/lang/php/oopi/

在 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 具有三个访问修饰符:publicprotectedprivate。 可以从任何地方访问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(),其参数不同。 一个引用一个浮点矩形对象,另一个引用一个整数矩形对象,最后一个引用四个参数,xywidthheight。 如果开发 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";
    }
}

在上面的脚本中,我们有三个类:CatDogBird。 我们遍历数组并为每个数组值打印类。

$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方法

当我们在对象实例中使用printecho关键字时,将调用__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;

我们在它们上使用printecho关键字。

$ 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(); 

我们实例化了BaseDerived类。

$ 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();

我们在这里使用了几个新概念。 在代码示例中,我们有三个类:BeingAnimalCatAnimal类继承自Being类。 Cat类继承自Animal类。 类继承未声明为私有的方法和数据成员。

abstract class Being {

Being类声明为abstractabstract关键字禁止类的实例化。 创建类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,它是按钮小部件的抽象基类,提供按钮所共有的功能。 按钮Q3ButtonQCheckBoxQPushButtonQRadioButtonQToolButton都从此基本抽象类继承。

正式地说,抽象类用于强制执行协议。 协议是所有实现对象都必须支持的一组操作。

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 {

CircleDrawing类的子类。 它必须实现抽象区域方法。

$ 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 类可以实现多个接口。 使用接口的多重继承与继承方法和变量无关。 它是关于继承想法或合同的,这些想法或合同由接口描述。

接口和抽象类之间有一个重要的区别。 抽象类为继承层次结构中相关的类提供部分实现。 另一方面,可以通过彼此不相关的类来实现接口。 例如,我们有两个按钮:经典按钮和圆形按钮。 两者都继承自抽象按钮类,该类为所有按钮提供了一些通用功能。 实现类是相关的,因为它们都是按钮。 另一个示例可能具有类DatabaseSignIn。 它们彼此无关。 我们可以应用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类。 此类演变为两个后代类别:RectangleSquare。 两者都提供了自己的area()方法实现。 多态为 OOP 系统带来了灵活性和可伸缩性。

这是 PHP 中 OOP 描述的第一部分。

PHP 中的面向对象编程 II

原文: https://zetcode.com/lang/php/oopii/

在 PHP 教程的这一章中,我们将继续描述 PHP 中的 OOP。

PHP static关键字

我们可以将类属性和方法声明为staticstatic属性和方法不属于该类的实例。 他们属于阶级本身。 可通过范围解析运算符::访问它们。

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 脚本中,我们定义了两个自定义对象:ObjectColorObject对象将具有对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。大小不同:smallbig。 但是,这两个实例的颜色对象的红色部分相同: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 教程

原文: https://zetcode.com/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 教程

原文: https://zetcode.com/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(['approot@example.com' => 'App root']);
$message->setTo(['support@example.com' => '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(['approot@example.com' => 'App root']);
$message->setTo(['support@example.com' => '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 配置教程

原文: https://zetcode.com/php/config/

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'
            ]
        ];
    }
}

该配置在AbstractConfiggetDefaults()文件中指定。

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 教程

原文: https://zetcode.com/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
johns.ryleigh@rowe.com
merle96@example.com
nyasia.bergnaum@hotmail.com
morar.dylan@champlin.com
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 教程

原文: https://zetcode.com/php/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 进行了emptynull测试。

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>

基本布局定义了两个由子代替换的块:titlebody

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 教程

原文: https://zetcode.com/php/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 包含一组预定义规则,例如requiredemailminmaxurl

规则可以与|字符结合使用。

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'
];

我们有四个验证规则。 需要nameemailname必须为字母数字值,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()方法添加了两个验证规则。

验证日期

日期有四个验证规则:datedateFormatdateBeforedateAfter

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教程

原文: https://zetcode.com/doctrine/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

我们安装makerserver组件。

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:s$cret@127.0.0.1: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 验证教程

原文: https://zetcode.com/php/respectvalidation/

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";
}

在示例中,我们有两个规则:alnumlength

$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 验证教程

原文: https://zetcode.com/php/rakitvalidation/

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 验证包含一组预定义规则,例如requiredemailminmaxurl

规则可以与|字符结合使用。

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 教程

原文: https://zetcode.com/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 数据库教程

原文: https://zetcode.com/php/cakephpdatabase/

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 教程

原文: https://zetcode.com/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 QueryBuildercars表中检索所有行。

这是 PHP SQLite3 教程。 您可能也对以下相关教程感兴趣: Doctrine QueryBuilder教程PHP PDO 教程PHP 教程,或列出所有 PHP 教程

PHP 文件系统函数

原文: https://zetcode.com/articles/phpfilesystemfunctions/

在本文中,我们介绍了 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()函数获取文件的类型。 可能的返回值是:fifochardirblocklinkfilesocketunknown

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标志以字母降序对条目进行排序。

在前面的示例中,我们仅列出了一个目录的内容; 我们没有包括子目录的元素。 使用RecursiveDirectoryIteratorRecursiveIteratorIterator类,我们可以轻松地使用递归遍历文件系统目录。 换句话说,我们遍历所有子目录,直到列出目录树中的所有项目。

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 文件系统函数。

posted @ 2024-10-24 18:16  绝不原创的飞龙  阅读(21)  评论(0编辑  收藏  举报