Skip to content

数据类型

概述

PHP是一种动态类型语言,意味着变量不需要显式的类型声明。然而,理解PHP的数据类型对于编写健壮的应用程序至关重要。本章涵盖所有PHP数据类型、类型转换、类型检查和类型声明。

标量类型

字符串

字符串是用于存储和操作文本的字符序列。

php
<?php
// 单引号 - 字面字符串
$name = '张三';
$message = '你好,世界!';

// 双引号 - 变量插值
$greeting = "你好,$name!";
$path = "C:\Users\$name\Documents";

// 双引号中的转义序列
$text = "第一行\n第二行\t制表符";
$quote = '他说"你好"';

// 字符串长度
echo strlen($name); // 6(中文字符可能不同)

// 字符串函数
echo strtoupper($name);    // 张三(可能不支持中文)
echo strtolower($name);    // 张三(可能不支持中文)
echo ucfirst($name);       // 张三
echo ucwords($name);       // 张三
?>

Heredoc和Nowdoc

php
<?php
$name = "小红";

// Heredoc - 类似双引号
$html = <<<HTML
<div class="user">
    <h1>欢迎,$name!</h1>
    <p>这里支持变量插值。</p>
</div>
HTML;

// Nowdoc - 类似单引号
$config = <<<'CONFIG'
server_name = localhost
database = myapp
user = $name  // 这里不会被插值
CONFIG;

echo $html;
echo $config;
?>

整数

整数是没有小数点的完整数字。

php
<?php
$decimal = 123;        // 十进制
$octal = 0123;         // 八进制(十进制83)
$hex = 0x1A;           // 十六进制(十进制26)
$binary = 0b1010;      // 二进制(十进制10,PHP 5.4+)

// 整数限制
echo PHP_INT_MAX;      // 最大整数值
echo PHP_INT_MIN;      // 最小整数值
echo PHP_INT_SIZE;     // 字节大小

// 类型检查
var_dump(is_int($decimal));     // true
var_dump(is_integer($decimal)); // true(别名)

// 整数运算
$a = 10;
$b = 3;
echo $a + $b;    // 13
echo $a - $b;    // 7
echo $a * $b;    // 30
echo $a / $b;    // 3.333...(变成浮点数)
echo $a % $b;    // 1(取模)
echo $a ** $b;   // 1000(幂运算,PHP 5.6+)
?>

浮点数 (Float/Double)

浮点数表示带有小数点的数值。

php
<?php
$price = 19.99;
$scientific = 1.23e4;    // 12300
$negative = -3.14;

// 浮点数精度问题
$result = 0.1 + 0.2;
var_dump($result);       // 0.30000000000000004
var_dump($result == 0.3); // false

// 正确的浮点数比较
function floatEquals($a, $b, $epsilon = 0.00001) {
    return abs($a - $b) < $epsilon;
}

var_dump(floatEquals(0.1 + 0.2, 0.3)); // true

// 浮点数函数
echo round(3.7);         // 4
echo floor(3.7);         // 3
echo ceil(3.2);          // 4
echo number_format(1234.567, 2); // "1,234.57"

// 类型检查
var_dump(is_float($price));  // true
var_dump(is_double($price)); // true(别名)
?>

布尔值

布尔值表示 true 或 false 值。

php
<?php
$isActive = true;
$isComplete = false;

// 布尔转换
var_dump((bool) 1);        // true
var_dump((bool) 0);        // false
var_dump((bool) "");       // false
var_dump((bool) "0");      // false
var_dump((bool) "false");  // true(非空字符串)
var_dump((bool) []);       // false(空数组)
var_dump((bool) null);     // false

// PHP 中的假值
$falsyValues = [
    false,
    0,
    0.0,
    "",
    "0",
    null,
    []
];

foreach ($falsyValues as $value) {
    if (!$value) {
        echo "这个值是假值\n";
    }
}

// 类型检查
var_dump(is_bool($isActive)); // true
?>

复合类型

数组

数组是值的有序集合。

索引数组

php
<?php
// 创建索引数组
$fruits = ["apple", "banana", "orange"];
$numbers = array(1, 2, 3, 4, 5);

// 访问元素
echo $fruits[0];  // "apple"
echo $fruits[1];  // "banana"

// 添加元素
$fruits[] = "grape";           // 附加
$fruits[10] = "mango";         // 指定索引
array_push($fruits, "kiwi");   // 使用函数附加

// 数组函数
echo count($fruits);           // 数组长度
echo sizeof($fruits);          // count()的别名
var_dump(in_array("apple", $fruits)); // true

// 遍历数组
foreach ($fruits as $fruit) {
    echo $fruit . "\n";
}

foreach ($fruits as $index => $fruit) {
    echo "$index: $fruit\n";
}
?>

关联数组

php
<?php
// 创建关联数组
$person = [
    "name" => "John Doe",
    "age" => 30,
    "email" => "john@example.com",
    "active" => true
];

// 访问元素
echo $person["name"];    // "John Doe"
echo $person["age"];     // 30

// 添加/修改元素
$person["city"] = "New York";
$person["age"] = 31;

// 数组函数
$keys = array_keys($person);       // 获取所有键
$values = array_values($person);   // 获取所有值
var_dump(array_key_exists("name", $person)); // true

// 遍历关联数组
foreach ($person as $key => $value) {
    echo "$key: $value\n";
}
?>

多维数组

php
<?php
$users = [
    [
        "id" => 1,
        "name" => "John",
        "email" => "john@example.com"
    ],
    [
        "id" => 2,
        "name" => "Jane",
        "email" => "jane@example.com"
    ]
];

// 访问嵌套元素
echo $users[0]["name"];  // "John"
echo $users[1]["email"]; // "jane@example.com"

// 添加嵌套元素
$users[0]["age"] = 30;

// 遍历多维数组
foreach ($users as $user) {
    echo "ID: " . $user["id"] . "\n";
    echo "Name: " . $user["name"] . "\n";
    echo "Email: " . $user["email"] . "\n";
    echo "---\n";
}
?>

数组操作

php
<?php
$numbers = [1, 2, 3, 4, 5];

// 数组函数
$doubled = array_map(function($n) { return $n * 2; }, $numbers);
$evens = array_filter($numbers, function($n) { return $n % 2 == 0; });
$sum = array_reduce($numbers, function($carry, $n) { return $carry + $n; }, 0);

// 排序
$fruits = ["banana", "apple", "orange"];
sort($fruits);           // 排序值
asort($fruits);          // 排序值,保持键
ksort($fruits);          // 按键排序

// 数组合并和切片
$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$merged = array_merge($arr1, $arr2);  // [1, 2, 3, 4, 5, 6]
$slice = array_slice($numbers, 1, 3); // [2, 3, 4]

// 数组搜索
$position = array_search("apple", $fruits);
$exists = in_array("banana", $fruits);
?>

对象

对象是封装数据和行为的类实例。

php
<?php
// 简单的类定义
class Person {
    public $name;
    public $age;
    private $email;
    
    public function __construct($name, $age, $email) {
        $this->name = $name;
        $this->age = $age;
        $this->email = $email;
    }
    
    public function getEmail() {
        return $this->email;
    }
    
    public function setEmail($email) {
        if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $this->email = $email;
        }
    }
    
    public function introduce() {
        return "你好,我是{$this->name},今年{$this->age}岁。";
    }
}

// 创建对象
$person1 = new Person("Alice", 25, "alice@example.com");
$person2 = new Person("Bob", 30, "bob@example.com");

// 访问属性和方法
echo $person1->name;           // "Alice"
echo $person1->introduce();    // "你好,我是Alice,今年25岁。"
$person1->setEmail("alice.new@example.com");

// 对象比较
var_dump($person1 == $person2);  // false(不同值)
var_dump($person1 === $person2); // false(不同对象)

// 类型检查
var_dump(is_object($person1));   // true
var_dump($person1 instanceof Person); // true
?>

stdClass 对象

php
<?php
// 创建 stdClass 对象
$obj = new stdClass();
$obj->name = "John";
$obj->age = 30;

// 将数组转为对象
$array = ["name" => "Jane", "age" => 25];
$obj2 = (object) $array;

echo $obj2->name; // "Jane"

// 将对象转为数组
$backToArray = (array) $obj2;
var_dump($backToArray); // ["name" => "Jane", "age" => 25]
?>

特殊类型

NULL

NULL 表示一个没有值的变量。

php
<?php
$var = null;
$undefined;  // 也是 null

// NULL 赋值
$name = "John";
$name = null;  // 现在是 null

// 类型检查
var_dump(is_null($var));      // true
var_dump($var === null);      // true
var_dump(isset($var));        // false
var_dump(empty($var));        // true

// 空合并运算符(PHP 7+)
$username = $_GET['user'] ?? 'guest';
$config = $userConfig ?? $defaultConfig ?? 'fallback';

// 空合并赋值(PHP 7.4+)
$config ??= 'default_value';
?>

资源

资源是保存对外部资源引用的特殊变量。

php
<?php
// 文件资源
$file = fopen('data.txt', 'r');
var_dump(is_resource($file)); // true
var_dump(get_resource_type($file)); // "stream"
fclose($file);

// 数据库资源(旧的 MySQL 扩展)
// $connection = mysql_connect('localhost', 'user', 'pass');
// var_dump(is_resource($connection)); // true

// cURL 资源
$curl = curl_init();
var_dump(is_resource($curl)); // true
curl_close($curl);

// 图像资源(GD 扩展)
if (extension_loaded('gd')) {
    $image = imagecreate(100, 100);
    var_dump(is_resource($image)); // true
    imagedestroy($image);
}
?>

类型转换和类型推断

自动类型转换

php
<?php
// 字符串转数字
$str = "123";
$num = $str + 0;     // 123(整数)
$float = $str + 0.0; // 123.0(浮点数)

// 算数运算
echo "10" + "20";    // 30(两个都转为整数)
echo "10.5" + "20.3"; // 30.8(两个都转为浮点数)

// 字符串连接
echo 10 . 20;        // "1020"(两个都转为字符串)

// 布尔上下文
if ("0") {           // false
    echo "这不会打印";
}

if ("false") {       // true(非空字符串)
    echo "这会打印";
}
?>

显式类型转换

php
<?php
$value = "123.45";

// 转换为不同类型
$int = (int) $value;        // 123
$float = (float) $value;    // 123.45
$string = (string) $value;  // "123.45"
$bool = (bool) $value;      // true
$array = (array) $value;    // ["123.45"]
$object = (object) $value;  // stdClass,属性 "scalar" => "123.45"

// 使用转换函数
$int2 = intval($value);     // 123
$float2 = floatval($value); // 123.45
$string2 = strval($value);  // "123.45"

// 解析函数
$parsed = parse_url("https://example.com/path?query=value");
$json = json_decode('{"name": "John", "age": 30}', true);
?>

类型检查函数

内置类型检查

php
<?php
$var = "Hello";

// 类型检查函数
var_dump(is_string($var));   // true
var_dump(is_int($var));      // false
var_dump(is_float($var));    // false
var_dump(is_bool($var));     // false
var_dump(is_array($var));    // false
var_dump(is_object($var));   // false
var_dump(is_null($var));     // false
var_dump(is_resource($var)); // false

// 通用类型检查
var_dump(gettype($var));     // "string"

// 数字检查
var_dump(is_numeric("123"));   // true
var_dump(is_numeric("12.3"));  // true
var_dump(is_numeric("abc"));   // false

// 标量检查
var_dump(is_scalar($var));     // true(string、int、float、bool)
var_dump(is_scalar([]));       // false(数组不是标量)
?>

自定义类型检查

php
<?php
function isPositiveInteger($value) {
    return is_int($value) && $value > 0;
}

function isValidEmail($email) {
    return is_string($email) && filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

function isAssociativeArray($array) {
    if (!is_array($array)) {
        return false;
    }
    return array_keys($array) !== range(0, count($array) - 1);
}

// 使用
var_dump(isPositiveInteger(5));        // true
var_dump(isPositiveInteger(-5));       // false
var_dump(isValidEmail("test@example.com")); // true
var_dump(isAssociativeArray(["a" => 1, "b" => 2])); // true
?>

类型声明(PHP 7+)

标量类型声明

php
<?php
// 启用严格类型(可选)
declare(strict_types=1);

function add(int $a, int $b): int {
    return $a + $b;
}

function divide(float $a, float $b): float {
    return $a / $b;
}

function greet(string $name): string {
    return "Hello, " . $name;
}

function isActive(bool $status): bool {
    return $status;
}

// 使用
echo add(5, 3);           // 8
echo divide(10.0, 3.0);   // 3.333...
echo greet("Alice");      // "Hello, Alice"
echo isActive(true);      // 1 (true)
?>

类类型声明

php
<?php
class User {
    public $name;
    
    public function __construct(string $name) {
        $this->name = $name;
    }
}

class UserService {
    public function saveUser(User $user): bool {
        // 保存用户逻辑
        return true;
    }
    
    public function getUsers(): array {
        // 返回用户数组
        return [];
    }
}

// 使用
$user = new User("John");
$service = new UserService();
$result = $service->saveUser($user);
?>

可空类型(PHP 7.1+)

php
<?php
function findUser(?int $id): ?User {
    if ($id === null) {
        return null;
    }
    
    // 查找用户逻辑
    return new User("找到的用户");
}

// 联合类型(PHP 8.0+)
function processId(int|string $id): string {
    return "处理 ID:" . $id;
}

// 使用
$user = findUser(null);     // 返回 null
$user = findUser(123);      // 返回 User 对象
echo processId(123);        // "处理 ID:123"
echo processId("abc");      // "处理 ID:abc"
?>

处理混合类型

处理未知类型

php
<?php
function processValue($value) {
    switch (gettype($value)) {
        case 'string':
            return strtoupper($value);
        case 'integer':
        case 'double':
            return $value * 2;
        case 'boolean':
            return $value ? '是' : '否';
        case 'array':
            return count($value);
        case 'object':
            return get_class($value);
        case 'NULL':
            return 'NULL 值';
        default:
            return '未知类型';
    }
}

// 测试不同类型
echo processValue("hello");     // "HELLO"
echo processValue(5);           // 10
echo processValue(true);        // "是"
echo processValue([1, 2, 3]);   // 3
echo processValue(new stdClass()); // "stdClass"
echo processValue(null);        // "NULL 值"
?>

类型安全函数

php
<?php
function safeAdd($a, $b) {
    if (!is_numeric($a) || !is_numeric($b)) {
        throw new InvalidArgumentException("两个参数都必须是数字");
    }
    
    return $a + $b;
}

function safeArrayAccess(array $array, $key, $default = null) {
    return array_key_exists($key, $array) ? $array[$key] : $default;
}

// 使用
try {
    echo safeAdd(5, 3);        // 8
    echo safeAdd("5", "3");    // 8
    echo safeAdd("a", "b");    // 抛出异常
} catch (InvalidArgumentException $e) {
    echo "错误:" . $e->getMessage();
}

$data = ["name" => "John", "age" => 30];
echo safeArrayAccess($data, "name", "未知");     // "John"
echo safeArrayAccess($data, "email", "无邮箱");  // "无邮箱"
?>

下一步

现在您已经了解了PHP的数据类型,让我们在变量和常量中更详细地探讨变量和常量。

实践练习

  1. 创建函数演示不同数据类型的类型转换
  2. 构建一个数据验证器,检查多种类型和格式
  3. 使用类型声明实现类型安全函数
  4. 创建用于安全类型转换的工具类
  5. 练习处理多维数组和对象

理解数据类型是编写健壮PHP应用程序的基础!

本站内容仅供学习和研究使用。