数据类型

什么是数据类型?

在编程中,数据类型指的是变量所存储数据的种类和性质。PHP是一种弱类型语言,这意味着你不需要显式声明变量的类型,PHP会根据存储的值自动确定变量的类型。

为什么需要了解数据类型?

  • 正确处理数据:不同的数据类型有不同的处理方式
  • 避免错误:类型不匹配可能导致意外的结果
  • 优化性能:选择合适的数据类型可以提高程序效率
  • 数据验证:确保输入的数据符合预期格式

PHP的数据类型分类

PHP支持8种基本数据类型,分为三大类:

1. 标量类型(Scalar Types)

  • 字符串(String):文本数据
  • 整型(Integer):整数数字
  • 浮点型(Float/Double):小数数字
  • 布尔型(Boolean):真或假

2. 复合类型(Compound Types)

  • 数组(Array):有序的数据集合
  • 对象(Object):类的实例

3. 特殊类型(Special Types)

  • NULL:空值
  • 资源(Resource):外部资源引用

标量类型详解

1. 字符串(String)

字符串是由字符组成的序列,用于存储文本信息。

字符串的声明方式:

<?php
// 单引号字符串
$name1 = '张三';
$message1 = 'Hello, World!';

// 双引号字符串
$name2 = "李四";
$message2 = "你好,世界!";

// Heredoc 语法(用于多行字符串)
$longText1 = <<<TEXT
这是一段
很长的文本
可以包含多行
和换行符
TEXT;

// Nowdoc 语法(类似单引号的多行字符串)
$longText2 = <<<'TEXT'
这是一段
很长的文本
$变量不会被解析
TEXT;

echo $name1;      // 输出:张三
echo $message2;   // 输出:你好,世界!
?>

单引号 vs 双引号的区别:

<?php
$name = "张三";
$age = 25;

// 单引号:变量不会被解析,转义字符有限
echo '姓名:$name,年龄:$age';  // 输出:姓名:$name,年龄:$age
echo '路径:C:\\Users\\Admin';   // 输出:路径:C:\Users\Admin
echo 'It\'s a nice day';         // 输出:It's a nice day

// 双引号:变量会被解析,支持更多转义字符
echo "姓名:{$name},年龄:{$age}";  // 输出:姓名:张三,年龄:25
echo "路径:C:\\Users\\Admin";       // 输出:路径:C:\Users\Admin
echo "换行符:\n制表符:\t";          // 输出会包含换行和制表符
echo "今天是:" . date('Y-m-d');      // 输出:今天是:2024-01-01
?>

字符串操作示例:

<?php
// 字符串连接
$firstName = "张";
$lastName = "三";
$fullName = $firstName . $lastName;  // 输出:张三

// 字符串长度
$text = "Hello, 世界!";
echo strlen($text);  // 输出:9(中文字符通常算3个字节)

// 字符串中的字符数量
echo mb_strlen($text, 'UTF-8');  // 输出:9(正确计算中文字符)

// 字符串查找
$sentence = "PHP是一种流行的Web开发语言";
if (strpos($sentence, "PHP") !== false) {
    echo "找到了PHP";  // 输出:找到了PHP
}

// 字符串替换
$newText = str_replace("PHP", "Python", $sentence);
echo $newText;  // 输出:Python是一种流行的Web开发语言

// 字符串截取
$substring = substr("Hello, World!", 0, 5);
echo $substring;  // 输出:Hello

// 大小写转换
echo strtoupper("hello");  // 输出:HELLO
echo strtolower("WORLD");  // 输出:world
echo ucfirst("hello world");  // 输出:Hello world
echo ucwords("hello world");  // 输出:Hello World
?>

2. 整型(Integer)

整型是不包含小数部分的数字,可以是正数、负数或零。

整型的范围和格式:

<?php
// 不同格式的整数
$decimal = 123;        // 十进制
$negative = -456;      // 负数
$zero = 0;            // 零
$octal = 0123;        // 八进制(以0开头)
$hexadecimal = 0x1A;   // 十六进制(以0x开头)
$binary = 0b1010;      // 二进制(以0b开头,PHP 5.4+)

echo $decimal;        // 输出:123
echo $negative;       // 输出:-456
echo $octal;          // 输出:83(八进制123转十进制)
echo $hexadecimal;    // 输出:26(十六进制1A转十进制)
echo $binary;         // 输出:10(二进制1010转十进制)

// 检查整型范围
echo PHP_INT_MAX;     // 输出:最大整数值(通常为2147483647或9223372036854775807)
echo PHP_INT_MIN;     // 输出:最小整数值

// 64位系统的整型范围
if (PHP_INT_SIZE === 8) {
    echo "系统支持64位整数";
} else {
    echo "系统支持32位整数";
}
?>

整型操作示例:

<?php
// 基本算术运算
$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+)

// 整型递增递减
$count = 5;
echo ++$count;    // 输出:6(先递增,后返回)
echo $count++;    // 输出:6(先返回,后递增)
echo $count;      // 输出:7

echo --$count;    // 输出:6(先递减,后返回)
echo $count--;    // 输出:6(先返回,后递减)
echo $count;      // 输出:5

// 数学函数
echo abs(-10);           // 输出:10(绝对值)
echo round(3.7);         // 输出:4(四舍五入)
echo ceil(3.2);          // 输出:4(向上取整)
echo floor(3.9);         // 输出:3(向下取整)
echo rand(1, 100);       // 输出:1-100之间的随机数
echo max(10, 20, 15);    // 输出:20(最大值)
echo min(10, 20, 15);    // 输出:10(最小值)

// 进制转换
echo decbin(10);         // 输出:1010(十进制转二进制)
echo bindec(1010);       // 输出:10(二进制转十进制)
echo decoct(10);         // 输出:12(十进制转八进制)
echo octdec(12);         // 输出:10(八进制转十进制)
echo dechex(10);         // 输出:a(十进制转十六进制)
echo hexdec('a');        // 输出:10(十六进制转十进制)
?>

3. 浮点型(Float/Double)

浮点型用于表示包含小数部分的数字,也称为双精度浮点数。

浮点型的声明和使用:

<?php
// 浮点数的不同表示方式
$price1 = 19.99;           // 小数形式
$price2 = -123.456;        // 负数小数
$scientific = 1.23e4;      // 科学计数法:1.23 × 10^4 = 12300
$scientific2 = 1.23E-4;    // 科学计数法:1.23 × 10^-4 = 0.000123

echo $price1;              // 输出:19.99
echo $scientific;          // 输出:12300
echo $scientific2;         // 输出:0.000123

// 浮点数精度问题
$result1 = 0.1 + 0.2;      // 理论上应该是0.3
echo $result1;             // 输出:0.30000000000000004(精度误差)

// 使用 round() 解决精度问题
$result2 = round(0.1 + 0.2, 2);
echo $result2;             // 输出:0.3

// 检查浮点数范围
echo PHP_FLOAT_MAX;        // 最大浮点数
echo PHP_FLOAT_MIN;        // 最小正浮点数

// 无穷大检测
$infinity = 1.0 / 0.0;
if (is_infinite($infinity)) {
    echo "这是无穷大";
}

// NaN 检测(Not a Number)
$nan = acos(1.1);  // 反余弦函数,参数超出范围
if (is_nan($nan)) {
    echo "这不是一个数字";
}
?>

浮点数操作示例:

<?php
// 浮点数运算
$a = 10.5;
$b = 2.5;

echo $a + $b;    // 输出:13
echo $a - $b;    // 输出:8
echo $a * $b;    // 输出:26.25
echo $a / $b;    // 输出:4.2

// 数学函数
$number = 3.14159;

echo round($number, 2);      // 输出:3.14(保留2位小数)
echo number_format($number, 2); // 输出:3.14(格式化输出)
echo sprintf("%.2f", $number);  // 输出:3.14(格式化字符串)

// 幂和根运算
echo pow(2, 3);             // 输出:8(2的3次方)
echo sqrt(16);              // 输出:4(平方根)
echo exp(1);                // 输出:2.718281828...(e的1次方)

// 三角函数
echo sin(pi() / 2);         // 输出:1(sin 90°)
echo cos(0);                // 输出:1(cos 0°)
echo tan(pi() / 4);         // 输出:1(tan 45°)

// 对数函数
echo log(10);               // 输出:2.302585...(自然对数)
echo log10(100);            // 输出:2(以10为底的对数)

// 绝对值和符号
echo abs(-5.5);             // 输出:5.5(绝对值)
echo $negative = -3.14;
echo abs($negative);        // 输出:3.14

// 浮点数比较(注意精度问题)
$a = 0.1 + 0.2;
$b = 0.3;

// ❌ 直接比较可能失败
if ($a == $b) {
    echo "相等";  // 可能不会执行
}

// ✅ 使用 epsilon 比较方法
$epsilon = 0.00001;
if (abs($a - $b) < $epsilon) {
    echo "近似相等";  // 正确的比较方式
}

// 或者使用 round()
if (round($a, 5) == round($b, 5)) {
    echo "四舍五入后相等";
}
?>

4. 布尔型(Boolean)

布尔型只有两个值:true(真)和 false(假),用于表示逻辑状态。

布尔值的声明和使用:

<?php
// 直接声明布尔值
$isVisible = true;
$isHidden = false;

// 输出布尔值
var_dump($isVisible);  // 输出:bool(true)
var_dump($isHidden);   // 输出:bool(false)

// 注意:echo 输出布尔值时,true 输出 1,false 不输出任何内容
echo $isVisible;       // 输出:1
echo $isHidden;        // 无输出

// 使用 var_dump 或 print_r 查看布尔值
print_r($isVisible);   // 输出:1
?>

其他类型转换为布尔值:

<?php
// 以下值转换为 false:
var_dump((bool) "");          // 空字符串:false
var_dump((bool) 0);           // 数字 0:false
var_dump((bool) 0.0);         // 浮点数 0.0:false
var_dump((bool) "0");         // 字符串 "0":false
var_dump((bool) array());     // 空数组:false
var_dump((bool) null);        // null:false

// 以下值转换为 true:
var_dump((bool) "hello");     // 非空字符串:true
var_dump((bool) 123);         // 非 0 数字:true
var_dump((bool) 3.14);        // 非 0 浮点数:true
var_dump((bool) array(1,2));  // 非空数组:true
var_dump((bool) "false");     // 字符串 "false":true(特别注意!)
?>

布尔操作示例:

<?php
// 逻辑运算
$x = true;
$y = false;

// 逻辑与(AND)
$result1 = $x and $y;        // false
$result2 = $x && $y;          // false(优先级更高)

// 逻辑或(OR)
$result3 = $x or $y;         // true
$result4 = $x || $y;         // true(优先级更高)

// 逻辑异或(XOR)
$result5 = $x xor $y;        // true(两个值不同时为真)

// 逻辑非(NOT)
$result6 = !$x;              // false
$result7 = !$y;              // true

// 条件判断中的布尔使用
$age = 18;
$isAdult = ($age >= 18);

if ($isAdult) {
    echo "你是成年人";
} else {
    echo "你是未成年人";
}

// 复杂条件判断
$hasLicense = true;
$hasInsurance = false;
$age = 20;

// 可以开车吗?(成年、有驾照、有保险)
$canDrive = ($age >= 18) and $hasLicense and $hasInsurance;

if ($canDrive) {
    echo "你可以合法开车";
} else {
    echo "你不能开车";
}
?>

复合类型详解

1. 数组(Array)

数组是一个有序的数据集合,可以存储多个值。PHP支持两种类型的数组:索引数组和关联数组。

索引数组:

<?php
// 创建索引数组的不同方式
$fruits1 = array("苹果", "香蕉", "橙子");  // 传统方式
$fruits2 = ["苹果", "香蕉", "橙子"];       // 短数组语法(PHP 5.4+)

// 逐个添加元素
$colors = array();
$colors[] = "红色";
$colors[] = "绿色";
$colors[] = "蓝色";

// 指定索引添加元素
$numbers = array();
$numbers[0] = "第一";
$numbers[1] = "第二";
$numbers[5] = "第六";  // 跳过索引

// 访问数组元素
echo $fruits1[0];     // 输出:苹果
echo $fruits1[1];     // 输出:香蕉
echo $colors[2];      // 输出:蓝色

// 修改数组元素
$fruits1[1] = "葡萄";
echo $fruits1[1];     // 输出:葡萄

// 查看数组结构和内容
print_r($fruits1);
var_dump($numbers);

// 数组常用函数
echo count($fruits1);           // 输出:3(数组长度)
echo sizeof($colors);           // 输出:3(count()的别名)

// 检查元素是否存在
if (isset($fruits1[0])) {
    echo "索引 0 存在";
}

if (in_array("苹果", $fruits1)) {
    echo "苹果在数组中";
}

// 查找元素索引
$index = array_search("橙子", $fruits1);
if ($index !== false) {
    echo "橙子的索引是:$index";  // 输出:橙子的索引是:2
}

// 数组排序
sort($fruits1);                 // 升序排序
rsort($fruits1);                // 降序排序
asort($colors);                 // 保持索引关联的升序排序
?>

关联数组:

<?php
// 创建关联数组
$person = array(
    "name" => "张三",
    "age" => 25,
    "email" => "zhangsan@example.com",
    "isStudent" => true
);

// 短数组语法
$config = [
    "host" => "localhost",
    "username" => "admin",
    "password" => "secret",
    "database" => "myapp"
];

// 访问关联数组元素
echo $person["name"];        // 输出:张三
echo $config["host"];        // 输出:localhost

// 修改关联数组元素
$person["age"] = 26;
echo $person["age"];         // 输出:26

// 添加新元素
$person["city"] = "北京";
echo $person["city"];        // 输出:北京

// 检查键是否存在
if (array_key_exists("name", $person)) {
    echo "name 键存在";
}

if (isset($person["email"])) {
    echo "email 键存在且值不为null";
}

// 获取所有键和值
$keys = array_keys($person);
$values = array_values($person);

print_r($keys);    // 输出:所有键的数组
print_r($values);  // 输出:所有值的数组

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

// 只遍历值
foreach ($person as $value) {
    echo $value . "<br>";
}

// 数组合并
$merged = array_merge($person, $config);
print_r($merged);
?>

多维数组:

<?php
// 二维数组(数组的数组)
$students = [
    [
        "id" => 1,
        "name" => "张三",
        "scores" => [85, 92, 78]
    ],
    [
        "id" => 2,
        "name" => "李四",
        "scores" => [90, 88, 95]
    ],
    [
        "id" => 3,
        "name" => "王五",
        "scores" => [76, 84, 89]
    ]
];

// 访问多维数组元素
echo $students[0]["name"];           // 输出:张三
echo $students[1]["scores"][0];      // 输出:90

// 修改多维数组元素
$students[2]["scores"][2] = 91;      // 修改王五的第三门课成绩

// 遍历多维数组
foreach ($students as $student) {
    echo "学生ID:{$student['id']}<br>";
    echo "姓名:{$student['name']}<br>";
    echo "成绩:";
    foreach ($student["scores"] as $score) {
        echo "{$score} ";
    }
    echo "<br><br>";
}

// 三维数组示例
$departments = [
    "技术部" => [
        "前端组" => ["张三", "李四", "王五"],
        "后端组" => ["赵六", "钱七", "孙八"],
        "测试组" => ["周九", "吴十"]
    ],
    "市场部" => [
        "推广组" => ["郑一", "王二"],
        "销售组" => ["冯三", "陈四", "褚五"]
    ]
];

// 访问三维数组
echo $departments["技术部"]["前端组"][0];  // 输出:张三

// 遍历三维数组
foreach ($departments as $department => $groups) {
    echo "<h3>{$department}</h3>";
    foreach ($groups as $group => $members) {
        echo "<h4>{$group}</h4>";
        echo "<ul>";
        foreach ($members as $member) {
            echo "<li>{$member}</li>";
        }
        echo "</ul>";
    }
}
?>

2. 对象(Object)

对象是类的实例,用于封装数据和操作这些数据的方法。对象是面向对象编程的核心概念。

类和对象的基本概念:

<?php
// 定义一个简单的类
class Person {
    // 属性(成员变量)
    public $name;
    public $age;
    private $email;  // 私有属性,只能在类内部访问

    // 构造函数,在创建对象时自动调用
    public function __construct($name, $age, $email) {
        $this->name = $name;
        $this->age = $age;
        $this->email = $email;
        echo "创建了一个新的人:{$name}<br>";
    }

    // 方法(成员函数)
    public function introduce() {
        return "大家好,我叫{$this->name},今年{$this->age}岁。";
    }

    public function getAge() {
        return $this->age;
    }

    public function setAge($newAge) {
        if ($newAge > 0 && $newAge < 150) {
            $this->age = $newAge;
            return true;
        }
        return false;
    }

    public function getEmail() {
        return $this->email;
    }

    // 析构函数,对象被销毁时自动调用
    public function __destruct() {
        echo "对象 {$this->name} 被销毁了。<br>";
    }
}

// 创建对象实例
$person1 = new Person("张三", 25, "zhangsan@example.com");
$person2 = new Person("李四", 30, "lisi@example.com");

// 访问对象的属性
echo $person1->name;     // 输出:张三
echo $person1->age;      // 输出:25

// 调用对象的方法
echo $person1->introduce();  // 输出:大家好,我叫张三,今年25岁。

// 修改属性值
$person1->age = 26;
echo $person1->getAge();     // 输出:26

// 使用方法修改属性(带验证)
if ($person1->setAge(27)) {
    echo "年龄修改成功,现在 {$person1->age} 岁<br>";
} else {
    echo "年龄修改失败<br>";
}

// 访问私有属性需要通过方法
echo $person1->getEmail();   // 输出:zhangsan@example.com
// echo $person1->email;     // 错误:无法直接访问私有属性

// 检查对象
var_dump($person1);  // 查看对象的详细信息
echo get_class($person1);  // 输出:Person(获取类名)

if ($person1 instanceof Person) {
    echo "person1 是 Person 类的实例";
}
?>

更复杂的对象示例:

<?php
// 银行账户类
class BankAccount {
    private $accountNumber;
    private $ownerName;
    private $balance;
    private static $totalAccounts = 0;  // 静态属性

    // 静态方法
    public static function getTotalAccounts() {
        return self::$totalAccounts;
    }

    public function __construct($accountNumber, $ownerName, $initialBalance = 0) {
        $this->accountNumber = $accountNumber;
        $this->ownerName = $ownerName;
        $this->balance = $initialBalance;
        self::$totalAccounts++;  // 增加账户总数
    }

    // 存款
    public function deposit($amount) {
        if ($amount > 0) {
            $this->balance += $amount;
            $this->logTransaction("存款", $amount);
            return true;
        }
        return false;
    }

    // 取款
    public function withdraw($amount) {
        if ($amount > 0 && $amount <= $this->balance) {
            $this->balance -= $amount;
            $this->logTransaction("取款", $amount);
            return true;
        }
        return false;
    }

    // 获取余额
    public function getBalance() {
        return $this->balance;
    }

    // 转账到另一个账户
    public function transferTo($targetAccount, $amount) {
        if ($this->withdraw($amount)) {
            if ($targetAccount->deposit($amount)) {
                $this->logTransaction("转账给{$targetAccount->getOwnerName()}", $amount);
                return true;
            } else {
                // 如果存款失败,退回取款
                $this->balance += $amount;
            }
        }
        return false;
    }

    // 获取账户信息
    public function getAccountInfo() {
        return [
            'accountNumber' => $this->accountNumber,
            'ownerName' => $this->ownerName,
            'balance' => $this->balance
        ];
    }

    public function getOwnerName() {
        return $this->ownerName;
    }

    // 记录交易日志
    private function logTransaction($type, $amount) {
        $timestamp = date('Y-m-d H:i:s');
        echo "[{$timestamp}] 账户 {$this->accountNumber} - {$type}: ¥{$amount},余额: ¥{$this->balance}<br>";
    }
}

// 创建银行账户
$account1 = new BankAccount("001", "张三", 1000);
$account2 = new BankAccount("002", "李四", 500);

echo "总账户数:" . BankAccount::getTotalAccounts() . "<br>";

// 进行一些交易
$account1->deposit(500);        // 存款
$account2->deposit(300);        // 存款

$account1->withdraw(200);       // 取款
$account2->withdraw(100);       // 取款

// 转账
if ($account1->transferTo($account2, 300)) {
    echo "转账成功!<br>";
} else {
    echo "转账失败!<br>";
}

// 显示最终余额
echo "{$account1->getOwnerName()} 的余额:¥{$account1->getBalance()}<br>";
echo "{$account2->getOwnerName()} 的余额:¥{$account2->getBalance()}<br>";

// 获取账户信息
$info = $account1->getAccountInfo();
print_r($info);
?>

特殊类型详解

1. NULL 类型

NULL 表示变量没有值,这是唯一可能的 NULL 值。

NULL 的使用:

<?php
// 变量为 NULL 的情况
$var1 = null;           // 直接赋值为 null
$var2;                  // 声明但未赋值的变量(可能产生 Notice)
$var3 = "hello";
unset($var3);           // 使用 unset() 销毁变量

// 检查变量是否为 NULL
var_dump(is_null($var1));      // 输出:bool(true)
var_dump(is_null($var2 ?? null)); // 输出:bool(true)
var_dump(is_null($var3 ?? null)); // 输出:bool(true)

// 使用 isset() 检查
if (isset($var1)) {
    echo "var1 已设置且不为 NULL";
} else {
    echo "var1 未设置或为 NULL";  // 输出这个
}

// 使用 empty() 检查
if (empty($var1)) {
    echo "var1 为空";  // 输出这个
}

// NULL 和其他类型的比较
var_dump(null == false);    // 输出:bool(true)
var_dump(null == 0);        // 输出:bool(true)
var_dump(null == "");       // 输出:bool(true)
var_dump(null === false);   // 输出:bool(false)(严格比较)
var_dump(null === 0);       // 输出:bool(false)

// NULL 的实际应用
function findUser($userId) {
    // 模拟数据库查询
    if ($userId == 999) {
        return null;  // 用户不存在
    }

    return ["id" => $userId, "name" => "用户{$userId}"];
}

$user = findUser(999);
if ($user === null) {
    echo "用户不存在";
} else {
    echo "找到用户:" . $user['name'];
}

// 使用 null 合并运算符(PHP 7.0+)
$defaultName = "匿名用户";
$username = $_GET['username'] ?? $defaultName;
echo "欢迎,{$username}!";
?>

2. 资源类型(Resource)

资源类型是特殊的变量,保存了对外部资源的引用,如文件句柄、数据库连接、图像等。

资源的使用示例:

<?php
// 文件资源
$fileHandle = fopen("test.txt", "w");  // 打开文件,返回文件资源
if ($fileHandle !== false) {
    echo "文件打开成功<br>";
    echo "资源类型:" . get_resource_type($fileHandle) . "<br>";

    // 写入文件
    fwrite($fileHandle, "Hello, World!");

    // 关闭文件资源
    fclose($fileHandle);
    echo "文件已关闭<br>";
}

// 数据库连接资源(示例,实际需要数据库支持)
/*
$dbConnection = mysqli_connect("localhost", "username", "password", "database");
if ($dbConnection) {
    echo "数据库连接成功<br>";
    echo "资源类型:" . get_resource_type($dbConnection) . "<br>";

    // 执行查询...

    // 关闭连接
    mysqli_close($dbConnection);
}
*/

// 图像处理资源(需要 GD 库支持)
if (function_exists('imagecreatetruecolor')) {
    $image = imagecreatetruecolor(100, 50);
    if ($image !== false) {
        echo "图像创建成功<br>";
        echo "资源类型:" . get_resource_type($image) . "<br>";

        // 销毁图像资源
        imagedestroy($image);
        echo "图像资源已销毁<br>";
    }
}

// 检查资源
$var = "hello";
if (is_resource($var)) {
    echo "这是一个资源";
} else {
    echo "这不是一个资源";
}

// 获取资源类型
$file = fopen("example.txt", "r");
if (is_resource($file)) {
    echo "资源类型:" . get_resource_type($file);  // 输出:stream
    fclose($file);
}
?>

类型检查和转换

1. 类型检查函数

<?php
// 定义不同类型的变量
$stringVar = "Hello";
$intVar = 123;
$floatVar = 12.34;
$boolVar = true;
$arrayVar = [1, 2, 3];
$objectVar = new stdClass();
$nullVar = null;

// 类型检查函数
var_dump(is_string($stringVar));     // bool(true)
var_dump(is_int($intVar));           // bool(true)
var_dump(is_float($floatVar));       // bool(true)
var_dump(is_bool($boolVar));         // bool(true)
var_dump(is_array($arrayVar));       // bool(true)
var_dump(is_object($objectVar));     // bool(true)
var_dump(is_null($nullVar));         // bool(true)

// 通用类型检查
var_dump(is_scalar($intVar));        // bool(true)(标量类型)
var_dump(is_numeric("123"));         // bool(true)(数字或数字字符串)
var_dump(is_callable('strlen'));     // bool(true)(可调用)

// 获取变量类型
echo gettype($stringVar);            // string
echo gettype($intVar);               // integer
echo gettype($boolVar);              // boolean

// 设置变量类型
$var = "123";
settype($var, "integer");
echo gettype($var);                  // integer
echo $var;                           // 123
?>

2. 类型转换

<?php
// 自动类型转换(隐式转换)
$result = "10" + 5;          // 结果:15(字符串转整数)
$result = "10 apples" + 5;   // 结果:15(字符串开头数字转整数)
$result = "apples 10" + 5;   // 结果:5(字符串开头不是数字,转0)
$result = "10.5" + 5;        // 结果:15.5(字符串转浮点数)

// 显式类型转换
$string = "123.45";
$intVal = (int)$string;       // 123(转整数)
$floatVal = (float)$string;   // 123.45(转浮点数)
$stringVal = (string)$intVal; // "123"(转字符串)
$boolVal = (bool)$string;     // true(转布尔值)

// 使用转换函数
$intVal = intval("123abc");     // 123
$floatVal = floatval("12.34abc"); // 12.34
$boolVal = boolval("hello");    // true

// 特殊转换示例
$string = "0";
$bool1 = (bool)$string;         // false
$int = 0;
$bool2 = (bool)$int;            // false
$emptyArray = [];
$bool3 = (bool)$emptyArray;     // false
$nonEmptyArray = [0];
$bool4 = (bool)$nonEmptyArray;  // true

// 数组转换
$var = "hello";
$array1 = (array)$var;          // ["hello"]

$obj = new stdClass();
$obj->property = "value";
$array2 = (array)$obj;          // ["property" => "value"]

// 对象转换
$array = ["name" => "张三", "age" => 25];
$obj = (object)$array;
echo $obj->name;                // 张三
echo $obj->age;                 // 25

// JSON 转换(常用)
$data = ["name" => "张三", "age" => 25, "isStudent" => true];
$jsonString = json_encode($data);
echo $jsonString;               // {"name":"张三","age":25,"isStudent":true}

$decodedData = json_decode($jsonString);
print_r($decodedData);          // 对象形式

$decodedArray = json_decode($jsonString, true);
print_r($decodedArray);         // 数组形式
?>

实际应用示例

示例1:用户注册表单数据处理

<?php
// ========================================
// 用户注册表单数据处理
// 展示不同数据类型的实际应用
// ========================================

// 模拟表单提交数据
$_POST = [
    'username' => '  zhangsan123  ',
    'email' => 'zhangsan@example.com',
    'age' => '25',
    'password' => 'mypassword123',
    'gender' => 'male',
    'hobbies' => ['reading', 'coding', 'music'],
    'newsletter' => 'on',
    'bio' => '我是一名PHP开发者,热爱编程!'
];

// 数据处理和验证类
class UserRegistrationProcessor {
    private $errors = [];
    private $cleanData = [];

    // 清理字符串数据
    private function sanitizeString($input) {
        return trim(stripslashes($input));
    }

    // 验证邮箱格式
    private function validateEmail($email) {
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }

    // 验证年龄
    private function validateAge($age) {
        $age = (int)$age;
        return $age >= 18 && $age <= 120;
    }

    // 验证用户名
    private function validateUsername($username) {
        $length = strlen($username);
        return $length >= 3 && $length <= 20 && preg_match('/^[a-zA-Z0-9_]+$/', $username);
    }

    // 主处理函数
    public function processRegistration($formData) {
        echo "<h2>用户注册数据处理</h2>";

        // 1. 处理用户名(字符串类型)
        if (isset($formData['username'])) {
            $username = $this->sanitizeString($formData['username']);

            if ($this->validateUsername($username)) {
                $this->cleanData['username'] = $username;
                echo "✓ 用户名验证通过:{$username}<br>";
            } else {
                $this->errors['username'] = "用户名必须是3-20个字符,只能包含字母、数字和下划线";
            }
        }

        // 2. 处理邮箱(字符串类型 + 格式验证)
        if (isset($formData['email'])) {
            $email = $this->sanitizeString($formData['email']);

            if ($this->validateEmail($email)) {
                $this->cleanData['email'] = strtolower($email); // 转为小写
                echo "✓ 邮箱验证通过:{$email}<br>";
            } else {
                $this->errors['email'] = "邮箱格式不正确";
            }
        }

        // 3. 处理年龄(整型)
        if (isset($formData['age'])) {
            $age = $formData['age'];

            if (is_numeric($age) && $this->validateAge($age)) {
                $this->cleanData['age'] = (int)$age;
                echo "✓ 年龄验证通过:{$this->cleanData['age']}<br>";
            } else {
                $this->errors['age'] = "年龄必须是18-120之间的数字";
            }
        }

        // 4. 处理密码(字符串类型)
        if (isset($formData['password'])) {
            $password = $formData['password'];

            if (strlen($password) >= 8) {
                $this->cleanData['password_hash'] = password_hash($password, PASSWORD_DEFAULT);
                echo "✓ 密码验证通过,已加密存储<br>";
            } else {
                $this->errors['password'] = "密码长度至少8位";
            }
        }

        // 5. 处理性别(字符串类型)
        if (isset($formData['gender'])) {
            $gender = $formData['gender'];
            $validGenders = ['male', 'female', 'other'];

            if (in_array($gender, $validGenders)) {
                $this->cleanData['gender'] = $gender;
                echo "✓ 性别验证通过:{$gender}<br>";
            } else {
                $this->errors['gender'] = "请选择有效的性别";
            }
        }

        // 6. 处理爱好(数组类型)
        if (isset($formData['hobbies'])) {
            $hobbies = $formData['hobbies'];

            if (is_array($hobbies) && !empty($hobbies)) {
                // 清理每个爱好
                $cleanHobbies = [];
                foreach ($hobbies as $hobby) {
                    $cleanHobbies[] = $this->sanitizeString($hobby);
                }
                $this->cleanData['hobbies'] = $cleanHobbies;
                echo "✓ 爱好验证通过:" . implode(', ', $cleanHobbies) . "<br>";
            } else {
                $this->cleanData['hobbies'] = [];
                echo "✓ 没有选择爱好<br>";
            }
        }

        // 7. 处理订阅选择(布尔类型)
        if (isset($formData['newsletter'])) {
            $this->cleanData['newsletter'] = true;
            echo "✓ 用户订阅了新闻邮件<br>";
        } else {
            $this->cleanData['newsletter'] = false;
            echo "✓ 用户没有订阅新闻邮件<br>";
        }

        // 8. 处理个人简介(字符串类型)
        if (isset($formData['bio'])) {
            $bio = $this->sanitizeString($formData['bio']);

            if (strlen($bio) <= 500) {
                $this->cleanData['bio'] = $bio;
                echo "✓ 个人简介验证通过(长度:" . strlen($bio) . "字符)<br>";
            } else {
                $this->errors['bio'] = "个人简介不能超过500个字符";
            }
        }

        // 添加元数据
        $this->cleanData['registration_date'] = date('Y-m-d H:i:s');
        $this->cleanData['ip_address'] = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
        $this->cleanData['user_agent'] = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';

        return empty($this->errors);
    }

    // 显示处理结果
    public function displayResults() {
        echo "<h3>处理结果</h3>";

        if (empty($this->errors)) {
            echo "<p style='color: green;'>✓ 所有数据验证通过!</p>";

            echo "<h4>清理后的数据(不同数据类型):</h4>";
            echo "<pre>";
            var_dump($this->cleanData);
            echo "</pre>";

            // 显示数据类型信息
            echo "<h4>数据类型分析:</h4>";
            echo "<ul>";
            foreach ($this->cleanData as $key => $value) {
                echo "<li><strong>{$key}</strong>: " . gettype($value);
                if (is_array($value)) {
                    echo "(" . count($value) . " 个元素)";
                }
                echo "</li>";
            }
            echo "</ul>";

        } else {
            echo "<p style='color: red;'>✗ 发现以下错误:</p>";
            echo "<ul>";
            foreach ($this->errors as $field => $error) {
                echo "<li><strong>{$field}</strong>: {$error}</li>";
            }
            echo "</ul>";
        }
    }
}

// 处理注册数据
$processor = new UserRegistrationProcessor();
$success = $processor->processRegistration($_POST);
$processor->displayResults();
?>

示例2:数据类型转换工具类

<?php
// ========================================
// 数据类型转换工具类
// 提供安全的数据类型转换方法
// ========================================

class DataTypeConverter {
    /**
     * 安全转换为整数
     * @param mixed $value 要转换的值
     * @param int $default 默认值
     * @param int|null $min 最小值限制
     * @param int|null $max 最大值限制
     * @return int
     */
    public static function toInt($value, $default = 0, $min = null, $max = null) {
        // 处理 null 值
        if ($value === null) {
            return $default;
        }

        // 处理布尔值
        if (is_bool($value)) {
            return $value ? 1 : 0;
        }

        // 处理字符串
        if (is_string($value)) {
            // 移除非数字字符(保留负号和小数点)
            $cleaned = preg_replace('/[^0-9.-]/', '', $value);

            if ($cleaned === '' || $cleaned === '-') {
                return $default;
            }

            $value = $cleaned;
        }

        // 转换为整数
        $intValue = (int)$value;

        // 应用范围限制
        if ($min !== null && $intValue < $min) {
            return $min;
        }
        if ($max !== null && $intValue > $max) {
            return $max;
        }

        return $intValue;
    }

    /**
     * 安全转换为浮点数
     * @param mixed $value 要转换的值
     * @param float $default 默认值
     * @param float|null $min 最小值限制
     * @param float|null $max 最大值限制
     * @return float
     */
    public static function toFloat($value, $default = 0.0, $min = null, $max = null) {
        if ($value === null) {
            return $default;
        }

        if (is_bool($value)) {
            return $value ? 1.0 : 0.0;
        }

        if (is_string($value)) {
            $cleaned = preg_replace('/[^0-9.-]/', '', $value);
            if ($cleaned === '' || $cleaned === '-' || $cleaned === '.') {
                return $default;
            }
            $value = $cleaned;
        }

        $floatValue = (float)$value;

        if ($min !== null && $floatValue < $min) {
            return $min;
        }
        if ($max !== null && $floatValue > $max) {
            return $max;
        }

        return $floatValue;
    }

    /**
     * 安全转换为字符串
     * @param mixed $value 要转换的值
     * @param string $default 默认值
     * @param int|null $maxLength 最大长度限制
     * @return string
     */
    public static function toString($value, $default = '', $maxLength = null) {
        if ($value === null) {
            return $default;
        }

        if (is_bool($value)) {
            return $value ? 'true' : 'false';
        }

        if (is_array($value) || is_object($value)) {
            return json_encode($value);
        }

        $stringValue = (string)$value;

        if ($maxLength !== null && strlen($stringValue) > $maxLength) {
            $stringValue = substr($stringValue, 0, $maxLength);
        }

        return $stringValue;
    }

    /**
     * 安全转换为布尔值
     * @param mixed $value 要转换的值
     * @param bool $default 默认值
     * @return bool
     */
    public static function toBool($value, $default = false) {
        if ($value === null) {
            return $default;
        }

        // 字符串的特殊处理
        if (is_string($value)) {
            $lowerValue = strtolower(trim($value));
            if ($lowerValue === 'true' || $lowerValue === '1' || $lowerValue === 'yes' || $lowerValue === 'on') {
                return true;
            }
            if ($lowerValue === 'false' || $lowerValue === '0' || $lowerValue === 'no' || $lowerValue === 'off') {
                return false;
            }
        }

        return (bool)$value;
    }

    /**
     * 安全转换为数组
     * @param mixed $value 要转换的值
     * @param array $default 默认值
     * @return array
     */
    public static function toArray($value, $default = []) {
        if ($value === null) {
            return $default;
        }

        if (is_array($value)) {
            return $value;
        }

        if (is_string($value)) {
            // 尝试解析 JSON
            $decoded = json_decode($value, true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                return $decoded;
            }

            // 尝试解析逗号分隔的字符串
            if (strpos($value, ',') !== false) {
                return array_map('trim', explode(',', $value));
            }

            // 单个值转换为数组
            return [$value];
        }

        return [$value];
    }

    /**
     * 获取数据的详细信息
     * @param mixed $value 要分析的值
     * @return array 详细信息
     */
    public static function analyze($value) {
        $analysis = [
            'type' => gettype($value),
            'value' => $value,
            'size' => null,
            'is_numeric' => is_numeric($value),
            'is_scalar' => is_scalar($value),
            'is_callable' => is_callable($value),
            'is_resource' => is_resource($value)
        ];

        // 获取大小信息
        switch ($analysis['type']) {
            case 'string':
                $analysis['size'] = strlen($value);
                break;
            case 'array':
                $analysis['size'] = count($value);
                break;
            case 'object':
                $analysis['class'] = get_class($value);
                break;
            case 'resource':
                $analysis['resource_type'] = get_resource_type($value);
                break;
        }

        return $analysis;
    }
}

// 使用示例
echo "<h2>数据类型转换工具示例</h2>";

// 测试数据
$testData = [
    'string_number' => '  123.45  ',
    'invalid_number' => 'abc123def',
    'boolean_string' => 'yes',
    'json_string' => '{"name": "张三", "age": 25}',
    'comma_separated' => 'apple, banana, orange',
    'null_value' => null,
    'empty_string' => '',
    'zero_value' => 0,
    'empty_array' => []
];

echo "<h3>转换测试</h3>";
foreach ($testData as $name => $value) {
    echo "<h4>测试:{$name}</h4>";
    echo "原始值:";
    var_dump($value);

    echo "<ul>";
    echo "<li>转整数:" . DataTypeConverter::toInt($value, 0, 0, 1000) . "</li>";
    echo "<li>转浮点数:" . DataTypeConverter::toFloat($value, 0.0, 0.0, 999.99) . "</li>";
    echo "<li>转字符串:" . DataTypeConverter::toString($value, 'default', 20) . "</li>";
    echo "<li>转布尔值:" . (DataTypeConverter::toBool($value, false) ? 'true' : 'false') . "</li>";
    echo "<li>转数组:";
    $arrayResult = DataTypeConverter::toArray($value, ['default']);
    echo json_encode($arrayResult, JSON_UNESCAPED_UNICODE) . "</li>";
    echo "</ul>";

    // 数据分析
    $analysis = DataTypeConverter::analyze($value);
    echo "<p>数据分析:<strong>类型:{$analysis['type']}</strong>";
    if ($analysis['size'] !== null) {
        echo ",大小:{$analysis['size']}";
    }
    echo "</p>";
}

echo "<h3>数据详细信息</h3>";
echo "<pre>";
var_dump(DataTypeConverter::analyze($testData));
echo "</pre>";
?>

常见错误和解决方案

1. 类型比较错误

<?php
// ❌ 常见错误:松散比较导致意外结果
if ("0" == false) {
    echo "这会执行,但可能不是你想要的";
}

if ("" == 0) {
    echo "这也会执行";
}

// ✅ 正确做法:使用严格比较
if ("0" === false) {
    echo "这不会执行";
}

if ("" === 0) {
    echo "这也不会执行";
}

// 字符串比较的陷阱
$userInput = "123abc";
if ($userInput == 123) {
    echo "意外的相等!";  // 会执行,因为"123abc"转换为123
}

// ✅ 正确的做法
if ($userInput === 123) {
    echo "这不会执行";
}

// 或者使用类型检查
if (is_string($userInput) && $userInput === "123") {
    echo "完全匹配";
}
?>

2. 数组访问错误

<?php
// ❌ 访问不存在的数组索引
$array = ['a' => 1, 'b' => 2];
// echo $array['c'];  // 会产生 Notice: Undefined index

// ✅ 正确的做法
if (isset($array['c'])) {
    echo $array['c'];
} else {
    echo "索引 c 不存在";
}

// 使用 null 合并运算符(PHP 7.0+)
$value = $array['c'] ?? '默认值';
echo $value;

// 多维数组的安全访问
$nested = ['level1' => ['level2' => ['level3' => 'value']]];

// ❌ 链式访问可能出错
// echo $nested['level1']['level2']['missing'];

// ✅ 安全的多维访问
$value = $nested['level1']['level2']['level3'] ?? null;
if ($value !== null) {
    echo $value;
}
?>

3. 浮点数精度问题

<?php
// ❌ 直接比较浮点数可能失败
$a = 0.1 + 0.2;
$b = 0.3;
if ($a == $b) {
    echo "相等";  // 可能不会执行
}

// ✅ 使用 epsilon 方法比较
function floatEquals($a, $b, $epsilon = 0.00001) {
    return abs($a - $b) < $epsilon;
}

if (floatEquals($a, $b)) {
    echo "近似相等";
}

// ✅ 或者使用 round()
if (round($a, 5) == round($b, 5)) {
    echo "四舍五入后相等";
}

// 货币计算的正确方式
$price = 19.99;
$quantity = 3;

// ❌ 可能产生精度问题
$total = $price * $quantity;  // 可能不是 59.97

// ✅ 使用整数计算(分为单位)
$priceInCents = 1999;  // 19.99 元 = 1999 分
$totalInCents = $priceInCents * $quantity;  // 5997 分
$total = $totalInCents / 100;  // 59.97 元
?>

练习题

基础练习

  1. 数据类型识别 确定以下变量的数据类型:

    $a = "123";
    $b = 123;
    $c = 123.45;
    $d = true;
    $e = array(1, 2, 3);
    $f = null;
    
  2. 类型转换练习 将以下字符串转换为适当的数据类型:

    $age = "25";
    $price = "99.99";
    $isMember = "true";
    $scores = "85,90,78";
    
  3. 数组操作 创建一个包含学生信息的关联数组,包含姓名、年龄、成绩等信息。

进阶练习

  1. 类型验证函数 编写一个函数,验证输入的数据是否符合预期类型:

    function validateData($data, $expectedType) {
        // 实现验证逻辑
    }
    
  2. 安全类型转换 实现一个安全的类型转换函数,处理各种边界情况:

    function safeConvert($value, $type, $default = null) {
        // 实现安全转换
    }
    
  3. 数据类型分析器 创建一个分析器,可以详细分析任意变量的数据类型和特征。

实践练习

  1. 表单数据处理 创建一个完整的表单数据处理脚本,包含:

    • 各种数据类型的接收和验证
    • 安全的类型转换
    • 错误处理和用户反馈
  2. 配置文件解析器 实现一个配置文件解析器,支持不同的数据类型:

    // 配置文件示例
    database_host = "localhost"
    database_port = 3306
    debug_mode = true
    allowed_ips = ["127.0.0.1", "::1"]
    

总结

PHP的数据类型系统为开发者提供了灵活而强大的数据处理能力:

核心概念:

  1. 8种基本数据类型:4种标量类型、2种复合类型、2种特殊类型
  2. 弱类型特性:自动类型转换提供了便利,但也需要注意陷阱
  3. 类型检查函数:帮助确保数据类型的正确性
  4. 安全类型转换:避免类型转换中的常见错误

最佳实践:

  • 明确类型意图:使用适当的数据类型存储相应的数据
  • 严格比较:在需要精确比较时使用 === 而不是 ==
  • 类型验证:在处理外部输入时进行严格的类型检查
  • 安全转换:使用专门的转换函数处理复杂的类型转换
  • 理解转换规则:了解PHP的自动类型转换机制,避免意外结果

实际应用要点:

  • 表单数据处理:正确处理各种用户输入的数据类型
  • 数据库交互:确保数据的正确类型存储和检索
  • API接口:规范数据类型的传输和接收
  • 数值计算:特别注意浮点数的精度问题

掌握PHP的数据类型是编写健壮、安全应用程序的基础。在实际开发中,合理的类型使用和严格的类型检查可以帮助避免许多常见的编程错误。

下一步学习:掌握数据类型后,让我们继续学习PHP中的运算符,了解如何对各种类型的数据进行操作。