【PHP 接口(Interface)完全入门指南】
🌟 PHP 接口(Interface)完全入门指南
一篇让你真正“懂了”的通俗讲解
一、什么是接口?—— 它是一份“能力合同”
想象一下:你想开一家咖啡店,需要供应商提供咖啡豆。你和供应商签了一份合同,上面写着:
“你必须能提供咖啡豆、牛奶、糖,并且保证每天送货。”
这份合同不关心你是怎么种咖啡豆的,也不管你从哪进货——它只关心:你能不能做到这些事?
在 PHP 中,接口(Interface)就是这样的“合同” 。
👉 它规定:
“任何想说自己‘支持我’的类,就必须实现我要求的方法!”
但它不告诉你这些方法具体怎么做。
✅ 接口怎么定义?
用 interface
关键字,方法都是空的(只写“要做什么”,不写“怎么做”):
// 定义一个“可缓存”的能力标准
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
来“签字”:
// 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 是否存在该 keyreturn true; // 简化示例}
}
// 文件缓存类,也实现了同一个接口
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:灵活替换,不影响代码(面向接口编程)
假设你写了一个函数,用来获取用户信息:
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
👉 它只关心:你有没有 set
、get
、has
这些能力?
不关心你是 Redis、文件,还是数据库缓存!
所以你可以这样调用:
// 用 Redis 缓存
$cache = new RedisCache();
getUserData($cache, 123);// 换成文件缓存?没问题,代码完全不用改!
$cache = new FileCache();
getUserData($cache, 123);
💡 这就是“面向接口编程”:
我们依赖的是“能力”,而不是“具体是谁”。
就像 USB 接口,只要符合标准,U盘、鼠标、键盘都能插。
✅ 好处 2:让函数更通用,不依赖具体实现
继续上面的例子:
RedisCache
和FileCache
是两个完全不同的类- 但它们都实现了
Cacheable
接口 - 所以它们都可以当作
Cacheable
类型来使用
// $cache 的类型是 Cacheable(接口类型)
Cacheable $cache = new RedisCache();
✅ 是的!接口也是一种类型,就像
int
、string
、User
类一样。
PHP 允许你用接口来做类型声明、类型检查。
四、接口之间的继承 —— extends
接口也可以“继承”其他接口,就像孩子继承父母的能力:
// 在 Cacheable 基础上,增加“可清除”能力
interface AdvancedCacheable extends Cacheable
{public function clear(): void;
}
现在,任何实现 AdvancedCacheable
的类,必须实现:
set()
get()
has()
clear()
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"; }
}
五、接口中的常量
接口里也可以定义常量,和类常量用法一样:
interface PaymentGateway
{const NAME = "Payment API";public const SUPPORTED_CURRENCIES = ['CNY', 'USD', 'EUR'];
}
使用方式:
echo PaymentGateway::NAME; // 输出: Payment APIclass Alipay implements PaymentGateway
{public function pay() {echo "Using currency: " . self::SUPPORTED_CURRENCIES[0];}
}
⚠️ PHP 8.1 之前,子类不能覆盖接口常量;8.1+ 可以。
六、PHP 8.4 新特性:接口可以有属性!
从 PHP 8.4 开始,接口可以声明属性,但必须说明是“可读”、“可写”还是“可读可写”:
interface UserInterface
{public readonly string $username; // 只读属性public string $email; // 可读可写public writeonly string $password; // 只写(少见)
}
实现类可以用多种方式满足:
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;}// 魔术方法满足 writeonlypublic 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) |
换设备不用改电脑 | 实现类可替换,调用代码不变 |