类型运算符
概述
PHP 的类型运算符 instanceof 用于检查一个变量是否是某个类的实例,或者是否实现了某个接口。在面向对象编程中,instanceof 是类型检查和接口契约验证的核心工具。
PHP 8.0+ 扩展
PHP 8.0 引入了联合类型(Union Types),PHP 8.1 引入了枚举(Enums),使得类型系统更加完善。instanceof 配合这些新特性可以实现更严格的类型安全。
基础概念
instanceof 语法
php
// 基本语法
$object instanceof ClassName
$object instanceof InterfaceName
$object instanceof $variableClass
// 三种检查维度:
// 1. 类检查:是否是某个类的实例
// 2. 接口检查:是否实现了某个接口
// 3. 父类检查:是否是某个父类的子类实例返回值
instanceof 返回布尔值 true 或 false。如果被检查的变量不是对象,始终返回 false(PHP 不会抛出错误)。
语法与代码示例
基本类检查
php
<?php
declare(strict_types=1);
class Animal
{
public function __construct(
public string $name
) {}
}
class Dog extends Animal
{
public function bark(): string
{
return "Woof!";
}
}
class Cat extends Animal
{
public function meow(): string
{
return "Meow!";
}
}
$dog = new Dog('Buddy');
$cat = new Cat('Whiskers');
// 类检查
var_dump($dog instanceof Dog); // bool(true)
var_dump($dog instanceof Animal); // bool(true) —— 继承关系
var_dump($dog instanceof Cat); // bool(false)
var_dump($cat instanceof Cat); // bool(true)
var_dump($cat instanceof Animal); // bool(true)
// 非对象检查
$name = "Hello";
var_dump($name instanceof Animal); // bool(false) —— 不会报错
$nullObj = null;
var_dump($nullObj instanceof Animal); // bool(false)接口检查
php
<?php
declare(strict_types=1);
interface Serializable
{
public function serialize(): string;
public function deserialize(string $data): void;
}
interface Loggable
{
public function toLogString(): string;
}
class User implements Serializable, Loggable
{
public function __construct(
public string $name,
public string $email
) {}
public function serialize(): string
{
return json_encode(['name' => $this->name, 'email' => $this->email]);
}
public function deserialize(string $data): void
{
$decoded = json_decode($data, true);
$this->name = $decoded['name'];
$this->email = $decoded['email'];
}
public function toLogString(): string
{
return "User({$this->name}, {$this->email})";
}
}
class Product implements Loggable
{
public function __construct(public string $title) {}
public function toLogString(): string
{
return "Product({$this->title})";
}
}
$user = new User('Alice', 'alice@example.com');
$product = new Product('Widget');
// 接口检查
var_dump($user instanceof Serializable); // bool(true)
var_dump($user instanceof Loggable); // bool(true)
var_dump($product instanceof Serializable); // bool(false)
var_dump($product instanceof Loggable); // bool(true)使用变量作为类名
php
<?php
declare(strict_types=1);
class Controller
{
}
class AdminController extends Controller
{
}
class ApiController extends Controller
{
}
// 变量类名
$className = 'AdminController';
$instance = new $className();
var_dump($instance instanceof $className); // bool(true)
var_dump($instance instanceof Controller); // bool(true)
// 动态类型检查
function checkType(object $obj, string $typeName): bool
{
return $obj instanceof $typeName;
}
var_dump(checkType($instance, 'AdminController')); // bool(true)
var_dump(checkType($instance, 'ApiController')); // bool(false)详细说明
instanceof 与 is_subclass_of 对比
php
<?php
declare(strict_types=1);
interface Renderable {}
class View implements Renderable {}
class AdminView extends View {}
$adminView = new AdminView();
// instanceof 检查实例
var_dump($adminView instanceof View); // bool(true)
var_dump($adminView instanceof Renderable); // bool(true)
// is_subclass_of 检查类名(不要求实例化)
var_dump(is_subclass_of(AdminView::class, View::class)); // bool(true)
var_dump(is_subclass_of(AdminView::class, Renderable::class)); // bool(true)
// class_exists 检查类是否存在
var_dump(class_exists(AdminView::class)); // bool(true)
var_dump(class_exists('NonExistent')); // bool(false)
// instanceof 检查实例,is_subclass_of 检查类
// 在有实例的情况下,两者都可以
// 在只有类名的情况下,用 is_subclass_ofPHP 8.0+ 类型系统的扩展
php
<?php
declare(strict_types=1);
// PHP 8.0+ 联合类型
class Processor
{
// 参数类型声明中的联合类型
public function process(int|string $input): int|string
{
return is_int($input) ? $input * 2 : strlen($input);
}
}
// PHP 8.1+ 枚举
interface HasPermission
{
public function getPermission(): Permission;
}
enum Permission: int
{
case Read = 1;
case Write = 2;
case Admin = 4;
}
class UserRole implements HasPermission
{
public function __construct(public Permission $permission) {}
public function getPermission(): Permission
{
return $this->permission;
}
}
$role = new UserRole(Permission::Admin);
// instanceof 也可以用于检查枚举
var_dump($role instanceof HasPermission); // bool(true)
// PHP 8.0+ match 表达式配合类型检查
function handleInput(int|string|float $value): string
{
return match (true) {
is_int($value) => "Integer: {$value}",
is_float($value) => "Float: {$value}",
is_string($value) => "String: {$value}",
default => "Unknown type",
};
}
echo handleInput(42) . "\n"; // Integer: 42
echo handleInput('hello') . "\n"; // String: hello类型安全的集合处理
php
<?php
declare(strict_types=1);
// 使用 instanceof 进行类型安全的集合过滤
interface Entity
{
public function getId(): int;
}
class User implements Entity
{
public function __construct(public int $id, public string $name) {}
public function getId(): int { return $this->id; }
}
class Product implements Entity
{
public function __construct(public int $id, public float $price) {}
public function getId(): int { return $this->id; }
}
function filterByType(array $items, string $className): array
{
return array_values(array_filter(
$items,
fn($item) => $item instanceof $className
));
}
$entities = [
new User(1, 'Alice'),
new Product(2, 29.99),
new User(3, 'Bob'),
new Product(4, 49.99),
];
$users = filterByType($entities, User::class);
$products = filterByType($entities, Product::class);
echo "Users: " . count($users) . "\n"; // 2
echo "Products: " . count($products) . "\n"; // 2实战示例
多态处理器
php
<?php
declare(strict_types=1);
interface Notifiable
{
public function send(string $message): void;
}
class EmailNotification implements Notifiable
{
public function __construct(public string $address) {}
public function send(string $message): void
{
echo "Sending email to {$this->address}: {$message}\n";
}
}
class SmsNotification implements Notifiable
{
public function __construct(public string $phoneNumber) {}
public function send(string $message): void
{
echo "Sending SMS to {$this->phoneNumber}: {$message}\n";
}
}
class NotificationService
{
/** @var Notifiable[] */
private array $channels = [];
public function addChannel(Notifiable $channel): void
{
$this->channels[] = $channel;
}
public function notifyAll(string $message): void
{
foreach ($this->channels as $channel) {
if ($channel instanceof Notifiable) {
$channel->send($message);
}
}
}
}
$service = new NotificationService();
$service->addChannel(new EmailNotification('alice@example.com'));
$service->addChannel(new SmsNotification('+1234567890'));
$service->notifyAll('Hello!');中间件类型检查
php
<?php
declare(strict_types=1);
interface Middleware
{
public function handle(Request $request, Closure $next): Response;
}
class Request
{
public function __construct(public string $method, public string $path) {}
}
class Response
{
public function __construct(public int $status, public string $body) {}
}
class AuthMiddleware implements Middleware
{
public function handle(Request $request, Closure $next): Response
{
if ($request->path === '/admin' && !isset($request->auth)) {
return new Response(401, 'Unauthorized');
}
return $next($request);
}
}
function validateMiddleware(object $middleware): void
{
if (!($middleware instanceof Middleware)) {
throw new InvalidArgumentException(
'Middleware must implement Middleware interface'
);
}
}注意事项
- 非对象变量返回
false:$x instanceof SomeClass不会报错,直接返回false instanceof不检查属性:只检查继承和接口关系- 避免
instanceof过多使用:过多的类型检查可能表明设计有问题,考虑使用多态 class_exists先检查:当使用变量类名时,建议先检查类是否存在- PHP 8.0+ 优先使用类型声明:参数和返回值类型声明比
instanceof更安全
最佳实践
- 优先使用类型声明:PHP 8.1+ 的联合类型和枚举比运行时
instanceof检查更安全 instanceof用于多态分发:在必须区分类型的场景中使用- 检查接口而非具体类:
$obj instanceof Renderable优于$obj instanceof PdfRenderer - 使用
::class常量:$obj instanceof User::class优于字符串 - try/catch 替代 if + instanceof:对于类型相关的错误,考虑异常处理