PHP高级特性

探索PHP的高级功能与技术

面向对象编程 (OOP)

PHP 5及以上版本提供了完整的面向对象编程功能,包括类、接口、抽象类、继承、多态等特性。

类与对象

类是创建对象的模板,对象是类的实例。

<?php
    // 定义类
    class Person {
        // 属性
        public $name;
        protected $age;
        private $salary;
        
        // 构造函数
        public function __construct($name, $age, $salary) {
            $this->name = $name;
            $this->age = $age;
            $this->salary = $salary;
        }
        
        // 方法
        public function sayHello() {
            return "你好,我是 {$this->name},今年 {$this->age} 岁。";
        }
        
        // 获取私有属性的方法
        public function getSalary() {
            return $this->salary;
        }
    }
    
    // 创建对象
    $person = new Person("张三", 30, 10000);
    
    // 访问公共属性
    echo $person->name;  // 输出:张三
    
    // 调用方法
    echo $person->sayHello();  // 输出:你好,我是 张三,今年 30 岁。
    
    // 通过方法访问私有属性
    echo $person->getSalary();  // 输出:10000
?>

继承

继承允许子类继承父类的属性和方法。

<?php
    // 父类
    class Employee {
        protected $name;
        protected $salary;
        
        public function __construct($name, $salary) {
            $this->name = $name;
            $this->salary = $salary;
        }
        
        public function getInfo() {
            return "员工: {$this->name}, 薪水: {$this->salary}";
        }
    }
    
    // 子类
    class Manager extends Employee {
        private $bonus;
        
        public function __construct($name, $salary, $bonus) {
            parent::__construct($name, $salary);
            $this->bonus = $bonus;
        }
        
        // 重写父类方法
        public function getInfo() {
            return "经理: {$this->name}, 薪水: {$this->salary}, 奖金: {$this->bonus}";
        }
    }
    
    $manager = new Manager("李四", 20000, 5000);
    echo $manager->getInfo();  // 输出:经理: 李四, 薪水: 20000, 奖金: 5000
?>

接口与抽象类

<?php
    // 接口
    interface Drawable {
        public function draw();
    }
    
    // 抽象类
    abstract class Shape {
        protected $color;
        
        public function __construct($color) {
            $this->color = $color;
        }
        
        // 抽象方法
        abstract public function getArea();
        
        public function getColor() {
            return $this->color;
        }
    }
    
    // 实现抽象类和接口
    class Circle extends Shape implements Drawable {
        private $radius;
        
        public function __construct($color, $radius) {
            parent::__construct($color);
            $this->radius = $radius;
        }
        
        public function getArea() {
            return pi() * $this->radius * $this->radius;
        }
        
        public function draw() {
            return "绘制一个 {$this->color} 的圆,半径为 {$this->radius}";
        }
    }
    
    $circle = new Circle("红色", 5);
    echo $circle->getArea();  // 输出:78.539816339745
    echo $circle->draw();     // 输出:绘制一个 红色 的圆,半径为 5
?>

命名空间

命名空间用于解决类名、函数名和常量名冲突的问题。

<?php
    // file1.php
    namespace App\Models;
    
    class User {
        public function __construct() {
            echo "App\\Models\\User 被实例化";
        }
    }
    
    // file2.php
    namespace App\Controllers;
    
    class User {
        public function __construct() {
            echo "App\\Controllers\\User 被实例化";
        }
    }
    
    // file3.php
    namespace App;
    
    // 使用完全限定名称
    $user1 = new Models\User();
    $user2 = new Controllers\User();
    
    // 或者使用use语句
    use App\Models\User as ModelUser;
    use App\Controllers\User as ControllerUser;
    
    $user3 = new ModelUser();
    $user4 = new ControllerUser();
?>

PHP 8.1新特性

PHP 8.1引入了许多新功能和改进,为开发者提供了更多的工具和可能性。

枚举类型(Enumerations)

枚举类型提供了一种定义有限集合值的方式。

<?php
    enum Status {
        case Pending;
        case Active;
        case Suspended;
        case Cancelled;
    }
    
    function updateStatus(Status $status) {
        // 处理不同状态
        return match($status) {
            Status::Pending => '待处理',
            Status::Active => '已激活',
            Status::Suspended => '已暂停',
            Status::Cancelled => '已取消',
        };
    }
    
    $status = Status::Active;
    echo updateStatus($status);  // 输出:已激活
    
    // 带值的枚举
    enum Currency: string {
        case Euro = "EUR";
        case Dollar = "USD";
        case Yuan = "CNY";
        
        public function getSymbol(): string {
            return match($this) {
                self::Euro => "€",
                self::Dollar => "$",
                self::Yuan => "¥",
            };
        }
    }
    
    $currency = Currency::Yuan;
    echo $currency->value;        // 输出:CNY
    echo $currency->getSymbol();  // 输出:¥
?>

只读属性(Readonly Properties)

只读属性允许类属性在初始化后不可修改。

<?php
    class User {
        public readonly string $name;
        public readonly string $email;
        
        public function __construct(string $name, string $email) {
            $this->name = $name;
            $this->email = $email;
        }
    }
    
    $user = new User("张三", "zhangsan@example.com");
    echo $user->name;  // 输出:张三
    
    // 以下代码会产生错误
    // $user->name = "李四";  // Fatal error: Cannot modify readonly property User::$name
?>

纤程(Fibers)

纤程提供了一种轻量级的协程实现,使异步编程更加简单。

<?php
    $fiber = new Fiber(function(): void {
        $value = Fiber::suspend('fiber suspended');
        echo "Value used to resume fiber: ", $value, "\n";
    });
    
    $value = $fiber->start();
    echo "Fiber suspended with value: ", $value, "\n";
    $fiber->resume('fiber resumed');
    
    // 输出:
    // Fiber suspended with value: fiber suspended
    // Value used to resume fiber: fiber resumed
?>

新的初始化方法

PHP 8.1允许在定义属性时直接初始化。

<?php
    class Product {
        public string $name = "默认产品";
        public float $price = 0.0;
        public array $tags = ["新品"];
        
        public function __construct(string $name = null, float $price = null) {
            if ($name !== null) {
                $this->name = $name;
            }
            
            if ($price !== null) {
                $this->price = $price;
            }
        }
    }
    
    $product1 = new Product();
    echo $product1->name;  // 输出:默认产品
    
    $product2 = new Product("手机", 1999.99);
    echo $product2->name;  // 输出:手机
?>

PHP中的设计模式实战应用

设计模式是解决特定问题的可复用方案,掌握常见的设计模式可以提高代码质量和可维护性。

单例模式(Singleton Pattern)

确保一个类只有一个实例,并提供一个全局访问点。

<?php
    class Database {
        private static $instance = null;
        private $connection;
        
        // 私有构造函数,防止外部实例化
        private function __construct() {
            $this->connection = new PDO("mysql:host=localhost;dbname=test", "username", "password");
        }
        
        // 获取单例实例
        public static function getInstance() {
            if (self::$instance === null) {
                self::$instance = new self();
            }
            return self::$instance;
        }
        
        public function query($sql) {
            return $this->connection->query($sql);
        }
        
        // 防止克隆
        private function __clone() {}
        
        // 防止反序列化
        private function __wakeup() {}
    }
    
    // 使用
    $db1 = Database::getInstance();
    $db2 = Database::getInstance();
    
    // $db1 和 $db2 是同一个实例
    var_dump($db1 === $db2);  // 输出:bool(true)
?>

工厂模式(Factory Pattern)

提供一个创建对象的接口,但允许子类决定实例化的类。

<?php
    // 产品接口
    interface Vehicle {
        public function drive();
    }
    
    // 具体产品
    class Car implements Vehicle {
        public function drive() {
            return "驾驶汽车...";
        }
    }
    
    class Bike implements Vehicle {
        public function drive() {
            return "骑自行车...";
        }
    }
    
    class Truck implements Vehicle {
        public function drive() {
            return "驾驶卡车...";
        }
    }
    
    // 工厂类
    class VehicleFactory {
        public static function createVehicle($type) {
            switch ($type) {
                case 'car':
                    return new Car();
                case 'bike':
                    return new Bike();
                case 'truck':
                    return new Truck();
                default:
                    throw new Exception("未知的车辆类型: {$type}");
            }
        }
    }
    
    // 使用
    $car = VehicleFactory::createVehicle('car');
    echo $car->drive();  // 输出:驾驶汽车...
    
    $bike = VehicleFactory::createVehicle('bike');
    echo $bike->drive();  // 输出:骑自行车...
?>

观察者模式(Observer Pattern)

定义对象间一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会收到通知。

<?php
    // 观察者接口
    interface Observer {
        public function update(string $message);
    }
    
    // 具体观察者
    class EmailNotifier implements Observer {
        private $email;
        
        public function __construct(string $email) {
            $this->email = $email;
        }
        
        public function update(string $message) {
            echo "向 {$this->email} 发送邮件通知: {$message}\n";
        }
    }
    
    class SMSNotifier implements Observer {
        private $phone;
        
        public function __construct(string $phone) {
            $this->phone = $phone;
        }
        
        public function update(string $message) {
            echo "向 {$this->phone} 发送短信通知: {$message}\n";
        }
    }
    
    // 主题
    class OrderStatus {
        private $observers = [];
        private $status;
        
        public function attach(Observer $observer) {
            $this->observers[] = $observer;
        }
        
        public function detach(Observer $observer) {
            $key = array_search($observer, $this->observers, true);
            if ($key !== false) {
                unset($this->observers[$key]);
            }
        }
        
        public function setStatus(string $status) {
            $this->status = $status;
            $this->notify();
        }
        
        private function notify() {
            foreach ($this->observers as $observer) {
                $observer->update("订单状态已更新为: {$this->status}");
            }
        }
    }
    
    // 使用
    $orderStatus = new OrderStatus();
    
    $emailNotifier = new EmailNotifier("customer@example.com");
    $smsNotifier = new SMSNotifier("13800138000");
    
    $orderStatus->attach($emailNotifier);
    $orderStatus->attach($smsNotifier);
    
    $orderStatus->setStatus("已发货");
    // 输出:
    // 向 customer@example.com 发送邮件通知: 订单状态已更新为: 已发货
    // 向 13800138000 发送短信通知: 订单状态已更新为: 已发货
?>

Composer依赖管理

Composer是PHP的依赖管理工具,它允许你声明项目所依赖的库,并自动帮你安装和更新它们。

Composer基本使用

  1. 安装Composer

    在Windows上,下载并运行Composer-Setup.exe。在Linux/Mac上,使用命令行安装:

    curl -sS https://getcomposer.org/installer | php
    sudo mv composer.phar /usr/local/bin/composer
  2. 创建composer.json文件

    {
        "name": "vendor/project-name",
        "description": "项目描述",
        "type": "project",
        "require": {
            "monolog/monolog": "^2.0",
            "guzzlehttp/guzzle": "^7.0"
        },
        "require-dev": {
            "phpunit/phpunit": "^9.0"
        },
        "autoload": {
            "psr-4": {
                "App\\": "src/"
            }
        }
    }
  3. 安装依赖

    composer install
  4. 添加新依赖

    composer require symfony/console
  5. 更新依赖

    composer update

使用自动加载

Composer生成的自动加载器使得你可以轻松加载项目中的类:

<?php
    // 加载自动加载器
    require 'vendor/autoload.php';
    
    // 现在可以直接使用Composer安装的库
    use Monolog\Logger;
    use Monolog\Handler\StreamHandler;
    
    // 创建日志频道
    $log = new Logger('name');
    $log->pushHandler(new StreamHandler('app.log', Logger::WARNING));
    
    // 添加记录
    $log->warning('警告信息');
    $log->error('错误信息');
?>

提示:Composer已成为PHP项目的标准工具,几乎所有现代PHP项目都使用Composer进行依赖管理。

PHP安全最佳实践

保护PHP应用程序安全是每个开发者的责任。以下是一些安全最佳实践:

防止SQL注入

不安全的代码:

<?php
    $username = $_POST['username'];
    $query = "SELECT * FROM users WHERE username = '$username'";
    $result = $db->query($query);
?>

安全的代码:

<?php
    // 使用预处理语句
    $stmt = $db->prepare("SELECT * FROM users WHERE username = ?");
    $stmt->bind_param("s", $_POST['username']);
    $stmt->execute();
    $result = $stmt->get_result();
    
    // 或使用PDO
    $stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
    $stmt->execute(['username' => $_POST['username']]);
    $result = $stmt->fetchAll();
?>

防止XSS攻击

不安全的代码:

<?php
    echo "欢迎, " . $_GET['name'];
?>

安全的代码:

<?php
    echo "欢迎, " . htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');
?>

防止CSRF攻击

在表单中添加CSRF令牌,并在提交表单时验证:

<?php
    // 在会话中存储令牌
    session_start();
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    
    // 在表单中包含令牌
    echo '<form method="post">';
    echo '<input type="hidden" name="csrf_token" value="' . $_SESSION['csrf_token'] . '">';
    echo '<!-- 其他表单字段 -->';
    echo '</form>';
    
    // 验证令牌
    if ($_SERVER['REQUEST_METHOD'] == 'POST') {
        if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
            die('CSRF令牌验证失败');
        }
        // 处理表单提交
    }
?>

安全配置