PHP-MySQL-入门教程-二-

42 阅读35分钟

PHP MySQL 入门教程(二)

原文:Beginning PHP and MySQL

协议:CC BY-NC-SA 4.0

四、函数

计算机编程的存在是为了自动化对人类来说太困难或太乏味的任务,从抵押贷款支付计算到计算视频游戏中虚拟玩家发射的足球的轨迹。您经常会发现,这样的任务包含可以在其他地方重用的逻辑位,不仅在同一个应用中,而且在许多其他应用中。例如,一个电子商务应用可能需要在几个不同的页面上验证一个电子邮件地址,比如当一个新用户注册使用一个网站时,当某人想要添加一个产品评论时,或者当一个访问者注册一个时事通讯时。用于验证电子邮件地址的逻辑异常复杂,因此最好将代码保存在一个位置,而不是嵌入到多个页面中。

令人欣慰的是,将这些重复的过程包含在一段已命名的代码中,然后在必要时调用这个名字,这一概念长期以来一直是现代计算机语言的一个关键特征。这样一段代码被称为函数,如果它定义的流程需要在未来进行更改,它将为您提供单一参考点的便利,这极大地降低了编程错误的可能性和维护开销。幸运的是,PHP 语言自带了 1000 多个原生函数,但是创建自己的函数也很容易!在这一章中,你将学习所有关于 PHP 函数的知识,包括如何创建和调用它们,向它们传递输入,使用类型提示,向调用者返回单个和多个值,以及创建和包含函数库。

调用函数

标准 PHP 发行版内置了 1000 多个函数,其中许多函数您将在本书中看到。您可以简单地通过指定函数名来调用您想要的函数,假设该函数已经通过将库编译到已安装的发行版中或者通过include()require()语句变得可用。例如,假设您想对数字 5 进行三次幂运算。你可以像这样调用 PHP 的pow()函数:

<?php
    echo pow(5,3);
?>

如果您想将函数输出存储在一个变量中,您可以像这样分配它:

<?php
    $value = pow(5,3); // returns 125
    echo $value;
?>

如果您想在一个更长的字符串中输出函数结果,您需要像这样连接它:

echo "Five raised to the third power equals ".pow(5,3).".";

坦白地说,这种方法往往很混乱,所以我建议首先将函数输出赋给一个变量,然后将变量嵌入字符串,就像这样:

$value = pow(5,3);
echo "Five raised to the third power equals {$value}.";

或者,你可以使用第三章中介绍的printf():

printf("Five raised to the third power equals %d.", pow(5,3));

在后三个示例中,将返回以下输出:

Five raised to the third power equals 125.

尝试

PHP 的函数库非常庞大,因此您将花费大量时间阅读文档,以了解更多关于特定函数的输入参数和行为的信息。当您想要使用诸如 date()之类的函数时尤其如此,该函数支持近 40 种不同的用于定义日期格式的说明符。幸运的是,官方 PHP 站点提供了一个方便的快捷方式,可以通过名字快速访问函数;只需将函数名附加到域 https://www.php.net 上。因此,要访问 date()函数,请导航至 https://www.php.net/date

手动输入日期()后,花点时间考虑一下如何设置日期的格式。出于本练习的目的,让我们使用 date()以此格式返回日期:2017 年 11 月 2 日,星期四。浏览格式说明符列表以找到合适的组合。小写字母 l 定义了星期几的完整文本表示,大写字母 F 定义了月份的完整文本表示,小写字母 n 定义了月份中某一天的数字表示,最后大写字母 Y 定义了年份的四位数表示。因此,您将把date() call like 嵌入到启用 PHP 的页面中,如下所示:

<?= date('l, F n, Y'); ?>

诚然,考虑到格式说明符的数量,函数date()有点反常;大多数 PHP 函数接受两个或三个参数,仅此而已。即便如此,你还是会发现快速导航到某个函数的能力非常方便。顺便说一下,它甚至适用于部分函数名!例如,假设您想将一个字符串全部转换为大写,但是不记得具体的函数名,只记得该名称包含字符串“upper”前往 https://www.php.net/upper ,你会看到相关函数和其他文档条目的列表!

大多数现代的 ide 像 PHP Storm,Sublime Text,Eclipse 等等。,提供了一个自动完成功能,可以显示任何函数的参数列表。这既适用于内置的 PHP 函数,也适用于您从库中编写或包含的函数。你不必每次都阅读 PHP 手册来检查参数的顺序,但是如果你在寻找函数,这是一个方便的工具。

创建函数

尽管 PHP 种类繁多的函数库对任何试图避免重复编程的人来说都是一个巨大的好处,但最终您会想要封装一个标准发行版中没有的任务,这意味着您需要创建自定义函数甚至整个函数库。为此,您需要定义自己的函数。用伪代码编写的函数定义如下:

function functionName(parameters)
{
    function body
}

虽然 PHP 对函数名没有太多限制(前提是不与现有的 PHP 函数冲突),也没有格式约定,但一个常用的格式标准是 camel case 格式( https://en.wikipedia.org/wiki/CamelCase ),它规定函数名的第一个字母是小写的,任何后续复合词的第一个字母都是大写的。此外,为了提高代码的可读性,应该使用描述性的名称!

例如,假设您希望将当前日期嵌入到站点的多个位置,但是希望以后能够方便地在一个位置更新日期格式。创建一个名为displayDate()的函数,并在其中结合适当的格式说明符使用date()函数,如下所示:

function displayDate()
{
    return date('l, F n, Y');
}

return语句正如其名称所暗示的那样,将相关的值返回给调用者。调用者是脚本中调用函数的位置,可能如下所示:

<?= displayDate(); ?>

当函数执行时,日期将被确定并格式化(例如,2016 年 8 月 24 日,星期六),结果返回给调用者。因为在这种情况下,您调用的是结合 PHP 的简短 echo 标记语法的displayDate(),当日期返回时,它将被直接嵌入到周围的页面中。

顺便说一下,您不需要输出函数结果。例如,您可以将结果赋给一个变量,如下所示:

$date = displayDate();

返回多个值

从一个函数返回多个值通常很方便。例如,假设您想创建一个从数据库中检索用户数据(比如用户的姓名、电子邮件地址和电话号码)并将其返回给调用者的函数。list()构造提供了一种从数组中检索值的便捷方法,如下所示:

<?php
    $colors = ["red","blue","green"];
    list($color1, $color2, $color3) = $colors;
?>

一旦list()构造执行完毕,$color1$color2$color3将分别被赋予redbluegreen。List()看起来像一个函数,但它实际上是一种语言结构,与用于右边计算并返回赋值的函数相比,它用在赋值运算符(=)的左边。

基于上一个例子中展示的概念,您可以想象如何使用list()从函数中返回三个先决条件值。

<?php
    function retrieveUserProfile()
    {
        $user[] = "Jason Gilmore";
        $user[] = "jason@example.com";
        $user[] = "English";
        return $user;
    }

    list($name, $email, $language) = retrieveUserProfile();
    echo "Name: {$name}, email: {$email}, language: {$language}";
?>

执行该脚本将返回以下内容:

Name: Jason Gilmore, email: jason@example.com, language: English

通过值传递参数

您会发现将数据传递给函数非常有用。例如,让我们创建一个函数,通过确定一件商品的销售税,然后将该金额加到价格上,来计算该商品的总成本。

function calculateSalesTax($price, $tax)
{
    return $price + ($price * $tax);
}

该函数接受在计算中使用的两个参数,恰当地命名为$price$tax。尽管这些参数是浮点型的,但是由于 PHP 的弱类型,没有什么可以阻止您传入任何数据类型的变量,但是结果可能不是您所期望的。此外,您可以根据需要定义尽可能少或尽可能多的参数;在这方面没有语言限制。

定义好之后,您就可以调用上一节中演示的函数了。例如,calculateSalesTax()函数可以这样调用:

calculateSalesTax(15.00, .0675);

当然,您不必将静态值传递给函数。您也可以像这样传递变量:

<?php
    $pricetag = 15.00;
    $salestax = .0675;
    $total = calculateSalesTax($pricetag, $salestax);
?>

当你以这种方式传递一个参数时,它被称为通过值传递。这意味着在函数范围内对这些值所做的任何更改都会在函数之外被忽略。本质上,解释器为每个变量创建了一个副本。如果您希望这些变化在函数范围之外得到反映,您可以通过引用传递参数*(),这将在下面介绍。*

注意

与 C++等语言不同,PHP 不要求您在调用函数之前定义它,因为整个脚本在执行之前就被读入 PHP 解析引擎。一个例外是,如果函数是在包含文件中定义的,则必须在使用函数之前执行 include/require 语句。

默认参数值

可以将默认值分配给输入参数,如果没有提供其他值,默认值将自动分配给该参数。为了修改销售税示例,假设您的大部分销售发生在俄亥俄州的富兰克林县。然后,您可以将默认值 6.75%分配给$tax,如下所示:

function calculateSalesTax($price, $tax=.0675)
{
   $total = $price + ($price * $tax);
   echo "Total cost: $total";
}

默认参数值必须出现在参数列表的末尾,并且必须是常量表达式;不能给非常数值赋值,如函数调用或变量。此外,请记住,你可以通过传递另一个税率来覆盖$tax;只有在没有第二个参数的情况下调用calculateSalesTax()时,才会使用 6.75%。

$price = 15.47;
calculateSalesTax($price);

您可以将某些参数指定为可选的,方法是将它们放在列表的末尾,并赋予它们缺省值 nothing,如下所示:

function calculateSalesTax($price, $tax=0)
{
    $total = $price + ($price * $tax);
    echo "Total cost: $total";
}

如果没有销售税,这允许您在没有第二个参数的情况下调用calculateSalesTax()

calculateSalesTax(42.9999);

它返回以下输出:

Total cost: $42.9999

如果指定了多个可选参数,您可以有选择地选择传递哪些参数。考虑这个例子:

function calculate($price, $price2=0, $price3=0)
{
    echo $price + $price2 + $price3; 

}

然后你可以调用calculate(),只传递$price$price2,就像这样:

calculate(10, 3);

这将返回以下值:

13

使用类型声明

不可否认,当谈到类型提示这个话题时,我把车放在了课程的前面,因为在这一节中,我不得不引用一些还没有正式介绍的术语和概念。然而,为了完整起见,在这一章中包括这一节是有意义的;因此,如果你觉得这些令人困惑,在阅读完第七章的所有内容后,请随意标记本页并返回本部分。PHP 5 引入了一个称为类型提示的新特性,后来被重命名为类型声明,它让您能够强制参数成为对象、接口、可调用或数组。PHP 7.0 增加了对标量(数字和字符串)类型提示的支持。如果提供的参数不是所需的类型,将会出现致命错误。举个例子,假设您创建了一个名为Customer的类,并希望确保传递给名为processPayPalPayment()的函数的任何参数都是Customer类型的。您可以使用类型提示来实现这种限制,如下所示:

function processPayPalPayment(Customer $customer) {
   // Process the customer's payment
}

PHP 7.0 还为返回值引入了类型提示,这是通过在参数列表的右括号后添加:来实现的。

function processPayPalPayment(Customer $customer): bool {
   // Process the customer's payment

}

在上面的例子中,如果函数试图返回除 true 或 false 之外的任何值,就会引发致命错误。

递归函数

递归函数,或者调用自身的函数,为程序员提供了相当大的实用价值,用于将一个复杂的问题分解成一个简单的案例,重复这个案例直到问题解决。

实际上,每个介绍性的递归例子都涉及阶乘计算。让我们做一些更实际的事情,创建一个贷款支付计算器。具体来说,下面的示例使用递归来创建付款计划,告诉您偿还贷款所需的每期付款的本金和利息金额。清单 4-1 中介绍了递归函数amortizationTable()。它接受四个参数作为输入:$paymentNumber,它标识付款号;$periodicPayment,携带每月总付款;$balance,表示剩余贷款余额;和$monthlyInterest,它决定了每月的利率百分比。这些项目在清单 4-2 中列出的脚本中指定或确定。

function amortizationTable($paymentNumber, $periodicPayment, $balance, $monthlyInterest)
{

    static $table = array();

    // Calculate payment interest
    $paymentInterest = round($balance * $monthlyInterest, 2);

    // Calculate payment principal
    $paymentPrincipal = round($periodicPayment - $paymentInterest, 2);

    // Deduct principal from remaining balance
    $newBalance = round($balance - $paymentPrincipal, 2);

    // If new balance < monthly payment, set to zero
    if ($newBalance < $paymentPrincipal) {
        $newBalance = 0;
    }

    $table[] = [$paymentNumber,
      number_format($newBalance, 2),
      number_format($periodicPayment, 2), 

      number_format($paymentPrincipal, 2),
      number_format($paymentInterest, 2)
    ];

// If balance not yet zero, recursively call amortizationTable()
    if ($newBalance > 0) {
         $paymentNumber++;
         amortizationTable($paymentNumber, $periodicPayment,
                            $newBalance, $monthlyInterest);
    }

    return $table;
}

Listing 4-1The Payment Calculator Function, amortizationTable()

在设置相关变量并执行一些初步计算后,清单 4-2 调用amortizationTable()函数。因为这个函数递归地调用自己,所有摊销表的计算将在这个函数内部执行;一旦完成,控制权将返回给调用者。

请注意,functions return 语句返回的值被返回给调用它的函数的实例,而不是主脚本(除了第一次调用该函数之外)。

<?php
   // Loan balance
   $balance = 10000.00;

   // Loan interest rate

   $interestRate = .0575;

   // Monthly interest rate
   $monthlyInterest = $interestRate / 12;

   // Term length of the loan, in years.
   $termLength = 5;

   // Number of payments per year.
   $paymentsPerYear = 12;

   // Payment iteration
   $paymentNumber = 1;

   // Determine total number payments
   $totalPayments = $termLength * $paymentsPerYear;

   // Determine interest component of periodic payment
   $intCalc = 1 + $interestRate / $paymentsPerYear;

   // Determine periodic payment
   $periodicPayment = $balance * pow($intCalc,$totalPayments) * ($intCalc - 1) /
                                    (pow($intCalc,$totalPayments) - 1); 

   // Round periodic payment to two decimals
   $periodicPayment = round($periodicPayment,2);

   $rows =  amortizationTable($paymentNumber, $periodicPayment, $balance, $monthlyInterest);

   // Create table
   echo "<table>";
   echo "<tr>
<th>Payment Number</th><th>Balance</th>
<th>Payment</th><th>Principal</th><th>Interest</th>

</tr>";

    foreach($rows as $row) {
        printf("<tr><td>%d</td>", $row[0]);
        printf("<td>$%s</td>", $row[1]);
        printf("<td>$%s</td>", $row[2]);
        printf("<td>$%s</td>", $row[3]);
        printf("<td>$%s</td></tr>", $row[4]);
    }

   // Close table
   echo "</table>";
?>

Listing 4-2A Payment Schedule Calculator Using Recursion

图 4-1 显示了示例输出,基于五年期固定贷款 10,000.00 美元的月供,利率为 5.75%。出于节省空间的原因,只列出了前 12 个支付迭代。

img/314623_5_En_4_Fig1_HTML.jpg

图 4-1

amortize.php 的输出示例

匿名函数

当用一个名字和一个参数列表声明一个函数时,可以从代码中定义它的任何地方调用它。在某些情况下,定义一个只能从特定位置调用的函数是有意义的。这通常用于回调函数,在回调函数中,由于调用另一个函数而调用一个特定的函数。这些函数被称为匿名函数或闭包。它们没有函数名。

闭包可以定义为变量的内容:

$example = function() {
   echo "Closure";
};
$example();

注意函数定义后面的分号。当闭包被赋给一个变量时,可以通过使用变量后跟()来执行函数,如示例所示。这类似于定义一个命名函数,将函数的名称赋给一个变量,然后使用该变量执行函数,如下所示:

function MyEcho() {
   echo "Closure";
};
$example = "MyEcho";
$example();

当涉及到函数外部变量的范围和访问时,闭包就像其他函数一样。为了提供对这些变量的访问,PHP 提供了关键字 use,如下例所示:

$a = 15;
$example = function() {
  $a += 100;
  echo $a . "\n";
};
$example();
echo $a . "\n";

$example = function() use ($a) {
  $a += 100;
  echo $a . "\n";
};
$example();
echo $a . "\n";

$example = function() use (&$a) {
  $a += 100;
  echo $a . "\n";
};
$example();
echo $a . "\n";

在第一部分中,全局变量$a是不可访问的,导致它在第一个闭包内被赋值为 0。在第二部分中,$a可用于闭包,但全局值不受影响。在最后一节中,全局变量$a通过引用变得可用。这导致在执行闭包时全局值发生变化。

函数库

伟大的程序员都是懒惰的,懒惰的程序员都是从复用性的角度来考虑的。函数为重用代码提供了一个很好的方法,通常被集中组装到库中,然后在类似的应用中重复使用。PHP 库是通过将函数定义简单地聚集在一个文件中创建的,如下所示:

<?php
   function localTax($grossIncome, $taxRate) {
      // function body here
   }
   function stateTax($grossIncome, $taxRate, $age) {
      // function body here
   }
   function medicare($grossIncome, $medicareRate) {
      // function body here
   }
?>

保存这个库,最好使用一个能清楚表明其用途的命名约定,比如library.taxation.php。但是,不要使用会导致 web 服务器传递未经解析的文件内容的扩展名将该文件保存在服务器文档根目录中。这样做为用户打开了从浏览器调用文件并检查代码的可能性,其中可能包含敏感数据。如果在完全控制硬盘和 web 服务器配置的服务器上部署代码,建议将包含文件存储在 web 根目录之外。这可以位于名为 include 或 libraries 的文件夹中。另一方面,如果您部署到一个共享的主机环境,您可能只能访问一个文件夹,即 web 根目录。在这种情况下,您的库和配置文件使用。php 扩展。如果它们被直接调用,这将确保它们通过 PHP 解释器传递。在这种情况下,它们将简单地生成一个空文档,尽管函数之外的任何代码都将被执行,并可能返回将成为输出一部分的内容。

你可以使用include()include_once()require()require_once()将这个文件插入到脚本中,这些在第三章中都有介绍。(或者,您可以使用 PHP 的auto_prepend配置指令来自动执行文件插入任务。)例如,假设您将这个库命名为library.taxation.php,您可以将它包含到如下脚本中:

<?php
    require_once("vendor/autoload.php");
    require_once("library.taxation.php");
    ...
?>

假设 vendor 文件夹在 web 根目录之外,这个脚本将使用配置好的include_path来查找目录和文件。这通常用于随 Composer 一起安装的库。一旦包含了这些函数,就可以根据需要调用这些库中的三个函数中的任何一个。

摘要

本章集中讨论了现代编程语言的一个基本构件:通过函数式编程的可重用性。您学习了如何创建和调用函数、在函数块之间传递信息、嵌套函数以及创建递归函数。最后,您学习了如何将函数聚合成库,并根据需要将它们包含到脚本中。

下一章介绍 PHP 的数组特性,涵盖该语言的大量数组管理和操作函数。

五、数组

作为程序员,你的大部分时间都花在数据集上。数据集的一些例子包括公司所有雇员的姓名;美国总统及其相应的出生日期;从 1900 年到 1975 年。事实上,使用数据集是如此普遍,以至于在代码中管理这些组的方法是所有主流编程语言的共同特征。在 PHP 语言中,这个特性被称为数组,它提供了一种存储、操作、排序和检索数据集的理想方式。

这一章讨论 PHP 的数组支持和令人印象深刻的各种函数。具体来说,您将学习如何执行以下操作:

  • 创建数组

  • 输出数组

  • 测试数组

  • 添加和移除数组元素

  • 定位数组元素

  • 遍历数组

  • 确定数组大小和元素唯一性

  • 排序数组

  • 合并、切片、拼接和剖析数组

在开始概述这些函数之前,让我们花点时间正式定义一个数组,并回顾一下 PHP 如何看待这一重要数据类型的一些基本概念。

什么是数组?

一个数组传统上被定义为一组共享某些特征的项目,比如相似性(汽车型号、棒球队、水果种类等)。)和类型(例如,所有字符串或整数)。每个物品都有一个特殊的标识符来区分,这个标识符被称为。PHP 将这个定义向前推进了一步,放弃了项目共享相同数据类型的要求。例如,一个数组很可能包含州名、邮政编码、考试分数或扑克牌花色等项目。PHP 中的数组被实现为一个映射,每个元素都有一个键和值。这使得数组足够灵活,可以将相同类型的多个值的结构处理为不同类型的复杂值。数据库查询的结果可以看作是行的数组。每一行都是一组值(字符串和数字等)。).

数组过去是用array()结构定义的。这仍然受到支持,但是 PHP 现在有了一种使用更短的语法和[]来定义数组的便捷方法,这种方法被称为 JSON 符号。每个条目由两部分组成:前面提到的键和值。这个键作为查找工具来检索它的对应项value。按键可以是numerical或者associative。除了值在数组中的位置之外,数字键与值没有真正的关系。例如,该数组可以由按字母顺序排序的汽车品牌列表组成。使用 PHP 语法,可能如下所示:

$carBrands = ["Cheverolet", "Chrysler""Ford", "Honda", "Toyota");

使用数字索引,您可以引用数组中的第一个品牌(雪佛兰),如下所示:

$ carBrands [0]

在上面的例子中,PHP 负责为每个值定义键。如果要指定键的其他值,可以通过定义第一个键或单独定义每个键来实现:

$carBrands = [12 => "Rolls Royce", "Bentley", "Porche"];
$germanCars = [20 => "Audi", 22 => "Porche", 25 => "VW"];

在上面的例子中,第一个数组将包含键 12、13 和 14;第二个示例将包含 20、22 和 25。

注意

像许多编程语言一样,PHP 的数字索引数组从位置 0 开始,而不是从 1 开始。

关联键在逻辑上与其对应的值有直接关系。当使用数字索引值没有意义时,关联映射数组特别方便。例如,您可能希望创建一个数组,将州缩写映射到它们的名称。使用 PHP 语法,可能如下所示:

$states = ["OH" => "Ohio", "PA" => "Pennsylvania", "NY" => "New York"];

你可以这样引用Ohio:

$states["OH"]

也可以创建数组的数组,称为多维数组。例如,您可以使用多维数组来存储美国的州信息。使用 PHP 语法,它可能看起来像这样:

$states = [
    "Ohio" => array("population" => "11,353,140", "capital" => "Columbus"),
    "Nebraska" => array("population" => "1,711,263", "capital" => "Omaha")
];

你可以参考俄亥俄州的人口:

$states["Ohio"]["population"]

这将返回以下内容:

11,353,140

从逻辑上讲,你需要一种方法来迭代数组的每个元素。正如你将在本章学到的,PHP 提供了很多方法来实现这一点。无论您使用的是关联键还是数字键,请记住,所有这些都依赖于一个称为的核心特性,即数组指针。数组指针就像一个书签,告诉你当前正在检查的数组的位置。您不会直接使用数组指针,而是使用内置语言特性或函数来遍历数组。尽管如此,理解这个基本概念还是很有用的。

创建数组

与其他语言不同,PHP 不要求在创建时给数组指定大小。事实上,因为它是一种松散类型的语言,PHP 甚至不要求您在使用它之前声明数组,尽管您可以这样做。本节介绍每种方法,从非正式的方法开始。

PHP 数组的单个元素是通过在一对方括号之间表示元素来引用的。因为数组没有大小限制,所以您可以通过引用它来创建数组,如下所示:

$state[0] = "Delaware";

然后,您可以像这样显示数组$state,的第一个元素:

echo $state[0];

通过将每个新值映射到数组索引,可以添加其他值,如下所示:

$state[1] = "Pennsylvania";
$state[2] = "New Jersey";
...
$state[49] = "Hawaii";

如果索引已被使用,该值将被覆盖。如果索引指向数组中未定义的元素,将添加一个新元素。

有趣的是,如果您希望索引值是数字的并且是升序的,那么您可以在创建时省略索引值:

$state[] = "Pennsylvania";
$state[] = "New Jersey";
...
$state[] = "Hawaii";

每次指数将被计算为最高数字指数加 1。

以这种方式创建关联数组同样简单,只是键总是必需的。下面的示例创建一个数组,该数组将美国各州的名称与其加入联邦的日期相匹配:

$state["Delaware"] = "December 7, 1787";
$state["Pennsylvania"] = "December 12, 1787";
$state["New Jersey"] = "December 18, 1787";
...
$state["Hawaii"] = "August 21, 1959";

接下来讨论的array()构造是一个功能相同但更正式的创建数组的方法。

使用 array()创建数组

array()构造将零个或多个条目作为其输入,并返回由这些输入元素组成的数组。它的原型是这样的:

array array([item1 [,item2 ... [,itemN]]])

下面是一个使用array()创建索引数组的例子:

$languages = array("English", "Gaelic", "Spanish");
// $languages[0] = "English", $languages[1] = "Gaelic", $languages[2] = "Spanish"

你也可以使用array()来创建一个关联数组,就像这样:

$languages = ["Spain" => "Spanish",
                   "Ireland" => "Gaelic",
                   "United States" => "English"];
// $languages["Spain"] = "Spanish"
// $languages["Ireland"] = "Gaelic"
// $languages["United States"] = "English"

当函数返回数组时,没有必要在访问单个元素之前将返回值赋给变量。这称为解引用,是访问感兴趣的单个元素的一种便捷方式。在下面的例子中。函数person()返回一个包含三个值的数组。为了只访问第一个,我们可以在函数调用后直接添加[0]

function person() {
  return ['Frank M. Kromann', 'frank@example.com', 'Author']
}
$name = person()[0];

使用 list()提取数组

list()构造与array()相似,尽管它被用来在一次操作中从数组中提取值来进行同步变量赋值。它的原型是这样的:

void list(mixed...)

当您从数据库或文件中提取信息时,这个构造可能特别有用。例如,假设您想要格式化并输出从名为users.txt的文本文件中读取的信息。文件的每一行都包含用户信息,包括姓名、职业和喜欢的颜色,每一项都用竖线分隔。典型的行类似于以下内容:

Nino Sanzi|professional golfer|green

使用list(),一个简单的循环可以读取每一行,将每一段数据分配给一个变量,并根据需要格式化和显示数据。下面是如何使用list()同时进行多个变量赋值:

// Open the users.txt file
$users = file("users.txt");

// While the End of File (EOF) hasn't been reached, get next line
foreach ($users as $user) {

     // use explode() to separate each piece of data.
     list($name, $occupation, $color) = explode("|", $user);

     // format and output the data
     printf("Name: %s <br>", $name);
     printf("Occupation: %s <br>", $occupation);
     printf("Favorite color: %s <br>", $color);

}

将读取users.txt文件的每一行,浏览器输出的格式如下:

Name: Nino Sanzi
Occupation: professional golfer
Favorite Color: green

回顾一下这个例子,list()依赖函数explode()(返回一个数组)将每一行分成三个元素,explode()通过使用竖线作为元素分隔符来完成这个任务。(第九章正式介绍了explode()功能。)这些元素然后被分配给$name$occupation$color。在这一点上,它只是一个向浏览器显示的格式化问题。

用预定义的值范围填充数组

range()函数提供了一种简单的方法来快速创建和填充一个由从lowhigh的整数值组成的数组。返回包含此范围内所有整数值的数组。它的原型是这样的:

array range(int low, int high [, int step])

例如,假设您需要一个包含骰子所有可能面值的数组:

$die = range(1, 6);
// Same as specifying $die = array(1, 2, 3, 4, 5, 6)

但是如果您想要一个仅由偶数或奇数组成的范围呢?或者由只能被 5 整除的值组成的范围?可选的step参数为此提供了一种方便的方法。例如,如果您想创建一个包含所有在020之间的偶数值的数组,您可以使用2step值:

$even = range(0, 20, 2);
// $even = array(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20);

range()功能也可用于字符序列。例如,假设您想要创建一个由字母 A 到 F 组成的数组:

$letters = range("A", "F");
// $letters = array("A", "B", "C", "D", "E", "F");

测试数组

当您将数组合并到应用中时,有时需要知道某个特定变量是否是数组。内置函数is_array()可用于完成该任务。其原型如下:

boolean is_array(mixed variable)

is_array()函数判断variable是否为数组,如果是则返回TRUE,否则返回FALSE。请注意,即使是由单个值组成的数组也将被视为数组。下面是一个例子:

$states = array("Florida");
$state = "Ohio";
printf("\$states is an array: %s <br />", (is_array($states) ? "TRUE" : "FALSE"));
printf("\$state is an array: %s <br />", (is_array($state) ? "TRUE" : "FALSE"));

执行此示例会产生以下结果:

$states is an array: TRUE
$state is an array: FALSE

输出数组

输出数组内容最常见的方式是遍历每个键并回显相应的值。例如,foreach 语句很好地完成了这个任务:

$states = array("Ohio", "Florida", "Texas");
foreach ($states as $state) {
    echo "{$state}<br />";
}

如果你想打印一个数组的数组或者需要对数组输出执行更严格的格式标准,考虑使用vprintf()函数,它允许你使用第三章中介绍的printf()sprintf()函数使用的相同格式语法轻松显示数组内容。这里有一个例子:

$customers = array();
$customers[] = array("Jason Gilmore", "jason@example.com", "614-999-9999");
$customers[] = array("Jesse James", "jesse@example.net", "818-999-9999");
$customers[] = array("Donald Duck", "donald@example.org", "212-999-9999");

foreach ($customers AS $customer) {
  vprintf("<p>Name: %s<br>E-mail: %s<br>Phone: %s</p>", $customer);
}

执行此代码会产生以下输出:

Name: Jason Gilmore

E-mail: jason@example.com

Phone: 614-999-9999

Name: Jesse James

E-mail: jesse@example.net

Phone: 818-999-9999

Name: Donald Duck

E-mail: donald@example.org

Phone: 212-999-9999

如果你想把格式化的结果发送到一个字符串,检查一下vsprintf()函数。

用于测试目的的打印数组

前面大多数例子中的数组内容都是用注释显示的。虽然这对于教学目的非常有用,但是在现实世界中,您需要知道如何轻松地将它们的内容输出到屏幕上进行测试。这通常用print_r()函数来完成。其原型如下:

boolean print_r(mixed variable [, boolean return])

print_r()函数接受一个变量并将其内容发送到标准输出,如果成功则返回TRUE,否则返回FALSE。这本身并不特别令人兴奋,直到您意识到它将把数组的内容(以及对象的内容)组织成可读的格式。例如,假设您想要查看由州及其对应的州首府组成的关联数组的内容。你可以这样称呼print_r():

print_r($states);

这将返回以下内容:

Array (
   [Ohio] => Columbus
   [Iowa] => Des Moines
   [Arizona] => Phoenix
)

可选参数 return 修改函数的行为,使其将输出作为字符串返回给调用者,而不是发送给标准输出。因此,如果想返回前面的$states数组的内容,只需将return设置为TRUE:

$stateCapitals = print_r($states, TRUE);

该函数在本章中反复使用,作为显示示例结果的简单方法。

记住print_r()函数不是输出数组的唯一方法;它只是为此提供了一种方便的方法。您可以使用循环条件自由输出数组,比如 while 或 for 事实上,使用这些类型的循环是实现许多应用功能所必需的。在本章和后面的章节中,我将反复讨论这个方法。

如果 print_r()函数用于向浏览器输出内容,您可能希望将文档的内容类型更改为 text/plain,因为默认的内容类型 text/html 会将空白减少为一个空格,因此输出将显示在一行中。或者,您可以将输出包含在标签中,让浏览器保留空白。这样,大型数组的输出将更具可读性。如果想知道更多关于数组的内容,可以使用var_dump()函数。它将包括每个元素的类型和长度。如果我们使用上面的状态示例切换到var_dump(),输出将如下所示:

array(3) {
  ["Ohio"]=>
  string(8) "Columbus"
  ["Iowa"]=>
  string(9) "Des Moins"
  ["Arizona"]=>
  string(7) "Phoenix"
}

 ..

tag causing the browser to preserve whitespace. The output of large arrays will be more readable that way. If you want to know more about the content of the array, you can use the

添加和移除数组元素

PHP 提供了许多函数来扩大和缩小一个数组。这些函数中的一部分是为了方便希望模仿各种队列实现(FIFO、LIFO 等)的程序员而提供的。),正如它们的名字(pushpopshiftunshift)所反映的那样。本节介绍这些函数并提供几个例子。

注意

传统的队列是一种数据结构,其中元素按照它们被输入的相同顺序被移除,称为先进先出FIFO 。相比之下,堆栈是一种数据结构,其中元素的移除顺序与输入顺序相反,称为后进先出LIFO

将值添加到数组的前面

array_unshift()函数将元素添加到数组的前面。所有预先存在的数字键被修改以反映它们在数组中的新位置,但是关联键不受影响。其原型如下:

int array_unshift(array array, mixed variable [, mixed variable...])

以下示例将两个状态添加到$states数组的前面:

$states = array("Ohio", "New York");
array_unshift($states, "California", "Texas");
// $states = array("California", "Texas", "Ohio", "New York");

向数组末尾添加一个值

array_push()函数将一个值添加到数组的末尾,在添加新值后返回数组中元素的总数。通过将多个变量作为输入参数传递给函数,可以将这些变量同时放入数组。其原型如下:

int array_push(array array, mixed variable [, mixed variable...])

以下示例将两个状态添加到$states数组中:

$states = array("Ohio", "New York");
array_push($states, "California", "Texas");
// $states = array("Ohio", "New York", "California", "Texas");

从数组前面移除值

函数的作用是:移除并返回数组中的第一项。如果使用数字键,所有相应的值都将下移,而使用关联键的数组不会受到影响。其原型如下:

mixed array_shift(array array)

以下示例从$states数组中删除第一个状态:

$states = array("Ohio", "New York", "California", "Texas");
$state = array_shift($states);
// $states = array("New York", "California", "Texas")
// $state = "Ohio"

从数组末尾移除值

函数的作用是:移除并返回数组中的最后一个元素。其原型如下:

mixed array_pop(array array)

以下示例从$states数组中删除最后一个状态:

$states = array("Ohio", "New York", "California", "Texas");
$state = array_pop($states);
// $states = array("Ohio", "New York", "California"
// $state = "Texas"

定位数组元素

在当今信息驱动的社会中,高效筛选数据的能力绝对至关重要。本节介绍几个函数,这些函数使您能够搜索数组以定位感兴趣的项目。

搜索数组

in_array()函数在一个数组中搜索一个特定的值,如果找到该值,返回TRUE,否则返回FALSE。其原型如下:

boolean in_array(mixed needle, array haystack [, boolean strict])

在下面的示例中,如果在由全州禁烟的州组成的数组中找到指定的州(俄亥俄州),则输出一条消息:

$state = "Ohio";
$states = ["California", "Hawaii", "Ohio", "New York"];
if(in_array($state, $states)) echo "Not to worry, $state is smoke-free!";

可选的第三个参数strict,强制in_array()也考虑类型。在这两种情况下,搜索都将区分大小写。搜索俄亥俄州或俄亥俄州不会找到值 ohio。

搜索关联数组键

如果在数组中找到指定的键,函数array_key_exists()返回TRUE,否则返回FALSE。其原型如下:

boolean array_key_exists(mixed key, array array)

下面的示例将在一个数组的键中搜索 Ohio,如果找到,将输出关于其进入 Union 的信息。请注意,这些键区分大小写:

$state["Delaware"] = "December 7, 1787";
$state["Pennsylvania"] = "December 12, 1787";
$state["Ohio"] = "March 1, 1803";
if (array_key_exists("Ohio", $state))
   printf("Ohio joined the Union on %s", $state["Ohio"]);

以下是结果:

Ohio joined the Union on March 1, 1803

搜索关联数组值

array_search()函数在数组中搜索指定的值,如果找到则返回其键,否则返回FALSE。其原型如下:

mixed array_search(mixed needle, array haystack [, boolean strict])

可选的 strict 参数用于强制函数查找相同的元素,这意味着类型和值必须匹配。搜索始终区分大小写。以下示例在$state中搜索特定日期(12 月 7 日),如果找到,则返回相应州的信息:

$state["Ohio"] = "March 1";
$state["Delaware"] = "December 7";
$state["Pennsylvania"] = "December 12";
$founded = array_search("December 7", $state);
if ($founded) printf("%s was founded on %s.", $founded, $state[$founded]);

输出如下:

Delaware was founded on December 7.

正在检索数组键

函数的作用是:返回一个由数组中所有键组成的数组。其原型如下:

array array_keys(array array [, mixed search_value [, boolean strict]])

如果包含可选的 search_value 参数,则只返回与该值匹配的键。strict 参数也用于强制类型检查。以下示例输出在$state数组中找到的所有键值:

$state["Delaware"] = "December 7, 1787";
$state["Pennsylvania"] = "December 12, 1787";
$state["New Jersey"] = "December 18, 1787";
$keys = array_keys($state);
print_r($keys);

输出如下:

Array (
   [0] => Delaware
   [1] => Pennsylvania
   [2] => New Jersey
)

检索数组值

array_values()函数返回数组中的所有值,自动为返回的数组提供数字索引。其原型如下:

array array_values(array array)

以下示例将检索在$population中找到的所有州的人口数量:

$population = ["Ohio" => "11,421,267", "Iowa" => "2,936,760"];
print_r(array_values($population));

此示例将输出以下内容:

Array ( [0] => 11,421,267 [1] => 2,936,760 )

提取列

处理数据库中的数据通常会产生多维数组,其中第一维对应于选定的行,第二维对应于结果集中的每一列。可以使用 array_column()函数从所有行的特定列中提取所有值。这将返回一个索引数组,只包含指定列中的值。其原型如下:

array array_column(array array, mixed column_key [, mixed index_key = null] )

以下示例显示了如何从多维数组中提取 name 列:

$simpsons = [
  ['name' => 'Homer Simpson', 'gender' => 'Male'],
  ['name' => 'Marge Simpson', 'gender' => 'Female'],
  ['name' => 'Bart Simpson', 'gender' => 'Male']
];
$names = array_column($simpsons, 'name');
print_r($names);

此示例将输出以下内容:

Array([0] => Homer Simpson [1] => Marge Simpson [2] => Bart Simpson )

可选的第三个参数可用于指定一个索引,该索引将用作返回数组中的键,从而创建一个新的键/值对数组,其中的键和值都来自原始数组。

遍历数组

遍历一个数组并检索各种键、值或两者的需求是很常见的,所以 PHP 提供了许多适合这种需求的函数也就不足为奇了。这些函数中的许多都有双重功能:检索驻留在当前指针位置的键或值,并将指针移动到下一个适当的位置。本节将介绍这些功能。

正在检索当前数组键

key()函数返回位于所提供数组的当前指针位置的键。其原型如下:

mixed key(array array)

以下示例将通过迭代数组并移动指针来输出$capitals数组键:

$capitals = array("Ohio" => "Columbus", "Iowa" => "Des Moines");
echo "<p>Can you name the capitals of these states?</p>";
while($key = key($capitals)) {
    printf("%s <br />", $key);
    next($capitals);
}

这将返回以下内容:

Can you name the capitals of these states?
Ohio
Iowa

注意key()不会在每次调用时推进指针。相反,您使用的是next()函数,它的唯一目的是完成这个任务。本节稍后将介绍该功能。

检索当前数组值

函数的作用是:返回当前指针位置的数组值。其原型如下:

mixed current(array array)

让我们修改前面的示例,这次检索数组值:

$capitals = array("Ohio" => "Columbus", "Iowa" => "Des Moines");

echo "<p>Can you name the states belonging to these capitals?</p>";

while($capital = current($capitals)) {
    printf("%s <br />", $capital);
    next($capitals);
}

输出如下:

Can you name the states belonging to these capitals?
Columbus
Des Moines

移动数组指针

有几个函数可以用来移动数组指针。本节将介绍这些功能。

将指针移动到下一个数组位置

函数的作用是:返回当前数组指针后面的数组值。当到达数组末尾,再次调用next()时,将返回 False。其原型如下:

mixed next(array array)

下面是一个例子:

$fruits = array("apple", "orange", "banana");
$fruit = next($fruits); // returns "orange"
$fruit = next($fruits); // returns "banana"

将指针移动到上一个数组位置

prev()函数返回位于当前指针位置之前的数组值,如果指针位于数组中的第一个位置,则返回FALSE。当到达数组的开头并再次调用prev()时,它将返回 null。其原型如下:

mixed prev(array array)

因为prev()的工作方式与next(),完全相同,所以无需举例。

将指针移动到第一个数组位置

函数的作用是将一个数组指针设置回数组的开头。其原型如下:

mixed reset(array array)

当您需要在脚本中多次查看或操作数组时,或者当排序已经完成时,通常会使用该函数。

将指针移动到最后一个数组位置

函数将指针移动到数组的最后一个位置,返回最后一个元素。其原型如下:

mixed end(array array)

下面的示例演示如何检索第一个和最后一个数组值:

$fruits = array("apple", "orange", "banana");
$fruit = current($fruits); // returns "apple"
$fruit = end($fruits); // returns "banana"

将数组值传递给函数

array_walk()函数将把数组的每个元素传递给用户定义的函数。当您需要基于每个数组元素执行特定操作时,这很有用。如果您打算实际修改数组键/值对,您需要将每个键/值作为引用传递给函数。其原型如下:

boolean array_walk(array &array, callback function [, mixed userdata])

用户定义的函数必须接受两个参数作为输入。第一个表示数组的当前值,第二个表示当前键。如果可选的userdata参数出现在对array_walk()的调用中,它的值将作为第三个参数传递给用户定义的函数。

您可能正在挠头,想知道这个函数有什么用处。也许最有效的例子之一是对用户提供的表单数据进行健全性检查。假设用户被要求提供六个他认为最能描述他所居住的州的关键词。清单 5-1 中提供了一个样本表格。

<form action="submitdata.php" method="post">
<p>
    Provide up to six keywords that you believe best describe the state in
    which you live:
</p>
<p>Keyword 1:<br />
<input type="text" name="keyword[]" size="20" maxlength="20" value="" /></p>
<p>Keyword 2:<br />
<input type="text" name="keyword[]" size="20" maxlength="20" value="" /></p>
<p>Keyword 3:<br />
<input type="text" name="keyword[]" size="20" maxlength="20" value="" /></p>
<p>Keyword 4:<br />
<input type="text" name="keyword[]" size="20" maxlength="20" value="" /></p>
<p>Keyword 5:<br />
<input type="text" name="keyword[]" size="20" maxlength="20" value="" /></p>
<p>Keyword 6:<br />
<input type="text" name="keyword[]" size="20" maxlength="20" value="" /></p>
<p><input type="submit" value="Submit!"></p>
</form>

Listing 5-1Using an Array in a Form

这个表单信息然后被发送到某个脚本,在表单中称为submitdata.php。该脚本应该清理用户数据,然后将其插入数据库供以后查看。使用array_walk(),您可以使用预定义的函数轻松过滤关键字:

<?php
    function sanitize_data(&$value, $key) {
        $value = strip_tags($value);
    }

    array_walk($_POST['keyword'],"sanitize_data");
?>

结果是$_POST['keyword']中的每个值都通过strip_tags()函数运行,这导致任何 HTML 和 PHP 标签都从值中删除。当然,额外的输入检查是必要的,但这足以说明array_walk()的效用

注意

如果你不熟悉 PHP 的表单处理能力,请参阅第十三章。

如果你正在处理数组的数组,函数array_walk_recursive()( PHP 5.0 中引入)能够递归地将用户定义的函数应用于数组中的每个元素。array_walk()array_walk_recursive()都会对数组进行修改。array_map()函数提供了类似的功能,但是产生了数据的副本。

确定数组大小和唯一性

有几个函数可用于确定总数组值和唯一数组值的数量。本节将介绍这些功能。

确定数组的大小

count()函数返回数组中找到的值的总数。其原型如下:

integer count(array array [, int mode])

如果可选的mode参数被启用(设置为1,数组将被递归计数,这是一个在计算多维数组的所有元素时有用的特性。第一个例子计算了在$garden数组中找到的蔬菜的总数:

$garden = array("cabbage", "peppers", "turnips", "carrots");
echo count($garden);

这将返回以下内容:

4

下一个示例对$locations 中的标量值和数组值进行计数:

$locations = array("Italy", "Amsterdam", array("Boston","Des Moines"), "Miami");
echo count($locations, 1);

这将返回以下内容:

6

您可能会对这个结果感到困惑,因为数组中似乎只有五个元素。保存波士顿和得梅因的数组实体被计为一个项,就像它的内容一样。

注意

sizeof()函数是count()的别名。它在功能上是相同的。

计数数组值频率

array_count_values()函数返回一个由关联的键/值对组成的数组。其原型如下:

array array_count_values(array array)

每个键代表在input_array中找到的一个值,其对应的值表示该键在input_array中出现的频率(作为一个值)。如果数组包含字符串和整数以外的值,将会生成警告。下面是一个例子:

$states = ["Ohio", "Iowa", "Arizona", "Iowa", "Ohio"];
$stateFrequency = array_count_values($states);
print_r($stateFrequency);

这将返回以下内容:

Array ( [Ohio] => 2 [Iowa] => 2 [Arizona] => 1 )

确定唯一数组值

array_unique()函数删除数组中所有重复的值,返回一个只包含唯一值的数组。注意,唯一值检查将每个值转换为字符串,因此 1 和“1”将被视为相同的值。其原型如下:

array array_unique(array array [, int sort_flags = SORT_STRING])

下面是一个例子:

$states = array("Ohio", "Iowa", "Arizona", "Iowa", "Ohio");
$uniqueStates = array_unique($states);
print_r($uniqueStates);

这将返回以下内容:

Array ( [0] => Ohio [1] => Iowa [2] => Arizona )

可选的sort_flags参数决定数组值如何排序。默认情况下,它们将作为字符串进行排序;但是,您也可以选择按照数字(SORT_NUMERIC)、使用 PHP 的默认排序方法(SORT_REGULAR)或根据地区(SORT_LOCALE_STRING)对它们进行排序。

排序数组

诚然,数据排序是计算机科学的一个中心话题。任何上过入门级编程课的人都很清楚诸如 bubble、heap、shell 和 quick 之类的排序算法。这个主题在日常编程任务中经常出现,以至于排序数据的过程就像创建一个if条件或while循环一样常见。PHP 通过提供大量有用的函数来简化这个过程,这些函数能够以各种方式对数组进行排序。

小费

默认情况下,PHP 的排序函数根据英语指定的规则进行排序。如果您需要用另一种语言排序,比如法语或德语,您需要通过使用setlocale()函数设置您的区域来修改这个默认行为。比如setlocale(LC_COLLATE, "de_DE")用于德语对比。

反转数组元素顺序

函数的作用是反转数组的元素顺序。其原型如下:

array array_reverse(array array [, boolean preserve_keys])

如果可选的 preserve_keys 参数设置为 TRUE,则保留键映射。

否则,每个新重新排列的值都将采用先前在该位置的值的键:

$states = array("Delaware", "Pennsylvania", "New Jersey");
print_r(array_reverse($states));
// Array ( [0] => New Jersey [1] => Pennsylvania [2] => Delaware )

将此行为与启用preserve_keys的结果进行对比:

$states = array("Delaware", "Pennsylvania", "New Jersey");
print_r(array_reverse($states,1));
// Array ( [2] => New Jersey [1] => Pennsylvania [0] => Delaware )

带有关联键的数组不受 preserve_keys 的影响;在这种情况下,始终保留键映射。

翻转数组键和值

函数的作用是颠倒数组中键和它们对应的值的角色。其原型如下:

array array_flip(array array)

下面是一个例子:

$state = array(0 => "Delaware", 1 => "Pennsylvania", 2 => "New Jersey");
$state = array_flip($state);
print_r($state);

此示例返回以下内容:

Array ( [Delaware] => 0 [Pennsylvania] => 1 [New Jersey] => 2 )

没有必要提供密钥,除非您想要不同于缺省值的密钥。

对数组排序

函数对数组进行排序,从最低值到最高值排列元素。其原型如下:

void sort(array array [, int sort_flags])

sort()函数不返回排序后的数组。相反,它对数组进行“就地”排序,并在成功或失败时返回 True 或 False。可选的sort_flags参数根据其赋值修改函数的默认行为:

  • SORT_NUMERIC:按数字顺序排列项目。这在对整数或浮点数进行排序时很有用。

  • SORT_REGULAR:按项目的 ASCII 值排序。例如,这意味着 B 将先于 a 到达。网上快速搜索会产生几个 ASCII 表,所以本书中不会复制其中一个。

  • 以一种更符合人类感知的正确顺序的方式对物品进行分类。关于此事的更多信息,见natsort(),在本节稍后介绍。

考虑一个例子。假设您想将考试成绩从最低到最高排序:

$grades = array(42, 98, 100, 100, 43, 12);
sort($grades);
print_r($grades);

结果看起来像这样:

Array ( [0] => 12 [1] => 42 [2] => 43 [3] => 98 [4] => 100 [5] => 100 )

需要注意的是,没有维护键/值关联。考虑以下示例:

$states = array("OH" => "Ohio", "CA" => "California", "MD" => "Maryland");
sort($states);
print_r($states);

以下是输出结果:

Array ( [0] => California [1] => Maryland [2] => Ohio )

要维护这些关联,请使用asort()

在维护键/值对的同时对数组进行排序

asort()函数与sort()相同,按照升序对数组进行排序,除了保持键/值的对应关系。其原型如下:

void asort(array array [, integer sort_flags])

请考虑一个数组,其中包含按照加入 Union 的顺序排列的州:

$state[0] = "Delaware";
$state[1] = "Pennsylvania";
$state[2] = "New Jersey";

使用sort()对这个数组进行排序会产生下面的顺序(注意,关联的相关性丢失了,这可能不是一个好主意):

Array ( [0] => Delaware [1] => New Jersey [2] => Pennsylvania )

然而,使用asort()排序会产生以下结果:

Array ( [0] => Delaware [2] => New Jersey [1] => Pennsylvania )

如果使用可选的sort_flags参数,精确的排序行为由其值决定,如sort()部分所述。

对数组进行逆序排序

rsort()函数与sort(),相同,除了它以逆序(降序)排序数组项目。其原型如下:

void rsort(array array [, int sort_flags])

下面是一个例子:

$states = array("Ohio", "Florida", "Massachusetts", "Montana");
rsort($states);
print_r($states);

它返回以下内容:

Array ( [0] => Ohio [1] => Montana [2] => Massachusetts [3] => Florida )

如果包含可选的sort_flags参数,精确的排序行为由其值决定,如sort()部分所述。

在保持键/值对的同时,对数组进行逆序排序

Like asort(),arsort()维护键/值的相关性。但是,它以相反的顺序对数组进行排序。其原型如下:

void arsort(array array [, int sort_flags])

下面是一个例子:

$states = array("Delaware", "Pennsylvania", "New Jersey");
arsort($states);
print_r($states);

它返回以下内容:

Array ( [1] => Pennsylvania [2] => New Jersey [0] => Delaware )

如果包含可选的sort_flags参数,精确的排序行为由其值决定,如sort()部分所述。

自然排序数组

natsort()函数旨在提供一种排序机制,可以与人们通常使用的机制相媲美。其原型如下:

void natsort(array array)

PHP 手册提供了一个很好的例子,展示了“自然”排序数组的含义考虑以下几项:picture1.jpgpicture2.jpgpicture10.jpgpicture20.jpg。使用典型算法对这些项目进行排序会产生以下顺序:

picture1.jpg, picture10.jpg, picture2.jpg, picture20.jpg

肯定不是你所期望的,对吗?natsort()函数解决了这个难题,按照您期望的顺序对数组进行排序,如下所示:

picture1.jpg, picture2.jpg, picture10.jpg, picture20.jpg

不区分大小写的自然排序

除了不区分大小写之外,函数natcasesort()在功能上与natsort(),相同:

void natcasesort(array array)

回到在natsort()部分提出的文件排序困境,假设这些图片是这样命名的:Picture1.JPGpicture2.jpgPICTURE10.jpgpicture20.jpgnatsort()函数将尽最大努力对这些项目进行排序,如下所示:

PICTURE10.jpg, Picture1.JPG, picture2.jpg, picture20.jpg

natcasesort()函数解决了这种特殊情况,如您所料进行排序:

Picture1.jpg, PICTURE10.jpg, picture2.jpg, picture20.jpg

按键值对数组排序

ksort()函数按键对数组排序,如果成功返回TRUE,否则返回FALSE。其原型如下:

integer ksort(array array [, int sort_flags])

如果包含可选的sort_flags参数,精确的排序行为由其值决定,如sort()部分所述。请记住,该行为将应用于键排序,而不是值排序。

逆序排序数组键

krsort()功能的操作与ksort(),按键排序相同,只是它以相反(降序)顺序排序。其原型如下:

integer krsort(array array [, int sort_flags])

根据用户定义的标准排序

usort()函数提供了一种使用用户定义的比较算法对数组进行排序的方法,该算法包含在一个函数中。当您需要以 PHP 内置排序函数无法提供的方式对数据进行排序时,这非常有用。其原型如下:

void usort(array array, callback function_name)

用户定义函数必须接受两个参数作为输入,并且必须根据第一个参数是小于、等于还是大于第二个参数,分别返回一个负整数、零或正整数。毫不奇怪,这个函数必须在调用usort()的同一个作用域中可用。

一个特别适用的例子是usort()的便利之处,它涉及美国格式日期的排序(月、日、年,而不是大多数其他国家使用的日、月、年)。假设您想对日期数组进行升序排序。虽然你可能认为sort()natsort()函数适合这份工作,但事实证明,两者都会产生不良结果。唯一的办法是创建一个自定义函数,能够按照正确的顺序对这些日期进行排序:

<?php
    $dates = array('10-10-2011', '2-17-2010', '2-16-2011',
                   '1-01-2013', '10-10-2012');
    sort($dates);

    echo "<p>Sorting the array using the sort() function:</p>";
    print_r($dates);

    natsort($dates);

    echo "<p>Sorting the array using the natsort() function: </p>";
    print_r($dates);

    // Create function use to compare two date values
    function DateSort($a, $b) {

        // If the dates are equal, do nothing.
        if($a == $b) return 0;

        // Disassemble dates
        list($amonth, $aday, $ayear) = explode('-',$a);
        list($bmonth, $bday, $byear) = explode('-',$b);

        // Pad the month with a leading zero if leading number not present
        $amonth = str_pad($amonth, 2, "0", STR_PAD_LEFT);
        $bmonth = str_pad($bmonth, 2, "0", STR_PAD_LEFT);

        // Pad the day with a leading zero if leading number not present
        $aday = str_pad($aday, 2, "0", STR_PAD_LEFT);
        $bday = str_pad($bday, 2, "0", STR_PAD_LEFT);

        // Reassemble dates
        $a = $ayear . $amonth . $aday;
        $b = $byear . $bmonth . $bday;

        // Determine whether date $a > date $b. Using the spaceship operator that return -1, 0 or 1
        // based on the comparison of $a and $b. This requires PHP 7.0 or greater.
        return ($a <=> $b);
    }

    usort($dates, 'DateSort');

    echo "<p>Sorting the array using the user-defined DateSort() function: </p>";

    print_r($dates);
?>

这将返回以下内容(为便于阅读而格式化):

Sorting the array using the sort() function:
Array ( [0] => 1-01-2013 [1] => 10-10-2011 [2] => 10-10-2012
        [3] => 2-16-2011 [4] => 2-17-2010 )

Sorting the array using the natsort() function:
Array ( [0] => 1-01-2013 [3] => 2-16-2011 [4] => 2-17-2010
        [1] => 10-10-2011 [2] => 10-10-2012 )

Sorting the array using the user-defined DateSort() function:
Array ( [0] => 2-17-2010 [1] => 2-16-2011 [2] => 10-10-2011
        [3] => 10-10-2012 [4] => 1-01-2013 )

合并、切片、拼接和分割数组

本节介绍了许多函数,这些函数能够执行更复杂的数组操作任务,例如组合和合并多个数组、提取数组元素的横截面以及比较数组。

合并数组

array_merge()函数将数组合并在一起,返回一个统一的数组。结果数组将从第一个输入数组参数开始,按照出现的顺序追加每个后续数组参数。其原型如下:

array array_merge(array array1, array array2 [, array arrayN])

如果输入数组包含的字符串键已经存在于结果数组中,则该键/值对将覆盖先前存在的条目。这种行为不适用于数字键,在这种情况下,键/值对将被追加到数组中。下面是一个例子:

$face = array("J", "Q", "K", "A");
$numbered = array("2", "3", "4", "5", "6", "7", "8", "9");
$cards = array_merge($face, $numbered);
shuffle($cards);
print_r($cards);

这将返回如下内容(您的结果会有所不同,因为 shuffle 函数会以随机顺序对数组元素进行重新排序):

Array ( [0] => 8 [1] => 6 [2] => K [3] => Q [4] => 9 [5] => 5
        [6] => 3 [7] => 2 [8] => 7 [9] => 4 [10] => A [11] => J )

递归追加数组

array_merge_recursive()功能的操作与array_merge(),相同,将两个或多个数组连接在一起,形成一个统一的数组。这两个函数的区别在于,当一个输入数组中的字符串键已经存在于结果数组中时,该函数的行为方式。注意,array_merge()将简单地覆盖预先存在的键/值对,用在当前输入数组中找到的键/值对替换它,而array_merge_recursive()将把值合并在一起,形成一个新的数组,用预先存在的键作为它的名称。其原型如下:

array array_merge_recursive(array array1, array array2 [, array arrayN])

下面是一个例子:

$class1 = array("John" => 100, "James" => 85);
$class2 = array("Micky" => 78, "John" => 45);
$classScores = array_merge_recursive($class1, $class2);
print_r($classScores);

这将返回以下内容:

Array (
   [John] => Array (
      [0] => 100
      [1] => 45
   )
   [James] => 85
   [Micky] => 78
)

注意,键John现在指向由两个分数组成的数字索引数组。

组合两个数组

array_combine()函数产生一个新的数组,由一组提交的键和相应的值组成。其原型如下:

array array_combine(array keys, array values)

两个输入数组的大小必须相等,并且都不能为空。下面是一个例子:

$abbreviations = array("AL", "AK", "AZ", "AR");
$states = array("Alabama", "Alaska", "Arizona", "Arkansas");
$stateMap = array_combine($abbreviations,$states);
print_r($stateMap);

这将返回以下内容:

Array ( [AL] => Alabama [AK] => Alaska [AZ] => Arizona [AR] => Arkansas )

分割数组

array_slice()函数根据起始值offset和 e length返回数组的一部分。其原型如下:

array array_slice(array array, int offset [, int length [, boolean preserve_keys]])

正的offset值将导致切片从数组的开头开始offset位置,而负的offset值将从数组的结尾开始切片offset位置。如果省略可选的 length 参数,切片将从偏移量开始,到数组的最后一个元素结束。如果提供了length并且是正数,它将在从数组开始的offset + length位置结束。相反,如果提供了length并且是负的,那么它将从数组的末尾开始在count(input_array) – length位置结束。考虑一个例子:

$states = array("Alabama", "Alaska", "Arizona", "Arkansas",
                 "California", "Colorado", "Connecticut");

$subset = array_slice($states, 4);

print_r($subset);

这将返回以下内容:

Array ( [0] => California [1] => Colorado [2] => Connecticut )

考虑第二个例子,这个例子涉及负长度:

$states = array("Alabama", "Alaska", "Arizona", "Arkansas",
"California", "Colorado", "Connecticut");

$subset = array_slice($states, 2, -2);

print_r($subset);

这将返回以下内容:

Array ( [0] => Arizona [1] => Arkansas [2] => California )

将可选的preserve_keys参数设置为true将导致数组值的键保留在返回的数组中。

拼接数组

array_splice()函数删除在指定范围内找到的数组的所有元素,用由replacement参数标识的值替换它们,并以数组的形式返回删除的元素。它可用于移除元素、添加元素或替换数组中的元素。其原型如下:

array array_splice(array array, int offset [, int length [, array replacement]])

正的offset值将导致拼接从数组开始的位置开始,而负的offset值将从数组结束的位置开始拼接。如果省略可选的length参数,从偏移位置到数组结尾的所有元素都将被删除。如果length被提供并且为正,拼接将在从数组开始的offset + length位置结束。相反,如果提供了length并且为负,拼接将在从数组末端开始的count(input_array)length位置结束。下面是一个例子:

$states = array("Alabama", "Alaska", "Arizona", "Arkansas",
                "California", "Connecticut");

$subset = array_splice($states, 4);

print_r($states);

print_r($subset);

这会产生以下内容(为便于阅读而格式化):

Array ( [0] => Alabama [1] => Alaska [2] => Arizona [3] => Arkansas )
Array ( [0] => California [1] => Connecticut )

您可以使用可选参数replacement来指定一个数组来替换目标段。下面是一个例子:

$states = array("Alabama", "Alaska", "Arizona", "Arkansas",
                "California", "Connecticut");

$subset = array_splice($states, 2, -1, array("New York", "Florida"));

print_r($states);

这将返回以下内容:

Array ( [0] => Alabama [1] => Alaska [2] => New York
        [3] => Florida [4] => Connecticut )

计算数组交集

array_intersect()函数返回一个键保留的数组,该数组只包含第一个数组中的值,这些值也存在于其他每个输入数组中。其原型如下:

array array_intersect(array array1, array array2 [, arrayN])

以下示例将返回在$array1中找到的、同时出现在$array2$array3中的所有状态:

$array1 = array("OH", "CA", "NY", "HI", "CT");
$array2 = array("OH", "CA", "HI", "NY", "IA");
$array3 = array("TX", "MD", "NE", "OH", "HI");
$intersection = array_intersect($array1, $array2, $array3);
print_r($intersection);

这将返回以下内容:

Array ( [0] => OH [3] => HI )

注意,array_intersect()认为两个项目相等,如果它们在转换成字符串后具有相同的值。

小费

array_intersect_key()函数将返回位于一个数组中的键,该数组位于任何其他提供的数组中。该功能的原型与array_intersect()相同。同样,array_intersect_ukey()函数允许你用用户定义的函数确定的比较算法来比较多个数组的键。更多信息请参考 PHP 手册。

计算关联数组交集

函数array_intersect_assoc()的操作与array_intersect(),相同,除了它也在比较中考虑数组键。因此,只有位于第一个数组中并且在所有其他输入数组中也可以找到的键/值对才会在结果数组中返回。其原型如下:

array array_intersect_assoc(array array1, array array2 [, arrayN])

以下示例返回一个数组,该数组包含在$array1中找到的、同时出现在$array2$array3中的所有键/值对:

$array1 = array("OH" => "Ohio", "CA" => "California", "HI" => "Hawaii");
$array2 = array("50" => "Hawaii", "CA" => "California", "OH" => "Ohio");
$array3 = array("TX" => "Texas", "MD" => "Maryland", "OH" => "Ohio");
$intersection = array_intersect_assoc($array1, $array2, $array3);
print_r($intersection);

这将返回以下内容:

Array ( [OH] => Ohio )

注意,Hawaii 没有被返回,因为$array2中对应的键是50而不是HI(其他两个数组也是这种情况)。

计算数组差异

本质上与array_intersect()相反,函数array_diff()返回位于第一个数组中但不在任何后续数组中的值:

array array_diff(array array1, array array2 [, arrayN])

下面是一个例子:

$array1 = array("OH", "CA", "NY", "HI", "CT");
$array2 = array("OH", "CA", "HI", "NY", "IA");
$array3 = array("TX", "MD", "NE", "OH", "HI");
$diff = array_diff($array1, $array2, $array3);
print_r($diff);

这将返回以下内容:

Array ( [0] => CT )

如果你想使用一个用户定义的函数来比较数组值,可以使用array_udiff()函数。

小费

array_diff_key()函数将返回位于一个数组中的键,这些键不在任何其他提供的数组中。该功能的原型与array_diff()相同。同样,array_diff_ukey()函数允许你用用户定义的函数确定的比较算法来比较多个数组的键。更多信息请参考 PHP 手册。

计算关联数组差异

函数array_diff_assoc()的操作与array_diff()相同,除了它在比较中也考虑数组键。因此,只有位于第一个数组中但没有出现在任何其他输入数组中的键/值对才会在结果数组中返回。其原型如下:

array array_diff_assoc(array array1, array array2 [, array arrayN])

以下示例仅返回"HI" => "Hawaii",因为这个特定的键/值出现在$array1中,但没有出现在$array2$array3中:

$array1 = array("OH" => "Ohio", "CA" => "California", "HI" => "Hawaii");
$array2 = array("50" => "Hawaii", "CA" => "California", "OH" => "Ohio");
$array3 = array("TX" => "Texas", "MD" => "Maryland", "KS" => "Kansas");
$diff = array_diff_assoc($array1, $array2, $array3);
print_r($diff);

这将返回以下内容:

Array ( [HI] => Hawaii )

小费

array_udiff_assoc()array_udiff_uassoc()array_diff_uassoc()函数都能够使用用户定义的函数以多种方式比较数组的差异。更多信息请参考 PHP 手册。

其他有用的数组函数

这一节介绍了许多数组函数,这些函数可能不容易归入前面的章节,但仍然非常有用。

返回一组随机的密钥

函数将返回在一个数组中找到的随机数。其原型如下:

mixed array_rand(array array [, int num_entries])

如果省略可选的num_entries参数,将只返回一个随机值。您可以通过相应地设置 num_entries 来调整返回的随机值的数量。下面是一个例子:

$states = array("Ohio" => "Columbus", "Iowa" => "Des Moines",
                "Arizona" => "Phoenix");
$randomStates = array_rand($states, 2);
print_r($randomStates);

这将返回以下内容(您的输出可能会有所不同):

Array ( [0] => Arizona [1] => Ohio )

洗牌数组元素

函数随机地对一个数组进行重新排序。其原型如下:

void shuffle(array input_array)

考虑一个包含代表扑克牌的值的数组:

$cards = array("jh", "js", "jd", "jc", "qh", "qs", "qd", "qc",
               "kh", "ks", "kd", "kc", "ah", "as", "ad", "ac");
shuffle($cards);
print_r($cards);

这将返回如下内容(您的结果将因随机而异):

Array ( [0] => js [1] => ks [2] => kh [3] => jd
            [4] => ad [5] => qd [6] => qc [7] => ah
            [8] => kc [9] => qh [10] => kd [11] => as
            [12] => ac [13] => jc [14] => jh [15] => qs )

添加数组值

array_sum()函数将input_array的所有值相加,返回最终总和。其原型如下:

mixed array_sum(array array)

如果在数组中发现其他数据类型(例如,带有非数值的字符串),它们将被忽略。下面是一个例子:

<?php
    $grades = array(42, "hello", "42");
    $total = array_sum($grades);
    print $total;
?>

这将返回以下内容:

84

细分数组

array_chunk()函数将 input_array 分解成一个多维数组,其中包含几个由size元素组成的更小的数组。其原型如下:

array array_chunk(array array, int size [, boolean preserve_keys])

如果input_array不能按大小均匀划分,最后一个数组将包含少于 size 的元素。启用可选参数 preserve_keys 将保留每个值的对应键。省略或禁用此参数会导致每个数组的数字索引从零开始。下面是一个例子:

$cards = array("jh", "js", "jd", "jc", "qh", "qs", "qd", "qc",
               "kh", "ks", "kd", "kc", "ah", "as", "ad", "ac");

// shuffle the cards
shuffle($cards);

// Use array_chunk() to divide the cards into four equal "hands"
$hands = array_chunk($cards, 4);

print_r($hands);

这将返回以下内容(您的结果会因随机播放而有所不同):

Array ( [0] => Array ( [0] => jc [1] => ks [2] => js [3] => qd )
        [1] => Array ( [0] => kh [1] => qh [2] => jd [3] => kd )
        [2] => Array ( [0] => jh [1] => kc [2] => ac [3] => as )
        [3] => Array ( [0] => ad [1] => ah [2] => qc [3] => qs ) )

摘要

数组在编程中扮演着不可或缺的角色,并且在所有可以想象的应用中无处不在,无论是否基于 web。本章的目的是让你快速了解许多 PHP 函数,当你处理这些数组时,这些函数会让你的编程生活变得更加容易。

下一章关注另一个非常重要的主题:面向对象编程。