Skip to content

数组和对象

概述

数组和对象是PHP中的基本数据结构。数组存储数据集合,而对象封装数据和行为。本章涵盖数组操作、面向对象编程基础和复杂数据结构的处理。

数组深入探讨

数组创建和类型

php
<?php
// 索引数组
$fruits = array("apple", "banana", "orange");
$numbers = [1, 2, 3, 4, 5]; // 简短语法(PHP 5.4+)

// 关联数组
$person = array(
    "name" => "张三",
    "age" => 30,
    "city" => "北京"
);

$config = [
    "database" => "mysql",
    "host" => "localhost",
    "port" => 3306
];

// 混合数组
$mixed = [
    0 => "第一个项目",
    "key" => "值",
    1 => "第二个项目",
    "nested" => ["a", "b", "c"]
];

// 多维数组
$matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

$users = [
    [
        "id" => 1,
        "name" => "小明",
        "email" => "xiaoming@example.com",
        "roles" => ["user", "editor"]
    ],
    [
        "id" => 2,
        "name" => "小红",
        "email" => "xiaohong@example.com",
        "roles" => ["user"]
    ]
];
?>

数组访问和修改

php
<?php
$fruits = ["apple", "banana", "orange"];

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

// 修改元素
$fruits[1] = "grape";
echo $fruits[1]; // "grape"

// 添加元素
$fruits[] = "kiwi";           // 附加到末尾
$fruits[10] = "mango";        // 指定索引
array_push($fruits, "peach"); // 使用函数附加
array_unshift($fruits, "strawberry"); // 前置

// 删除元素
unset($fruits[2]);            // 删除指定索引
$lastFruit = array_pop($fruits);     // 删除并返回最后一个
$firstFruit = array_shift($fruits);  // 删除并返回第一个

// 关联数组操作
$person = ["name" => "张三", "age" => 30];

// 添加/修改
$person["email"] = "zhangsan@example.com";
$person["age"] = 31;

// 检查存在
if (isset($person["email"])) {
    echo "邮箱存在:" . $person["email"];
}

if (array_key_exists("phone", $person)) {
    echo "电话存在";
} else {
    echo "电话未设置";
}

// 删除
unset($person["age"]);
?>

数组函数和操作

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

// 数组信息
echo count($numbers);        // 8(长度)
echo sizeof($numbers);       // 8(count的别名)
echo array_sum($numbers);    // 31(求和)
echo array_product($numbers); // 6480(乘积)

// 最小/最大值
echo min($numbers);          // 1
echo max($numbers);          // 9

// 搜索
$position = array_search(5, $numbers);  // 返回第一个匹配的索引
$exists = in_array(4, $numbers);        // true/false

// 排序
$sorted = $numbers;
sort($sorted);               // 对值排序,丢失键
print_r($sorted);

$reversed = $numbers;
rsort($reversed);            // 逆序排序
print_r($reversed);

// 关联数组排序
$people = [
    "zhangsan" => 30,
    "lisi" => 25,
    "wangwu" => 35
];

asort($people);              // 按值排序,保持键
print_r($people);            // lisi=>25, zhangsan=>30, wangwu=>35

ksort($people);              // 按键排序
print_r($people);            // lisi=>25, wangwu=>35, zhangsan=>30

// 自定义排序
$users = [
    ["name" => "张三", "age" => 30],
    ["name" => "李四", "age" => 25],
    ["name" => "王五", "age" => 35]
];

usort($users, function($a, $b) {
    return $a["age"] <=> $b["age"]; // 按年龄排序
});

print_r($users);
?>

数组操作函数

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

// Map - 转换每个元素
$doubled = array_map(function($n) {
    return $n * 2;
}, $numbers);
print_r($doubled); // [2, 4, 6, 8, 10]

// Filter - 根据条件筛选元素
$evens = array_filter($numbers, function($n) {
    return $n % 2 === 0;
});
print_r($evens); // [2, 4]

// Reduce - 将元素合并为单个值
$sum = array_reduce($numbers, function($carry, $item) {
    return $carry + $item;
}, 0);
echo $sum; // 15

// 数组合并
$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$merged = array_merge($arr1, $arr2);
print_r($merged); // [1, 2, 3, 4, 5, 6]

// 数组切片
$slice = array_slice($numbers, 1, 3); // 从索引1开始,取3个元素
print_r($slice); // [2, 3, 4]

// 数组分块
$chunks = array_chunk($numbers, 2);
print_r($chunks); // [[1, 2], [3, 4], [5]]

// 数组键和值
$person = ["name" => "张三", "age" => 30, "city" => "北京"];
$keys = array_keys($person);     // ["name", "age", "city"]
$values = array_values($person); // ["张三", 30, "北京"]

// 翻转键和值
$flipped = array_flip($person);
print_r($flipped); // ["张三" => "name", 30 => "age", "北京" => "city"]
?>

高级数组技术

php
<?php
// 数组遍历 - 对每个元素应用函数
$fruits = ["apple", "banana", "orange"];

array_walk($fruits, function(&$fruit, $key) {
    $fruit = strtoupper($fruit);
});
print_r($fruits); // ["APPLE", "BANANA", "ORANGE"]

// 数组列提取 - 从多维数组中提取列
$users = [
    ["id" => 1, "name" => "张三", "email" => "zhangsan@example.com"],
    ["id" => 2, "name" => "李四", "email" => "lisi@example.com"],
    ["id" => 3, "name" => "王五", "email" => "wangwu@example.com"]
];

$names = array_column($users, "name");
print_r($names); // ["张三", "李四", "王五"]

$emailsById = array_column($users, "email", "id");
print_r($emailsById); // [1 => "zhangsan@example.com", 2 => "lisi@example.com", ...]

// 数组组合 - 使用一个数组作为键,另一个作为值来创建数组
$keys = ["name", "age", "city"];
$values = ["张三", 30, "北京"];
$combined = array_combine($keys, $values);
print_r($combined); // ["name" => "张三", "age" => 30, "city" => "北京"]

// 数组交集和差集
$array1 = [1, 2, 3, 4, 5];
$array2 = [3, 4, 5, 6, 7];

$intersection = array_intersect($array1, $array2); // [3, 4, 5]
$difference = array_diff($array1, $array2);        // [1, 2]

// 唯一值
$duplicates = [1, 2, 2, 3, 3, 3, 4];
$unique = array_unique($duplicates);
print_r($unique); // [1, 2, 3, 4]
?>

对象基础

类定义和实例化

php
<?php
// 基本类定义
class Person {
    // 属性(特性)
    public $name;
    public $age;
    public $email;
    
    // 构造函数
    public function __construct($name, $age, $email) {
        $this->name = $name;
        $this->age = $age;
        $this->email = $email;
    }
    
    // 方法(函数)
    public function introduce() {
        return "你好,我是{$this->name},今年{$this->age}岁。";
    }
    
    public function getEmail() {
        return $this->email;
    }
    
    public function setEmail($email) {
        if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $this->email = $email;
            return true;
        }
        return false;
    }
}

// 创建对象(实例化)
$person1 = new Person("小红", 25, "xiaohong@example.com");
$person2 = new Person("小明", 30, "xiaoming@example.com");

// 使用对象
echo $person1->introduce(); // "你好,我是小红,今年25岁。"
echo $person1->name;        // "小红"

$person1->setEmail("xiaohong.new@example.com");
echo $person1->getEmail();  // "xiaohong.new@example.com"
?>

属性可见性

php
<?php
class BankAccount {
    public $accountNumber;    // 可从任何地方访问
    protected $balance;       // 可从此类和子类访问
    private $pin;            // 仅可从此类访问
    
    public function __construct($accountNumber, $initialBalance, $pin) {
        $this->accountNumber = $accountNumber;
        $this->balance = $initialBalance;
        $this->pin = $pin;
    }
    
    public function getBalance() {
        return $this->balance;
    }
    
    public function deposit($amount) {
        if ($amount > 0) {
            $this->balance += $amount;
            return true;
        }
        return false;
    }
    
    public function withdraw($amount, $enteredPin) {
        if ($this->validatePin($enteredPin) && $amount > 0 && $amount <= $this->balance) {
            $this->balance -= $amount;
            return true;
        }
        return false;
    }
    
    private function validatePin($enteredPin) {
        return $this->pin === $enteredPin;
    }
    
    protected function calculateInterest($rate) {
        return $this->balance * $rate;
    }
}

$account = new BankAccount("12345", 1000, "1234");

echo $account->accountNumber;  // 正常(public)
echo $account->getBalance();   // 正常(public 方法)

// 这些会导致错误:
// echo $account->balance;     // 错误(protected)
// echo $account->pin;         // 错误(private)
// $account->validatePin("1234"); // 错误(private 方法)
?>

静态属性和方法

php
<?php
class Counter {
    private static $count = 0;
    public static $instances = [];
    
    public $id;
    
    public function __construct() {
        self::$count++;
        $this->id = self::$count;
        self::$instances[] = $this;
    }
    
    public static function getCount() {
        return self::$count;
    }
    
    public static function resetCount() {
        self::$count = 0;
        self::$instances = [];
    }
    
    public function getId() {
        return $this->id;
    }
}

// 使用静态方法和属性
echo Counter::getCount(); // 0

$counter1 = new Counter();
$counter2 = new Counter();
$counter3 = new Counter();

echo Counter::getCount(); // 3
echo $counter2->getId();  // 2

print_r(Counter::$instances); // Array of Counter objects

Counter::resetCount();
echo Counter::getCount(); // 0
?>

魔术方法

php
<?php
class MagicExample {
    private $data = [];
    
    // 构造函数和析构函数
    public function __construct($initialData = []) {
        $this->data = $initialData;
        echo "对象已创建\n";
    }
    
    public function __destruct() {
        echo "对象已销毁\n";
    }
    
    // 属性访问
    public function __get($name) {
        return $this->data[$name] ?? null;
    }
    
    public function __set($name, $value) {
        $this->data[$name] = $value;
    }
    
    public function __isset($name) {
        return isset($this->data[$name]);
    }
    
    public function __unset($name) {
        unset($this->data[$name]);
    }
    
    // 方法调用
    public function __call($method, $args) {
        echo "调用方法 '$method',参数:" . implode(', ', $args) . "\n";
    }
    
    public static function __callStatic($method, $args) {
        echo "调用静态方法 '$method',参数:" . implode(', ', $args) . "\n";
    }
    
    // 字符串转换
    public function __toString() {
        return json_encode($this->data);
    }
    
    // 数组访问
    public function __invoke($arg) {
        echo "对象作为函数调用,参数:$arg\n";
    }
}

$obj = new MagicExample(["name" => "张三"]);

// 属性访问
echo $obj->name;        // "张三"(调用 __get)
$obj->age = 30;         // 调用 __set
echo isset($obj->age);  // true(调用 __isset)

// 方法调用
$obj->nonExistentMethod("arg1", "arg2"); // 调用 __call

// 字符串转换
echo $obj; // 调用 __toString,输出JSON

// 函数调用
$obj("hello"); // 调用 __invoke
?>

面向对象编程概念

继承

php
<?php
// 基类
class Animal {
    protected $name;
    protected $species;
    
    public function __construct($name, $species) {
        $this->name = $name;
        $this->species = $species;
    }
    
    public function getName() {
        return $this->name;
    }
    
    public function getSpecies() {
        return $this->species;
    }
    
    public function makeSound() {
        return "一些通用动物声音";
    }
    
    public function sleep() {
        return "{$this->name}在睡觉";
    }
}

// 派生类
class Dog extends Animal {
    private $breed;
    
    public function __construct($name, $breed) {
        parent::__construct($name, "犬科");
        $this->breed = $breed;
    }
    
    public function makeSound() {
        return "汪!汪!";
    }
    
    public function fetch() {
        return "{$this->name}在捕球";
    }
    
    public function getBreed() {
        return $this->breed;
    }
}

class Cat extends Animal {
    public function __construct($name) {
        parent::__construct($name, "猫科");
    }
    
    public function makeSound() {
        return "喘!";
    }
    
    public function purr() {
        return "{$this->name}在咕咕叫";
    }
}

// 使用
$dog = new Dog("小白", "金毛寻回犬");
$cat = new Cat("胡须");

echo $dog->getName();     // "小白"
echo $dog->makeSound();   // "汪!汪!"
echo $dog->fetch();       // "小白在捕球"
echo $dog->getBreed();    // "金毛寻回犬"

echo $cat->getName();     // "胡须"
echo $cat->makeSound();   // "喘!"
echo $cat->purr();        // "胡须在咕咕叫"

// 多态性
$animals = [$dog, $cat];
foreach ($animals as $animal) {
    echo $animal->getName() . " 说:" . $animal->makeSound() . "\n";
}
?>

抽象类和接口

php
<?php
// 抽象类
abstract class Shape {
    protected $color;
    
    public function __construct($color) {
        $this->color = $color;
    }
    
    public function getColor() {
        return $this->color;
    }
    
    // 抽象方法 - 必须由子类实现
    abstract public function calculateArea();
    abstract public function calculatePerimeter();
}

// 接口
interface Drawable {
    public function draw();
}

interface Resizable {
    public function resize($factor);
}

// 具体类
class Circle extends Shape implements Drawable, Resizable {
    private $radius;
    
    public function __construct($color, $radius) {
        parent::__construct($color);
        $this->radius = $radius;
    }
    
    public function calculateArea() {
        return pi() * $this->radius * $this->radius;
    }
    
    public function calculatePerimeter() {
        return 2 * pi() * $this->radius;
    }
    
    public function draw() {
        return "绘制一个{$this->color}的圆,半径为{$this->radius}";
    }
    
    public function resize($factor) {
        $this->radius *= $factor;
    }
}

class Rectangle extends Shape implements Drawable {
    private $width;
    private $height;
    
    public function __construct($color, $width, $height) {
        parent::__construct($color);
        $this->width = $width;
        $this->height = $height;
    }
    
    public function calculateArea() {
        return $this->width * $this->height;
    }
    
    public function calculatePerimeter() {
        return 2 * ($this->width + $this->height);
    }
    
    public function draw() {
        return "绘制一个{$this->color}的矩形({$this->width}x{$this->height})";
    }
}

// 使用
$circle = new Circle("红色", 5);
$rectangle = new Rectangle("蓝色", 4, 6);

echo $circle->draw();                    // "绘制一个红色的圆,半径为5"
echo "面积:" . $circle->calculateArea(); // 面积:78.54

$circle->resize(2);
echo "新面积:" . $circle->calculateArea(); // 新面积:314.16

// 使用接口的多态性
$shapes = [$circle, $rectangle];
foreach ($shapes as $shape) {
    if ($shape instanceof Drawable) {
        echo $shape->draw() . "\n";
    }
}
?>

特征

php
<?php
// 特征 - 可重用的代码块
trait Timestampable {
    private $createdAt;
    private $updatedAt;
    
    public function setCreatedAt($timestamp = null) {
        $this->createdAt = $timestamp ?: date('Y-m-d H:i:s');
    }
    
    public function setUpdatedAt($timestamp = null) {
        $this->updatedAt = $timestamp ?: date('Y-m-d H:i:s');
    }
    
    public function getCreatedAt() {
        return $this->createdAt;
    }
    
    public function getUpdatedAt() {
        return $this->updatedAt;
    }
}

trait Validatable {
    private $errors = [];
    
    public function addError($field, $message) {
        $this->errors[$field][] = $message;
    }
    
    public function getErrors() {
        return $this->errors;
    }
    
    public function hasErrors() {
        return !empty($this->errors);
    }
    
    public function clearErrors() {
        $this->errors = [];
    }
}

// 使用特征
class User {
    use Timestampable, Validatable;
    
    private $name;
    private $email;
    
    public function __construct($name, $email) {
        $this->name = $name;
        $this->email = $email;
        $this->setCreatedAt();
        $this->validate();
    }
    
    private function validate() {
        if (empty($this->name)) {
            $this->addError('name', '姓名是必需的');
        }
        
        if (!filter_var($this->email, FILTER_VALIDATE_EMAIL)) {
            $this->addError('email', '邮箱格式无效');
        }
    }
    
    public function getName() {
        return $this->name;
    }
    
    public function getEmail() {
        return $this->email;
    }
    
    public function setName($name) {
        $this->name = $name;
        $this->setUpdatedAt();
        $this->validate();
    }
}

$user = new User("张三", "zhangsan@example.com");

echo "创建时间:" . $user->getCreatedAt();
echo "是否有错误:" . ($user->hasErrors() ? '是' : '否');

$user->setName("");
if ($user->hasErrors()) {
    print_r($user->getErrors());
}
?>

处理复杂数据结构

嵌套数组和对象

php
<?php
// 复杂嵌套结构
$company = [
    "name" => "科技公司",
    "founded" => 2010,
    "departments" => [
        "engineering" => [
            "manager" => "张经理",
            "employees" => [
                ["name" => "李开发", "role" => "高级开发工程师", "salary" => 90000],
                ["name" => "王设计", "role" => "初级开发工程师", "salary" => 60000],
                ["name" => "赵运维", "role" => "DevOps工程师", "salary" => 85000]
            ]
        ],
        "marketing" => [
            "manager" => "刘营销",
            "employees" => [
                ["name" => "陈经理", "role" => "营销经理", "salary" => 75000],
                ["name" => "孙创作", "role" => "内容创作者", "salary" => 55000]
            ]
        ]
    ]
];

// 访问嵌套数据
echo $company["name"]; // "科技公司"
echo $company["departments"]["engineering"]["manager"]; // "张经理"
echo $company["departments"]["engineering"]["employees"][0]["name"]; // "李开发"

// 处理嵌套数据
function calculateDepartmentPayroll($department) {
    $total = 0;
    foreach ($department["employees"] as $employee) {
        $total += $employee["salary"];
    }
    return $total;
}

function getCompanyStats($company) {
    $stats = [
        "total_employees" => 0,
        "total_payroll" => 0,
        "departments" => []
    ];
    
    foreach ($company["departments"] as $deptName => $department) {
        $employeeCount = count($department["employees"]);
        $payroll = calculateDepartmentPayroll($department);
        
        $stats["departments"][$deptName] = [
            "manager" => $department["manager"],
            "employee_count" => $employeeCount,
            "payroll" => $payroll
        ];
        
        $stats["total_employees"] += $employeeCount;
        $stats["total_payroll"] += $payroll;
    }
    
    return $stats;
}

$stats = getCompanyStats($company);
print_r($stats);
?>

数组和对象的相互转换

php
<?php
// 数组到对象的转换
$array = [
    "name" => "张三",
    "age" => 30,
    "address" => [
        "street" => "主干道123号",
        "city" => "北京"
    ]
];

// 简单转换(浅层)
$obj = (object) $array;
echo $obj->name; // "张三"
echo $obj->address["street"]; // "主干道123号"(仍然是数组)

// 深度转换函数
function arrayToObject($array) {
    if (is_array($array)) {
        $obj = new stdClass();
        foreach ($array as $key => $value) {
            $obj->$key = arrayToObject($value);
        }
        return $obj;
    }
    return $array;
}

$deepObj = arrayToObject($array);
echo $deepObj->name; // "张三"
echo $deepObj->address->street; // "主干道123号"(现在是对象属性)

// 对象到数组的转换
function objectToArray($obj) {
    if (is_object($obj)) {
        $array = [];
        foreach (get_object_vars($obj) as $key => $value) {
            $array[$key] = objectToArray($value);
        }
        return $array;
    }
    return $obj;
}

$backToArray = objectToArray($deepObj);
print_r($backToArray);

// JSON转换(处理嵌套结构)
$jsonString = json_encode($array);
$objFromJson = json_decode($jsonString); // 对象
$arrayFromJson = json_decode($jsonString, true); // 数组
?>

数据操作模式

php
<?php
// 数据管理的仓库模式
class UserRepository {
    private $users = [];
    
    public function add($user) {
        $this->users[] = $user;
    }
    
    public function findById($id) {
        foreach ($this->users as $user) {
            if ($user['id'] === $id) {
                return $user;
            }
        }
        return null;
    }
    
    public function findByEmail($email) {
        return array_filter($this->users, function($user) use ($email) {
            return $user['email'] === $email;
        });
    }
    
    public function update($id, $data) {
        foreach ($this->users as &$user) {
            if ($user['id'] === $id) {
                $user = array_merge($user, $data);
                return true;
            }
        }
        return false;
    }
    
    public function delete($id) {
        foreach ($this->users as $index => $user) {
            if ($user['id'] === $id) {
                unset($this->users[$index]);
                $this->users = array_values($this->users); // Reindex
                return true;
            }
        }
        return false;
    }
    
    public function getAll() {
        return $this->users;
    }
    
    public function filter($callback) {
        return array_filter($this->users, $callback);
    }
    
    public function map($callback) {
        return array_map($callback, $this->users);
    }
}

// Usage
$repo = new UserRepository();

$repo->add(['id' => 1, 'name' => '张三', 'email' => 'zhangsan@example.com', 'active' => true]);
$repo->add(['id' => 2, 'name' => '李四', 'email' => 'lisi@example.com', 'active' => false]);
$repo->add(['id' => 3, 'name' => '王五', 'email' => 'wangwu@example.com', 'active' => true]);

// 查找操作
$user = $repo->findById(2);
echo "找到用户:" . $user['name'];

$activeUsers = $repo->filter(function($user) {
    return $user['active'];
});
echo "活跃用户数:" . count($activeUsers);

// 转换数据
$userNames = $repo->map(function($user) {
    return $user['name'];
});
print_r($userNames); // ['张三', '李四', '王五']

// 更新和删除
$repo->update(2, ['active' => true]);
$repo->delete(3);

print_r($repo->getAll());
?>

下一步

现在您已经了解了数组和对象,让我们在API和接口中探索API和接口。

实践练习

  1. 使用数组和对象创建一个购物车系统
  2. 构建一个具有CRUD操作的简单数据库系统
  3. 为不同类型的车辆实现一个类层次结构
  4. 使用数组函数创建一个数据处理管道
  5. 使用嵌套数组构建一个配置管理系统

理解数组和对象是构建复杂PHP应用程序的基础!

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