PHP高级特性

学习PHP命名空间、Traits、生成器等高级特性

PHP高级特性概述

PHP不断演进,引入了许多强大的高级特性,使开发更加高效、代码更加优雅。本教程将介绍PHP 7和PHP 8引入的一些重要高级特性。

版本要求: 本教程中的大部分特性需要PHP 7.0或更高版本,部分特性需要PHP 8.0或更高版本。

命名空间 (Namespaces)

命名空间是PHP 5.3引入的重要特性,用于解决代码命名冲突问题,特别是在使用第三方库时。

命名空间基本用法

命名空间示例
<?php
// 定义命名空间
namespace MyProject\Database;

class Connection {
    public function connect() {
        echo "数据库连接已建立\n";
    }
}

function logMessage($message) {
    echo "日志: $message\n";
}

// 使用完全限定名称
$conn = new \MyProject\Database\Connection();
$conn->connect();

// 或者使用use关键字
use MyProject\Database\Connection;
use function MyProject\Database\logMessage;

$conn2 = new Connection();
logMessage("测试消息");
?>

命名空间别名

命名空间别名示例
<?php
namespace MyProject\Utilities;

class Logger {
    public function log($message) {
        echo "记录: $message\n";
    }
}

// 使用别名
use MyProject\Utilities\Logger as MyLogger;

$logger = new MyLogger();
$logger->log("使用别名的日志");
?>

全局命名空间

全局命名空间示例
<?php
namespace MyProject;

// 访问全局命名空间中的类
$datetime = new \DateTime();
$exception = new \Exception("错误消息");

// 全局命名空间中的函数
$length = \strlen("Hello World");
?>

Traits

Traits是PHP 5.4引入的代码复用机制,可以在不同类之间复用方法,解决了PHP单继承的限制。

Trait基本用法

Trait示例
<?php
// 定义Trait
trait Loggable {
    public function log($message) {
        echo "[" . date('Y-m-d H:i:s') . "] $message\n";
    }
}

trait Serializable {
    public function serialize() {
        return serialize(get_object_vars($this));
    }
    
    public function unserialize($data) {
        $vars = unserialize($data);
        foreach ($vars as $key => $value) {
            $this->$key = $value;
        }
    }
}

// 使用多个Traits
class User {
    use Loggable, Serializable;
    
    private $name;
    private $email;
    
    public function __construct($name, $email) {
        $this->name = $name;
        $this->email = $email;
        $this->log("创建用户: $name");
    }
}

$user = new User("张三", "zhangsan@example.com");
$serialized = $user->serialize();
echo "序列化数据: $serialized\n";
?>

Trait冲突解决

Trait冲突解决示例
<?php
trait A {
    public function smallTalk() {
        echo "a";
    }
    
    public function bigTalk() {
        echo "A";
    }
}

trait B {
    public function smallTalk() {
        echo "b";
    }
    
    public function bigTalk() {
        echo "B";
    }
}

class Talker {
    use A, B {
        B::smallTalk insteadof A;  // 使用B的smallTalk而不是A的
        A::bigTalk insteadof B;    // 使用A的bigTalk而不是B的
        B::bigTalk as talk;        // 给B的bigTalk起别名
    }
}

$talker = new Talker();
$talker->smallTalk(); // 输出 "b"
$talker->bigTalk();   // 输出 "A"
$talker->talk();     // 输出 "B"
?>

Trait中的抽象方法

Trait抽象方法示例
<?php
trait Renderable {
    abstract public function getData();
    
    public function render() {
        $data = $this->getData();
        echo "渲染数据: " . json_encode($data);
    }
}

class Product {
    use Renderable;
    
    private $name, $price;
    
    public function __construct($name, $price) {
        $this->name = $name;
        $this->price = $price;
    }
    
    public function getData() {
        return [
            'name' => $this->name,
            'price' => $this->price
        ];
    }
}

$product = new Product("笔记本电脑", 5999);
$product->render();
?>

生成器 (Generators)

生成器是PHP 5.5引入的强大特性,可以让你以简单的方式实现迭代器,无需实现完整的Iterator接口。

生成器基本用法

生成器示例
<?php
// 简单的生成器函数
function xrange($start, $limit, $step = 1) {
    if ($start < $limit) {
        if ($step <= 0) {
            throw new LogicException('步长必须为正数');
        }
        
        for ($i = $start; $i <= $limit; $i += $step) {
            yield $i;
        }
    } else {
        if ($step >= 0) {
            throw new LogicException('步长必须为负数');
        }
        
        for ($i = $start; $i >= $limit; $i += $step) {
            yield $i;
        }
    }
}

// 使用生成器
echo "单数: ";
foreach (xrange(1, 9, 2) as $number) {
    echo "$number ";
}

echo "\n倒数: ";
foreach (xrange(5, 1, -1) as $number) {
    echo "$number ";
}
?>

生成器与键值对

键值对生成器示例
<?php
// 生成键值对
function inputParser($input) {
    $lines = explode("\n", $input);
    
    foreach ($lines as $lineNumber => $line) {
        $trimmed = trim($line);
        if (empty($trimmed)) {
            continue;
        }
        
        yield $lineNumber => $trimmed;
    }
}

$input = "
name=张三
age=25
email=zhangsan@example.com
";

foreach (inputParser($input) as $lineNumber => $line) {
    echo "第$lineNumber行: $line\n";
}
?>

生成器委托

生成器委托示例
<?php
// 生成器委托 (PHP 7.0+)
function countToTen() {
    yield 1;
    yield 2;
    yield from [3, 4];
    yield from fiveToSeven();
    yield 8;
    yield 9;
    yield 10;
}

function fiveToSeven() {
    yield 5;
    yield 6;
    yield 7;
}

foreach (countToTen() as $number) {
    echo "$number ";
}
?>

PHP 8新特性

PHP 8引入了许多令人兴奋的新特性,使代码更加简洁和高效。

命名参数

命名参数示例
<?php
function createUser($name, $age = 0, $email = "", $phone = "") {
    return [
        'name' => $name,
        'age' => $age,
        'email' => $email,
        'phone' => $phone
    ];
}

// 传统方式 - 必须按顺序传递所有参数
$user1 = createUser("张三", 25, "", "13800138000");

// 使用命名参数 - 可以跳过可选参数
$user2 = createUser(
    name: "李四",
    phone: "13900139000",
    age: 30
);

print_r($user1);
print_r($user2);
?>

属性(Attributes)

属性示例
<?php
// 定义属性
class Route {
    public function __construct(
        public $path,
        public $methods = ['GET']
    ) {}
}

// 使用属性
#[Route('/users', ['GET'])]
class UserController {
    #[Route('/users/{id}', ['GET'])]
    public function show($id) {
        return "显示用户 $id";
    }
    
    #[Route('/users', ['POST'])]
    public function store() {
        return "创建用户";
    }
}

// 反射获取属性信息
$reflection = new ReflectionClass('UserController');
$attributes = $reflection->getAttributes();

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    echo "控制器路由: {$instance->path}\n";
}
?>

Match表达式

Match表达式示例
<?php
$statusCode = 404;

// 传统的switch语句
switch ($statusCode) {
    case 200:
        $message = 'OK';
        break;
    case 404:
        $message = 'Not Found';
        break;
    case 500:
        $message = 'Server Error';
        break;
    default:
        $message = 'Unknown';
}

// 使用match表达式(更简洁)
$message = match ($statusCode) {
    200 => 'OK',
    404 => 'Not Found',
    500 => 'Server Error',
    default => 'Unknown',
};

echo "状态码 $statusCode: $message\n";

// match表达式还可以处理复杂条件
$age = 25;
$category = match (true) {
    $age < 18 => '未成年',
    $age >= 18 && $age < 60 => '成年',
    $age >= 60 => '老年',
};

echo "年龄 $age: $category\n";
?>

联合类型

联合类型示例
<?php
// 联合类型 (PHP 8.0+)
function displayValue(string|int|float $value): void {
    echo "值: $value\n";
}

displayValue("Hello");     // 字符串
displayValue(42);          // 整数
displayValue(3.14);       // 浮点数

// 可空类型 (PHP 8.0+)
function findUser(?int $id): ?string {
    if ($id === null) {
        return null;
    }
    return "用户 $id";
}

echo findUser(123) ?? "未找到";
echo "\n";
echo findUser(null) ?? "未找到";
?>

其他高级特性

匿名类

匿名类示例
<?php
// 匿名类 (PHP 7.0+)
$logger = new class {
    public function log($message) {
        echo "日志: $message\n";
    }
};

$logger->log("这是一条日志消息");

// 带构造函数的匿名类
$user = new class("张三", 25) {
    public function __construct(private $name, private $age) {}
    
    public function getInfo() {
        return "姓名: $this->name, 年龄: $this->age";
    }
};

echo $user->getInfo();
?>

返回类型声明

返回类型声明示例
<?php
// 返回类型声明 (PHP 7.0+)
function add(int $a, int $b): int {
    return $a + $b;
}

function getUsers(): array {
    return ['张三', '李四', '王五'];
}

function noReturn(): void {
    echo "这个函数没有返回值\n";
}

echo add(5, 3);
echo "\n";
print_r(getUsers());
noReturn();
?>

实践练习

尝试使用所学的高级特性完成以下练习:

练习要求

创建一个简单的用户管理系统,要求:

  • 使用命名空间组织代码
  • 使用Traits实现日志功能
  • 使用生成器遍历用户数据
  • 使用PHP 8的命名参数和match表达式
  • 使用联合类型和返回类型声明
  • 使用属性(Attributes)标记路由
提示: 可以先设计用户类,然后添加日志Trait,最后使用生成器实现数据遍历功能。