🌟 PHP 接口(Interface)完全入门指南

🌟 PHP 接口(Interface)完全入门指南

一篇让你真正"懂了"的通俗讲解


一、什么是接口?------ 它是一份"能力合同"

想象一下:你想开一家咖啡店,需要供应商提供咖啡豆。你和供应商签了一份合同,上面写着:

"你必须能提供咖啡豆、牛奶、糖,并且保证每天送货。"

这份合同不关心你是怎么种咖啡豆的 ,也不管你从哪进货------它只关心:你能不能做到这些事?

在 PHP 中,接口(Interface)就是这样的"合同"

👉 它规定:

"任何想说自己'支持我'的类,就必须实现我要求的方法!"

但它不告诉你这些方法具体怎么做。


✅ 接口怎么定义?

interface 关键字,方法都是空的(只写"要做什么",不写"怎么做"):

php 复制代码
// 定义一个"可缓存"的能力标准
interface Cacheable // 可缓存接口
{
    public function set(string $key, mixed $value): void;
    public function get(string $key): mixed;
    public function has(string $key): bool;
}

🔔 注意:

  • 接口里的方法必须是 public(默认就是 public,不用写)
  • 所有方法都不能有具体实现(不能写大括号 {} 里的内容)

二、类如何"签合同"?------ implements

一个类如果想说自己"具备缓存能力",就要用 implements 来"签字":

php 复制代码
// Redis 缓存类,声明:我支持 Cacheable 接口
class RedisCache implements Cacheable
{
    public function set(string $key, mixed $value): void
    {
        // 实际使用 Redis 客户端存储
        echo "Saving to Redis: $key\n";
    }

    public function get(string $key): mixed
    {
        // 从 Redis 获取数据
        return "data_from_redis";
    }

    public function has(string $key): bool
    {
        // 检查 Redis 是否存在该 key
        return true; // 简化示例
    }
}
php 复制代码
// 文件缓存类,也实现了同一个接口
class FileCache implements Cacheable
{
    public function set(string $key, mixed $value): void
    {
        file_put_contents("cache/$key.txt", serialize($value));
    }

    public function get(string $key): mixed
    {
        $file = "cache/$key.txt";
        return file_exists($file) ? unserialize(file_get_contents($file)) : null;
    }

    public function has(string $key): bool
    {
        return file_exists("cache/$key.txt");
    }
}

❗ 重点:一旦 implements 了某个接口,就必须实现它所有的方法,一个都不能少!否则 PHP 会报致命错误。


三、接口到底有什么用?两个核心好处

✅ 好处 1:灵活替换,不影响代码(面向接口编程)

假设你写了一个函数,用来获取用户信息:

php 复制代码
function getUserData(Cacheable $cache, int $userId)
{
    $key = "user:$userId";

    if ($cache->has($key)) {
        return $cache->get($key); // 从缓存读
    }

    $userData = fetchDataFromDatabase($userId); // 查数据库
    $cache->set($key, $userData); // 存入缓存

    return $userData;
}

注意参数类型:Cacheable $cache

👉 它只关心:你有没有 setgethas 这些能力?
不关心你是 Redis、文件,还是数据库缓存!

所以你可以这样调用:

scss 复制代码
// 用 Redis 缓存
$cache = new RedisCache();
getUserData($cache, 123);

// 换成文件缓存?没问题,代码完全不用改!
$cache = new FileCache();
getUserData($cache, 123);

💡 这就是"面向接口编程 ":

我们依赖的是"能力",而不是"具体是谁"。

就像 USB 接口,只要符合标准,U盘、鼠标、键盘都能插。


✅ 好处 2:让函数更通用,不依赖具体实现

继续上面的例子:

  • RedisCacheFileCache 是两个完全不同的类
  • 但它们都实现了 Cacheable 接口
  • 所以它们都可以当作 Cacheable 类型来使用
ini 复制代码
// $cache 的类型是 Cacheable(接口类型)
Cacheable $cache = new RedisCache();

✅ 是的!接口也是一种类型 ,就像 intstringUser 类一样。

PHP 允许你用接口来做类型声明、类型检查。


四、接口之间的继承 ------ extends

接口也可以"继承"其他接口,就像孩子继承父母的能力:

csharp 复制代码
// 在 Cacheable 基础上,增加"可清除"能力
interface AdvancedCacheable extends Cacheable
{
    public function clear(): void;
}

现在,任何实现 AdvancedCacheable 的类,必须实现:

  • set()
  • get()
  • has()
  • clear()
php 复制代码
class RedisAdvancedCache implements AdvancedCacheable
{
    public function set(string $key, mixed $value): void { /* ... */ }
    public function get(string $key): mixed { /* ... */ }
    public function has(string $key): bool { /* ... */ }
    public function clear(): void { echo "Redis cache cleared!\n"; }
}

五、接口中的常量

接口里也可以定义常量,和类常量用法一样:

ini 复制代码
interface PaymentGateway
{
    const NAME = "Payment API";
    public const SUPPORTED_CURRENCIES = ['CNY', 'USD', 'EUR'];
}

使用方式:

php 复制代码
echo PaymentGateway::NAME; // 输出: Payment API

class Alipay implements PaymentGateway
{
    public function pay() {
        echo "Using currency: " . self::SUPPORTED_CURRENCIES[0];
    }
}

⚠️ PHP 8.1 之前,子类不能覆盖接口常量;8.1+ 可以。


六、PHP 8.4 新特性:接口可以有属性!

PHP 8.4 开始,接口可以声明属性,但必须说明是"可读"、"可写"还是"可读可写":

php 复制代码
interface UserInterface
{
    public readonly string $username;     // 只读属性
    public string $email;                 // 可读可写
    public writeonly string $password;    // 只写(少见)
}

实现类可以用多种方式满足:

php 复制代码
class User implements UserInterface
{
    public readonly string $username; // 直接定义 readonly 属性
    public string $email;
    private string $pwd;

    public function __construct(string $username, string $email)
    {
        $this->username = $username;
        $this->email = $email;
    }

    // 魔术方法满足 writeonly
    public function __set(string $name, string $value): void
    {
        if ($name === 'password') {
            $this->pwd = password_hash($value, PASSWORD_DEFAULT);
        }
    }
}

❗ 注意:readonly 属性不能用于满足"可写"接口属性。


七、重要提醒

注意事项 说明
🚫 不要写构造函数 接口中不要定义 __construct(),会限制灵活性,导致不可预测行为。
✅ 参数名要一致 PHP 8.0+ 支持命名参数,建议接口和实现类的参数名保持一致。
✅ 可以实现多个接口 一个类可以 implements A, B, C
✅ 继承 + 实现顺序 class Child extends Parent implements A, B

✅ 总结一句话

接口是一种"能力类型"

它不关心"你是谁",只关心"你能做什么"。

只要实现了接口,你的对象就可以当作该接口类型来使用,实现灵活替换、通用编程。


🧠 类比记忆

现实世界 PHP 对应
USB 接口 interface USB
U盘、鼠标、键盘 class UDisk implements USB
电脑插口只认 USB 标准 function connect(USB $device)
换设备不用改电脑 实现类可替换,调用代码不变
相关推荐
BingoGo1 小时前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack1 小时前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo1 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack1 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack2 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo2 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack3 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理4 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
QQ5110082854 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php
WeiXin_DZbishe4 天前
基于django在线音乐数据采集的设计与实现-计算机毕设 附源码 22647
javascript·spring boot·mysql·django·node.js·php·html5