数据类型之三种复合类型

在关于变量的章节中,我们已经知道 PHP 支持 9 种原始数据类型,在这里我们再次复习一下:

四种标量类型

  • Boolean:布尔值。仅有两个值,TRUEFALSE
  • Integer:整数型
  • Float:浮点数,也称作double,表示带小数点的小数,例如66.66
  • String:字符串

三种复合类型

  • Array:数组
  • Object:对象
  • Callable:可调用类型

两种特殊类型

  • Resource:资源类型,保存了到外部资源的一个引用
  • NULL:表示一个变量没有值,只有唯一的可能值NULL

复习完毕,上一节我们了解了数据类型的四种标量类型,现在我们来了解三种复合类型

Array:数组

数组是可存储一系列值的单个变量数据类型,实际上是一组“键-值”对的有序映射(将值关联到键)。其中键(key)只能是整型或者字符串类型,值(value)可以是任意类型。请看下方示例代码:

<?php

// 定义一个数组
$arr = array();
var_dump($arr);
/* 输出:
array(0) {
}
*/

$arr = [];// 方括号定义
var_dump($arr);
/* 输出:
array(0) {
}
*/

$arr = [
    'key'=>'value',
    '键'=>'值',
    6=>'整型键名',
    7.8=>'浮点型键名会被强制类型转换为整型',
    'key'=>'同名键只使用最后一个,之前的会被覆盖',
    null=>'NULL类型键名会被转化为空字符串',
    true=>'布尔值true键名会被转化为1,false则是0'
];
print_r($arr);
/* 输出:
Array
(
    [key] => 同名键只使用最后一个,之前的会被覆盖
    [键] => 值
    [6] => 整型键名
    [7] => 浮点型键名会被强制类型转换为整型
    [] => NULL类型键名会被转化为空字符串
    [1] => 布尔值true键名会被转化为1,false则是0
)
*/

var_dump(count($arr));// count()是检测数组元素个数的函数。输出:int(6)
// var_dump($arr[4]);// 提示:该键名不存在,无法访问
var_dump($arr['']);// 通过键名访问特定元素。输出:string(43) "NULL类型键名会被转化为空字符串"

示例代码中的数组中,每个元素都拥有键名,这种数组被称为“关联数组”,意为值与键相关联,通常用于键名有一定含义的情况;

若是未定义键名的数组,则该数组会自动转化为“数字索引数组”,可以通过元素的位置进行访问,数字索引数组的起始索引为0。例如:

<?php

$arr = [
    '极速数据',
    'https://www.jisuapi.com/',
    'PHP教程'
];
var_dump($arr[2]);// 访问数组$arr的第三个元素。输出:string(9) "PHP教程"

以上代码中只出现了一维数组,一维数组指的是一个数组中不包含其他数组,在现实世界我们可以将之看为一个只有行的列表。而数组的值可以是任意类型。如果数组元素嵌套另一个数组,形如下方代码,二维数组可以看做具有行和列(多于 1 列)的表格,三维数组可看做现实世界的魔方,每个格子代表一个元素:

<?php

// 二维数组
$arr = [
    [1, 2, 3],// 该数组是数组$arr的一个元素
    [4, 5, 6],
    [7, 8, 9],
];

// 三维数组
$arr = [
    [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
    ],// 该数组是数组$arr的一个元素,该数组中又包含一个数组
    [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
    ],
    [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
    ],
];

常用函数

PHP 中有许多操作数组的函数,在开发时经常会用到的比如计算数组中元素的个数(函数count())、将一维数组转为字符串(函数implode())、检测值是否为数组(函数is_array())等。后续我们将根据需求来详细讲解这些函数。

Object:对象

对象是描述客观世界中的一个实体。这个实体具备的特征与功能定义了其对象。例如一本书,它拥有出版社、作者、定价等特征,它可以被查看、借阅。这些则定义了“书”这个对象。

定义一个对象就是定义一个类,使用关键字class开头,其后跟着类名,然后是花括号,花括号内包含类的属性和方法的定义。定义对象暂且略过不提,这里主要讲对象的使用。

创建一个对象

要创建一个对象,需要使用new关键字实例化一个,后跟类名和用小括号包裹的参数列表(根据类定义)

<?php

// 预先定义一个类Book
class Book
{
    // 类属性
    // 类方法
}

// 实例化一个类
$book = new Book();

其他类型转化为对象

其他类型转化为对象将会创建一个内置的staClass实例。请看示例代码:

<?php

// 其他类型转化为对象:非数组类型转化为对象将会自动包含成员变量名 scalar
$boolean = true;
$obj = (object)$boolean;
var_dump($obj);
/* 输出:
object(stdClass)#1 (1) {
  ["scalar"]=>
  bool(true)
}
*/

$int = 10;
$obj = (object)$int;
var_dump($obj);
/* 输出:
object(stdClass)#1 (1) {
  ["scalar"]=>
  int(10)
}
*/

$float = 7.8;
$obj = (object)$float;
var_dump($obj);
/* 输出:
object(stdClass)#1 (1) {
  ["scalar"]=>
  float(7.8)
}
*/

$str = '一个字符串对象';
$obj = (object)$str;
var_dump($obj);
/* 输出:
object(stdClass)#1 (1) {
  ["scalar"]=>
  string(21) "一个字符串对象"
}
*/

// 数组类型转化为对象
$arr = [
    'key'=>'value',
    '键'=>'值',
    6=>'整型键名',
    7.8=>'浮点型键名会被强制类型转换为整型',
    'key'=>'同名键只使用最后一个,之前的会被覆盖',
    null=>'NULL类型键名会被转化为空字符串',
    true=>'布尔值true键名会被转化为1,false则是0'
];
$obj = (object)$arr;
var_dump($obj);
/* 输出:
object(stdClass)#1 (6) {
  ["key"]=>
  string(54) "同名键只使用最后一个,之前的会被覆盖"
  ["键"]=>
  string(3) "值"
  ["6"]=>
  string(12) "整型键名"
  ["7"]=>
  string(48) "浮点型键名会被强制类型转换为整型"
  [""]=>
  string(43) "NULL类型键名会被转化为空字符串"
  ["1"]=>
  string(50) "布尔值true键名会被转化为1,false则是0"
}
*/

不同的对象与它们之间的联系共同构建了客观世界。我们可以根据某一些特征与行为来定义某一类对象。 在之后的面向对象程序设计中,我们将感受到对象的强大。

Callable:可调用类型

自 PHP 5.4 起,PHP 支持接受用户自定义的函数作为参数传入另一个函数中使用,函数作为值使用,简洁了代码,增强了可读性,也更加灵活,此时传入的函数就是可调用类型

参数传递方式

PHP传递函数时以string类型的函数名作为参数传递的,可使用任何内置或者用户自定义的函数,除了语言结构array()echoempty()eval()exit()isset()list()printunset()。例如:

<?php

function callFunc($a, $b, $callback) {
    $callback();// 调用传入$callback的函数
    // callback();// 调用名为 callback() 的函数
    return $a + $b;
}
function callback() {
    echo '调用方法名:',__METHOD__;
    echo PHP_EOL;
}
function callback2() {
    echo '调用方法名:',__METHOD__;
    echo PHP_EOL;
}
callFunc(1, 2, 'callback');
// 输出:调用方法名:callback

callFunc(1, 2, 'callback2');
// 输出:调用方法名:callback2

可使用callable来指定回调类型callbackcallable类型可接受普通函数和匿名函数,closure类型只接受匿名函数。如下方代码:

<?php

function callFunc2(callable $callback) {
    $callback();
}
function callFunc3(Closure $callback) {
    $callback();
}
callFunc2('callback');// 输出:调用方法名:callback
// callFunc3('callback');// 出错:传入参数必须是一个匿名函数
$closure = function() {
    echo '这是一个匿名函数', __METHOD__;
};
callFunc3($closure);// 输出:这是一个匿名函数{closure}

回调函数不仅可以是简单函数,也可以是对象的方法,包括静态类方法。如下:

<?php

// 回调类静态方法
class Jisu
{
    public static function myMethod() {
        echo '调用了一个类中的静态方法';
        echo PHP_EOL;
    }
}
call_user_func(array('Jisu', 'myMethod'));// 输出:调用了一个类中的静态方法
class API extends Jisu
{
    public static function myMethod()
    {
        echo '继承了父类的静态方法,在子类中重写了';
        echo PHP_EOL;
    }
}
call_user_func(array('API', 'myMethod'));// 调用类API的myMethod()方法。输出:继承了父类的静态方法,在子类中重写了
call_user_func(array('API', 'parent::myMethod'));// 调用了子类API的父类的myMethod()方法。输出:调用了一个类中的静态方法

上方代码使用了call_user_func()函数,它将第一个参数作为回调函数调用,其余参数为回调函数的参数。类似的方法还有call_user_func_array()

可调用类型在PHP初级编程中涉及不多,这里不作深入讲解。


好的,关于数据类型的三种复合类型就讲到这里,之后我们将讲解两种特殊类型